views:

101

answers:

2

I'm having problems implementing classes in mootools since I can't use 'this' when I send methods in say element.addEvent.

Say I have this mootools class:

var Dude = new Class({

    highlightColor: '#f00',

    doStuff: function() {
        var parent = $('theParentId');

        new Element('div', {'html': 'Click me'})
            .inject(parent)
            .addEvent('click', function(){

                new Element('div', {'html': 'you clicked'})
                    .highlight(this.highlightColor);

            });
    },

});

This code will throw exception inside the addEvent method call, because this is suddenly is in another context. Is there some other way to get the object's highlightColor (or any other member that a mootools Class may have)?

+2  A: 

The "MooTools way" would be to use the bindWithEvent function:

var Dude = new Class({

    highlightColor: '#f00',

    doStuff: function() {
        var parent = $('theParentId');

        new Element('div', {'html': 'Click me'})
            .inject(parent)
            .addEvent('click', function(event){

                new Element('div', {'html': 'you clicked'})
                    .highlight(this.highlightColor); // <- `this` refers to the 
            }.bindWithEvent(this));                  //    outer `this` value
    },
    //...
});

That method allows you to preserve the this value on a function, and pass additional arguments if necessary.

The first argument of the bound function, will refer to the Event object of the triggered event.

CMS
`bind` should be used instead of `bindWithEvent` - that would be "the mootools way" as core developers encourage not to use `bindWithEvent`.
Oskar Krawczyk
@Oskar, well, `bindWithEvent` has been exactly made for this, [documentation](http://j.mp/cAoTn4) recommends its usage specifically when using addEvent: "This allows the function to be used in conjunction with Element:addEvent and arguments.", although I concede one benefit about using `bind`, the native implementations of the ECMAScript 5 standard `Function.prototype.bind` will be available soon on all browsers, and native implementations have always great performance. Anyway if Core developers don't encourage the usage of this method, a note in the docs would be helpful.
CMS
I agree with Oskar in that it's far more common to use `bind`--keeping scope to the class instance is _usually_ done like so. as far as my understanding goes, you don't need `bindWithEvent` here - all he accesses in the callback is the `this.highlightColor` property so keeping the scope to the class instance is enough. The event doesn't _need_ to be passed here at all as the callback already has direct access to it by definition. eg, `...click", this.methodName.bind(this)` will also pass the event object to the method as the first argument, so what's a good test case for `bindWithEvent`?
Dimitar Christoff
i built a little case to demonstrate when `bindWithEvent` needs to be used - when there are more arguments needing to be passed to the callback method than the event: http://jsfiddle.net/etCqH/
Dimitar Christoff
ahhhhh now i get it! thxs @Dimitar, sometimes an example is better than the documentation
pleasedontbelong
+3  A: 

you need to bind the this reference to the function each time you use a function (on addEvents or each)

var Dude = new Class({

    highlightColor: '#f00',

    doStuff: function() {
        var parent = $('theParentId');

        new Element('div', {'html': 'Click me'})
            .inject(parent)
            .addEvent('click', function(){

                new Element('div', {'html': 'you clicked'})
                    .highlight(this.highlightColor);

            }.bind(this));
    }
});

be carefoul with the last coma on the function doStuff... firefox is like a mother it will foregive you but iexplorer is a bmf it will throw an error and wont tell you why

pleasedontbelong