Friday, June 5, 2009

JQuery Callback Context

Most of my web applications using AJAX have built around a "client control" model, similar to the user control model in ASP.NET, in which a client side JavaScript class encapsulates all the functionality related to an editor, list or other interface component. This means that my callbacks (both AJAX and event handlers) need to execute in the context of the containing JavaScript object, not the object executing the function to return the data.

After played around with a couple of methods I settles on using the jQuery.context plug-in. It's a very nifty bit of code and relies on using a closure to capture the initial state. While this works great, I often find myself needing to pass some state information back along with the callback, typically when I am dealing with arrays of items (eg a column of buttons in a table that trigger click events).

I solved my problem by modifying the context plug-in to take an additional parameter that is stored inside the closure and appended to the parameter list when the callback is executed. My revised code looks like this:

   1:  // $.context

   2:  jQuery.extend(

   3:  {

   4:    context: function (context)

   5:    {

   6:      var co = 

   7:      {

   8:        callback: function (method, state)

   9:        {

  10:          if (typeof method == 'string') method = context[method];

  11:          var cb = function () 

  12:          { 

  13:              var args = new Array();

  14:              for(var i = 0; i < arguments.length; i++) {

  15:                  args[i] = arguments[i];

  16:              };

  17:              args[arguments.length] = state;

  18:              method.apply(context, args); 

  19:          }

  20:          return cb;

  21:        }

  22:      };

  23:      return co;

  24:    }

  25:  }); 

I'm using the same apply function as in the original code, but I'm copying over the argument list and appending the state object that was passed in along with the context. Copying over the arguments array is important, just appending the state to the arguments array causes funky results.

I initially planned on allowing an array of arguments, but since its so easy to create a JSON style object on the fly as your state, it seemed more confusing than useful.

No comments: