views:

106

answers:

1

I've been learning Mootools, but I'm having problems firing custom events. I'm sure it must be something simple, but I can't see it for the life of me.

I wrote a simple class to nudge some list items using Fx.Tween. It works perfectly, except that the custom events aren't being triggered, no matter what I try.

<script type="text/javascript">
    var Pusher = new Class({
        Implements: [Events,Options],
        options: {
            elements: []
        },

        initialize: function(options){
            this.setOptions(options);
            this.attachListeners(this.options.elements);
        },

        attachListeners: function(elements){
            $$(elements).each(function(el){
                $(el).addEvent('mouseover', this.pushIn.bind(el))
                     .addEvent('mouseout', this.pushOut.bind(el));
            }, this);
        },

        pushIn: function(){
            this.fireEvent('in');
            this.set('tween', {duration: 'short'});
            this.tween('paddingLeft', '50px');
        },

        pushOut: function(){
            this.fireEvent('out');
            this.set('tween', {duration: 'short'});
            this.tween('paddingLeft', '0px');            
        }
    });

    window.addEvent('domready', function(){
        var p = new Pusher({
            elements: $$('li')
        });
        p.addEvent('in', function(){ alert('in'); });
        p.addEvent('out', function(){ alert('out'); });
    });
</script>

And in the HTML:

<ul id="mylist">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

I've also tried the following:

window.addEvent('domready', function(){
    var p = new Pusher({
        elements: $$('li'),
        onIn: function(){ alert('in'); },
        onOut: function(){ alert('out'); }
    });
});

What am I doing wrong?

+2  A: 

The problem is with this line:

this.pushIn.bind(el)

When pushIn is called, this refers to the <li> element that was hovered, and not an object of Pusher. So calling this.fireEvent('in') will fire the event on the <li> element, instead of your class' object. The DOM event object contains the target which refers to the element that triggered the event. Using this target property, we can get the element that triggered the event, and then animate it.

Side note: when the mouse(over|out) event is triggered, this already refers to the DOM object, so you don't have to bind it explicitly with .bind(el).

Made the following things to your code:

  1. bound event handlers to object of Pusher
  2. use event.target to animate the <li> DOM element

example on jsf

attachListeners: function(elements){
    $$(elements).each(function(el){
        $(el).addEvent('mouseover', this.pushIn.bind(this))
             .addEvent('mouseout', this.pushOut.bind(this))
    }, this);
},

pushIn: function(event) {
    this.fireEvent('in');
    var item = event.target;
    item.set('tween', {duration: 'short'});
    item.tween('paddingLeft', '50px');
},

pushOut: function(event){
    var item = event.target;
    this.fireEvent('out');
    item.set('tween', {duration: 'short'});
    item.tween('paddingLeft', '0px');            
}
Anurag
Fantastic, what a great answer. Thank you!
John McCollum
glad it worked for you. Cheers!
Anurag