views:

466

answers:

1

I'm creating a JavaScript class (using Prototype) that will set the page state to idle if there's no mouse movement within a specified number of seconds. When the mouse moves, the class will "wake up" the page by sending a message to a list of listeners.

The thing I don't understand is that this.handlers is valid in one function (setIdle), but not another (setActive). The annotated code below illustrates my problem:

var IM2 = Class.create({

handlers: null,

initialize: function(callback, frequency) {
 this.handlers = [];
 Event.observe(document, "mousemove", this.sendActiveSignal);
 Event.observe(document, "keypress", this.sendActiveSignal);
 setInterval(this.sendIdleSignal.bind(this), 5000);
},

addListener: function(h) {
 console.log(this.handlers.size());  // it's 0 here, as expected
 this.handlers.push(h);
 console.log(this.handlers.size());  // it's 1 here, as expected
},

sendIdleSignal: function(args) {
 console.log("IDLE");
 this.handlers.each(function(i){
  i.setIdle();
 })
},

sendActiveSignal: function() {
                                    // this.handlers is undefined here. Why?
 this.handlers.each(function(r) {
  r.setActive();
 })
}

});
+1  A: 

Assuming you mean it's valid in SendIdleSignal and it's not valid in SendActiveSignal...

Your event listeners should also use bind, like this:

Event.observe(document, "mousemove", this.sendActiveSignal.bind(this));
Event.observe(document, "keypress", this.sendActiveSignal.bind(this));

Also, if you're using prototype 1.6 or higher, you can use

document.observe("mousemove", this.sendActiveSignal.bind(this));
document.observe("keypress", this.sendActiveSignal.bind(this));

Additionally, if you want a generic (framework agnostic) way to do this, you could define your functions like this:

sendActiveSignal: function() {
    var that = this;
    return function() {
        that.handlers.each(function(r) {
            r.setActive();
        });
    }
}

then your event handlers/setInterval could be left as

Event.observe(document, "keypress", this.sendActiveSignal);
Jonathan Fingland
Exactly what I was missing; thanks!
yalestar
glad to help, also see the edit for a more generic approach
Jonathan Fingland