Search code examples
eventsmootoolsaddeventlistener

Event removal in Mootools, and syntax of event addition


So I have been adding my events thusly:

element.addEvent('click', function() {
    alert('foobar');
});

However, when attempting to remove said event, this syntactically identical code (with "add" switched to "remove") does not work.

element.removeEvent('click', function() {
    alert('foobar');
});

I assume this is because the two functions defined are not referenced the same, so the event is not technically removed. Alright, so I redefine the event addition and removal:

element.addEvent('click', alert('foobar'));
element.removeEvent('click', alert('foobar'));

Which works great, except now when the page loads, the click event is fired even before it's clicked!

The function is removed, though, which is great......


Solution

  • update: when you do .addEvent('type', function(){ }) and .removeEvent('type', function(){ }), even though the functions may have the same 'signatures', they are two separte anonymous functions, assigned on the fly. function 1 is !== to function 2 - hence there is no match when MooTools tries to remove it.

    to be able to remove an exact handler, o:

    function handler(){ ... } el.addEvent('click', handler); // .. later el.removeEvent('click', handler);

    Internally, events are actually a map of keys to functions in element storage. have a look at this fiddle i did a while back for another SO question - http://www.jsfiddle.net/mVJDr/

    it will check to see how many events are stacked up for a particular event type on any given element (or all events).

    similarly, removeEvent looks for a match in the events storage - have a look on http://jsfiddle.net/dimitar/wLuY3/1/. hence, using named functions like Nikolaus suggested allows you to remove them easily as it provides a match.

    also, you can remove events via element.removeEvents("click") for all click events.

    your page now alerts because you pass on alert as the function as well as execute it with the params 'foobar'. METHOD followed by () in javascript means RUN THE METHOD PRECEDING IT IMMEDIATELY, NOT LATER. when you bind functions to events, you pass the reference (the method name) only.

    to avoid using an anonymous function and to pass argument,s you can do something like:

    document.id('foobar').addEvent('click', alert.bind(this, 'foo'));
    

    as bind raps it for you, but removing this will be even more complicated.

    as for event delegation, it's:

    parentEl.addEvents({
        "click:relay(a.linkout)": function(e, el) {
    
        },
        "mouseover:relay(li.menu)": function(e, el) {
    
        }
    });
    

    more on that here http://mootools.net/docs/more/Element/Element.Delegation#Element:removeEvent

    keep in mind it's not great / very stable. works fine for click stuff, mouseenter is not to be used delegated, just mouseover - which means IE can fire mouseout when it should not. the way i understand it, it's coming improved in mootools 2.0

    edit updating to show an example of bound and unbound method within a class pattern in mootools

    http://www.jsfiddle.net/wmhgw/

    var foo = new Class({
        message: "hi",
        toElement: function() {
            return this.element = new Element("a", {
                href: "http://www.google.com",
                text: "google",
                events: {
                    "click": this.bar.bind(this), // bind it
                    "mouseenter": this.bar // unbound -> this.element becomes this
                }
            });
    
        },
        bar: function(event) {
            event.stop();
            // hi when bound to class instance (this.message will exist)
            // 'undefined' otherwise.
            console.log(this.message || "undefined");
        }
    });
    
    document.id(new foo()).inject(document.body);
    

    the mouseenter here will be unbound where this will refer to the default scope (i.e the element that triggered the event - the a href). when bound, you can get the element via event.target instead - the event object is always passed on to the function as a parameter.

    btw, this is a slightly less familiar use of class and element relation but it serves my purposes here to illustrate binding in the context of classes.