Binding Events The Right Way

March 19, 2012

On of the interesting new things that Javascript 1.8.5 introduced is something that we were doing for long time – binding functions to events while controlling the context of called method. If up until now we used tricks like closures to create this binding, now this is built into the language.

Binding Events

This is a task that any JS developer has done million times – registering to an event by providing some method. On jQuery it usually looks something like this:


$(".myclass").click( function(e){
    //do something
});

In this case we created an anonymous function that handle the event. The context of this function is the target element. For example, if this would be a handler for a click on a button then the “this” keyword will be the button element.

when writing in object oriented approach usually we have some class that handle specific logic in the page. If this class also needs to register to some events the previous implementation will need to be adopted to something like this:


function AppLogic(){
    this.init();
};
AppLogic.prototype = {
    init: function(){
        this._bind();
    },
    _bind: function(){
        var self = this;
        $("#button1").click(function(e){
            self._onButtonClick(e);
        }
    },
    _onButtonClick: function(e){
        //do something
    }
};

var app = new AppLogic();

In this example, we created a handler method called _onButtonClick and we called it from the anonymous function but making sure the context is the AppLogic instance using the self variable.

The bind Method

This implementation or variation of it has been done so many times, that i think it was decided to make our life easier and introduce the bind method.

The bind method is a method that can be invoked on functions in javascript as follow:

function.bind( context, [arg1[, arg2 ... ]] );

Lets the the previous example if the use of this method:


function AppLogic(){
    this.init();
};
AppLogic.prototype = {
    init: function(){
        this._bind();
    },
    _bind: function(){
        $("#button1").click( this._onButtonClick.bind(this) );
    },
    _onButtonClick: function(e){
        //do something
    }
};

var app = new AppLogic();

Now the code looks much cleaner and readable (at least to me).

Another thing that the bind method is supporting is additional arguments that are being prepend to the arguments of the called method. Lets check the following example:


<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
  <head>
    <title>Bind Example</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
      <span>Ask me a question: </span><input type="text" /><button>Get an answer 1</button><button>Get answer 2</button>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
      <script>
          function App(){};
          App.prototype = {
              init: function(){
                  this._bind();
              },
              _bind: function(){
                  $(".answer1").click(this._onAnswer.bind(this,1));
                  $(".answer2").click(this._onAnswer.bind(this,2));
              },

              _onAnswer: function(id,e){
                  if( id === 1 ){
                      alert(" i don't know that!");
                  }
                  else{
                      window.location.href = "https://www.google.de/search?q="+$("input").val().replace(/ /g,"+");
                  }
              }
          };

          var app = new App();
          app.init();
      </script>
  </body>
</html>

You can check this code here.

In this example we are registering using bind to different elements but we add an argument of the button id to the bind method. This id is the first argument that we get in the callback. I agree that this is not the best use case for this, but i gives you an idea how you can utilize it.

Browser Support

This feature is currently supported by:

  • Firefox 4
  • Chrome 7
  • IE 9

But what if we want use it also in older browsers?

Bind Compatibility

In order to use the bind method in any browser you can add the following code to your project:


if (!Function.prototype.bind) {
  Function.prototype.bind = function(context) {
    var args = Array.prototype.slice.call(arguments, 1),  //we are saving all the arguments after the context.
        fToBind = this,
        fBound = function () {
          return fToBind.apply( context || window,
                                args.concat(Array.prototype.slice.call(arguments)));
        };
    return fBound;
  };
}

Frameworks Support

This binding mechanism is supported by several libraries out there. The one that i like the most is YUI. in YUI this feature is already built into the framework event mechanism. Everywhere you can register to events YUI gives you the option to provide a context to the callback. Lets see how it looks in jQuery and how it is in YUI


//binding in jQuery
$(".myclass").click(function(e){ self._onEvent(e) } );

//binding in YUI
Y.one(".myclass").on("click" , this._onEvent , this );

I use YUI a lot and i have to say that this is an amazing framework and i have a feeling that it is under appreciated in the industry.

Bookmark and Share
Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • E-mail this story to a friend!
  • FriendFeed
  • LinkedIn
  • StumbleUpon
  • Twitter

tags: , , ,
posted in Blog by Amir Harel

3 Comments to "Binding Events The Right Way"

  1. Danny wrote:

    cool site, and very nice commenting system :)

  2. Eran wrote:

    awesome!

  3. aaaa wrote:

    yyyy xxx

 
Powered by Wordpress and MySQL. Theme by openark.org