views:

122

answers:

1

I'm writing some MVC JavaScript code using Prototype. The problem is that when I reference this in the snippet below it does of course reference the Window object, whereas I need it to refer to my Controller instance so it can invoke my updateValue function, passing the HTML element ID.

I think I have to use bind or bindAsEventListener but I don't really understand how.

var Foo = {
  Controller: Class.create({
    observeEvents: function() {
      $$("#myform input").each(function(input) {
        input.observe("blur", this.updateValue(input.id); // <- wrong this!
      });
    },

    updateValue: function(elementID) {
      ...
    }
  })
}

Any help would be much appreciated.

+2  A: 

This should work.

    observeEvents: function() {
      var Controller = this;
      $$("#myform input").each(function(input) {
        input.observe("blur", Controller.updateValue.bind(Controller, input.id));
      });
     ...

If you don't ever want to learn how to use bind (and frankly I don't blame you) then you can forget about it and just use another teensy closure.

    observeEvents: function() {
      var Controller = this;
      $$("#myform input").each(function(input) {
        input.observe("blur", function(event) {
                                Controller.updateValue(input.id);
                              });
      });
     ...
Jason Orendorff
bind is so useful everyone should know how to use it, if only to better understand the scope of their functions and how they relate.
Rob
IMHO - one cannot program JS without understanding bind.
Upper Stage
I tried using `bind` as per your first example and it didn't work. The second example does work. Thank you.
John Topley
The `bind` example doesn't works because inside the `each` callback, `this` refers to the Global object.
CMS
Hmm. Maybe jQuery has just spoiled me. I don't think I've ever actually used `bind`. Surprisingly often you can just write `$("#myform input").live("blur", updateValue)` and move on to the next problem.
Jason Orendorff
Sigh, I just checked, and of course jQuery doesn't support `live("blur"...)`.
Jason Orendorff
@John Topley: CMS was right. I edited the post to fix the bug.
Jason Orendorff
@Jason, you are still using `this` inside the `each` loop, you need `Controller.updateValue.bind(Controller, input.id)`
CMS
Right, fixed again.
Jason Orendorff