Skip to content Skip to sidebar Skip to footer

Mootools | Open/close Popup Menu And Outer Click Event

I'm using mootools and working on popup menu: document.getElement('.cart a').toggle( function() { this.getParent('div').removeClass('open'); this.getNext('.cart_contents').

Solution 1:

This is a problem (or a deficiency) to do with the outerClick implementation by Darren. It's not a bug - it's built to work as fast as possible. you just need to understand what it does when it binds the actual event to document.

Element.Events.outerClick = {
    base : 'click',    
    condition : function(event){
        event.stopPropagation();
        return false;
    },
    onAdd : function(fn){
        // the event actually gets added to document!
        // hence scope in fn will be document as delegator.
        this.getDocument().addEvent('click', fn);
    },
    onRemove : function(fn){
        this.getDocument().removeEvent('click', fn);
    }
};

So the functions will run with context this === document.

One way to fix it is to bind the callback specifically to the element. Problem is, removing it won't work as .bind will return a unique new function that won't match the same function again.

(function(){
    var Element = this.Element,
        Elements = this.Elements;

    [Element, Elements].invoke('implement', {
        toggle: function(){
            var args = Array.prototype.slice.call(arguments), 
                count = args.length-1,
                // start at 0
                index = 0;

            return this.addEvent('click', function(){
                var fn = args[index];
                typeof fn === 'function' && fn.apply(this, arguments);
                // loop args.
                index = count > index ? index+1 : 0;
            });
        }
    });

    Element.Events.outerClick = {
        base : 'click',    
        condition : function(event){
            event.stopPropagation();
            return false;
        },
        onAdd : function(fn){
            this.getDocument().addEvent('click', fn.bind(this));
        },
        onRemove : function(fn){
            // WARNING: fn.bind(this) !== fn.bind(this) so the following
            // will not work. you need to keep track of bound fns or 
            // do it upstream before you add the event.
            this.getDocument().removeEvent('click', fn.bind(this));
        }
    };
}());

document.id('myp').toggle(
    function(e){
        console.log(e); // event.
        this.set('html', 'new text');
    },
    function(){
        console.log(this); // element
        this.set('html', 'old text');
    },
    function(){
        this.set("html", "function 3!");
    }
).addEvent('outerClick', function(e){
     console.log(this, e); 
});

http://jsfiddle.net/dimitar/UZRx5/ - this will work for now - depends if you have a destructor that removes it.

Another approach is when you add the event to do so:

var el = document.getElement('.cart a');
el.addEvent('outerClick', function(){ el.getParent(); // etc });
// or bind it 
el.addEvent('outerClick', function(){ this.getParent(); }.bind(el));

it can then be removes if you save a ref

var el = document.getElement('.cart a'),
    bound = function(){
        this.getParent('div');
    }.bind(el);

el.addEvent('outerClick', bound);

// later
el.removeEvent('outerClick', bound);

that's about it. an alternative outerClick is here: https://github.com/yearofmoo/MooTools-Event.outerClick/blob/master/Source/Event.outerClick.js - not tried it but looks like it tries to do the right thing by changing scope to element and keeping a reference of the memoized functions - though multiple events will likely cause an issue, needs event ids to identify the precise function to remove. Also, it looks quite heavy - considering the event is on document, you want to NOT do too much logic on each click that bubbles to that.


Post a Comment for "Mootools | Open/close Popup Menu And Outer Click Event"