Programster
Programster

Reputation: 12764

javascript problems with passing methods as callbacks

I am trying to access an object's member variables from inside a method that is passed as a callback which is fired during a filereader event.

I have whipped together the code below just to try and convey my point. It appears that 'this' becomes the filereader instead of the object at the point of call. Is there a way to have the finishLoading be able to access the objects variables?

I would like to make sure that the callbacks are tailored to the object, otherwise I would have just defined them as static functions outside the class.

function myClass(newName)
{
    this.name = newName;
    this.m_fileReader = new FileReader();

    this.finishedLoading = 
        function(param1)
        {
            alert(this.name);
        };

    this.m_fileReader.addEventListener('loadend',  
                                       this.callback_finishedLoading, 
                                       false);
}

var instance = new myClass('timmy');
var instance2 = new myClass('joe');

Upvotes: 1

Views: 129

Answers (3)

Alnitak
Alnitak

Reputation: 339816

You need the .bind function:

this.m_fileReader.addEventListener('loadend',
    this.callback_finishedLoading.bind(this),
    false);

The .bind function will take the passed parameter, and call the original function with that parameter as its this instead of whatever value the browser tried to supply.

Alternatively, just create your own alias to this and wrap your call in an anonymous function:

var self = this;
this.m_fileReader.addEventListener('loadend', function(ev) { 
    self.callback_finishedLoading(ev)
}, false);

The latter is mostly what .bind does behind the scenes, but does have the advantage that it'll work on pre-ES5 browsers without a shim.

Upvotes: 4

user2437417
user2437417

Reputation:

You can make your constructor implement the EventListener interface, like this:

function myClass(newName) {
    this.name = newName;
    this.m_fileReader = new FileReader();
    this.m_fileReader.addEventListener('loadend', this, false);
}

myClass.prototype.handleEvent = function(event) {
    return this[event.type] && this[event.type](event)
}

myClass.prototype.loadend = function(event) {
    alert(this.name);
};

var instance = new myClass('timmy');
var instance2 = new myClass('joe');

I renamed the finishedLoading to loadend, and put it on the .prototype of the constructor. Then I added a .handleEvent method to the .prototype.

Finally in the constructor, we don't pass a function at all. Instead just pass the this, which is your myClass instance.

I removed your param1 because it was unclear how that was to be used. If it needs to receive some value from other invocations, then you can create a separate finishedLoading method on the .prototype, and have the .loadend() method invoke it.

Upvotes: 1

aldux
aldux

Reputation: 2804

this is relative to the context. Every time you open a new block {} it changes to the current block context. Save this to another variable before calling the callback function.

Upvotes: 0

Related Questions