MooTools Events 1.3

By Ryan Florence, published 2010-11-12

Part of the issue MooTools 1.3.

Events are the communication lines between objects. What’s exciting about client-side JavaScript to me is the changing state of a page as the user interacts. Without events, there would be no way to manage the state of all your objects and create a dynamic experience.

There are two types of events in MooTools, DOM events and custom events. DOM events are events that the browser supports natively, like click, mouseover, focus, blur, load, etc. Custom events are whatever you want.

Adding events

There are two methods for adding events, addEvent and addEvents.

$('an-element').addEvent('click', function(){
	// do something when clicked
});

new Fx.Tween('an-element').addEvents({
	start: function(){
		// do something when the animation starts
	},
	complete: function(){
		// do something when the animation finishes
	}
});

Note that if a class Implements events (like Fx.tween) you can just throw the events in as options with the on prefix.

new Fx.Tween('an-element', {
	onStart: function(){
		// do something when the animation starts
	},
	onComplete: function(){
		// do something when the animation finishes
	}
});

Or if you’re creating elements dynamically, you can add an events option there too:

new Element('div',{
	id: 'event-me-please',
	events: {
		click: function(){
			// do something on click
		},
		mouseenter: function(){
			// do something else
		}
	}
});

Removing events

Occasionally you’ll want to remove events after you’ve added them. You can blow away all events of any type pretty easily.

$('an-element').removeEvents('click');

That’s usually not what you’re after, however. Typically if you need to remove an event, you want to remove one specific thing. In order to do so, you need to store a pointer to the function you add. Before, we added an “unnamed function expression” as the second argument to addEvent; this time we’ll assign the function expression to a variable, and then pass that variable in.

View this on jsFiddle.net

var element = $('an-element'),
    handler1 = function(){
      console.log('handler1');
    },
    handler2 = function(){
      console.log('handler2');
    };

element.addEvent('focus', handler1);
element.addEvent('focus', handler2);

element.focus(); // console logs 'handler1' and 'handler2'

// later
element.blur();
element.removeEvent('focus', handler1);
element.focus(); // console logs 'handler2'

Firing Events

If you’ve added an event to an element, you can fire it whenever you want:

var el = $('el');
el.addEvent('click', function(){ /* do something */ });
// later
el.fireEvent('click');

You ought to liberally fire events in your classes and send along any arguments that make sense. First you need to implement Events. Consider this useless class:

var Useless = new Class({
  Implements: [Options, Events],
  doSomething: function(){
    // do cool stuff
    var arg = 'awesome';
    this.fireEvent('finish', arg);
  }
});

var foo = new Useless;
foo.addEvent('finish', function(arg){
  console.log(arg);
});
foo.doSomething();
// console logs 'awesome'

The Fx class is a great example. All animations have start, cancel, complete, and chainComplete events allowing you to easily get your page to respond to the effects happening on the screen.

Events in a Class

If you add events to objects in your class, you should always provide a way to remove them. I like to call the two methods attach and detach. It’s also helpful to bind your handlers so your class stays cleaner and the context of this is always your class instance object. This navigation class ought to demonstrate what I’m talking about.

Check it out on jsFiddle.net

var Nav = new Class({

    Implements: [Options, Events],

    options: {
        currentClass: 'current'
    },

    initialize: function(element, options) {
        this.setOptions(options);
        this.element = document.id(element);
        this.current = null;
        this.bound = this.clickHandler.bind(this);
        this.attach();
    },

    attach: function() {
        this.element.addEvent('click', this.bound);
        return this;
    },

    detach: function() {
        this.element.removeEvent('click', this.bound);
        return this;
    },

    clickHandler: function(event) {
        this.setCurrent(event.target)
        return this;
    },

    setCurrent: function(target) {
        if (target == this.current) return;
        if (this.current) this.current.removeClass(this.options.currentClass);
        this.current = target.addClass(this.options.currentClass);
        this.fireEvent('click', target);
        return this;
    }

});

Event Delegation and Pseudo Events

Event delegation is the pattern of listening to an event on one element and relaying it to children elements, so you don’t have to listen to an event on every child element. Its handy when dealing with a lot of elements, or with a dynamic DOM (think ajax partial page updates.)

MooTools parses the event name with Slick, opening up some powerful stuff.

Event Delegation with More

$('some-el').addEvent('click:relay(li)', function(event, target){
  console.log(target);
});

This listens to clicks on some-el, but only fires the function if it was an li element that received the click.

Pseudo Events new in MooTools 1.3

Notice how the event name in the last example looks exactly like a CSS pseudo selector, a lot like :nth-child(2). MooTools More has what are called Event Pseudos that work just like Slick’s pseudo selectors. This next example is built in:

$('el').addEvent('click:once', function(){
	// this will only happen once
});

If you want to add your own pseudo events, here’s how to do it.

View this on jsFiddle.net

Event.definePseudo('n-times', function(split, fn, args){
  if (!fn.count) fn.count = 0;
  fn.apply(this, args);
  if (++fn.count == split.value) this.removeEvent(split.original, fn);
});

Using Slick to parse the event name has barely been explored. Several of the MooTools developers have come up with some ideas on how to use it more extensively. As of yet, there’s not much use outside of :relay, :once and a few things added by the Keyboard class from MooTools More.

Continue on to the next article in this issue: MooTools Element 1.3.

Go back to the last article in this issue: MooTools Class 1.3

Hi, I'm Ryan!

Location:
South Jordan, UT
Github:
rpflorence
Twitter:
ryanflorence
Freenode:
rpflo

About Me

I'm a front-end web developer from Salt Lake City, Utah and have been creating websites since the early 90's. I like making awesome user experiences and leaving behind maintainable code. I'm active in the JavaScript community writing plugins, contributing to popular JavaScript libraries, speaking at conferences & meet-ups, and writing about it on the web. I work as the JavaScript guy at Instructure.