• 26 . 08 . 10
  • Update: This code is now on GitHub and has had some substantial improvements made. You should look at the latest code here and submit a pull request if you make any improvements! In a recent post, I outlined a method to abstract away the complexity of creating an encapsulated jQuery plugin. However, as was pointed […]

  • Tags

    , , , ,

  • StumbleUpon

Object Oriented jQuery Plugins Mk 2

Update: This code is now on GitHub and has had some substantial improvements made. You should look at the latest code here and submit a pull request if you make any improvements!


In a recent post, I outlined a method to abstract away the complexity of creating an encapsulated jQuery plugin. However, as was pointed out in the comments, there was a missing piece that didn’t allow for arguments to be passed through. More seriously, there was an issue with the binding of the facade function, which meant that only the last defined public function in the class could be called.

As an aside, if you need to bind a variable at the time that it is defined, it isn’t enough to define an anonymous function with a reference to the closure, as that can change by the time the function is called. The bug in my code was in the piece that bound the facade function to the set member functions.

[javascript]
for ( var i in template) {
if (typeof (template[i]) == ‘function’) {
result[i] = function() {
this.each(function() {
this[i]();
});
};
}
}
[/javascript]

By the time the inner function is called, “i” has already been re-bound to the final function name in the template. The solution is to bind the inner function name to the outer function name at the time of definition, which we can do by wrapping it in (yet another!) function.

[javascript]
// Iterates through the set calling the specified function.
function makeIteratorFunction(f, set) {
return function() {
for ( var i = 0; i < set.length; i++) {
set[i][f].apply(set[i][f], arguments);
}
};
}
[/javascript]

and then calling that function:

[javascript]
if (template) {
for ( var i in template) {
if (typeof (template[i]) == ‘function’) {
result[i] = makeIteratorFunction(i, result);
}
}
}
[/javascript]

At this point, although “i” will continue to change as the loop continues, the function call is bound through the closure on “f” in the auxiliary function, which remains fixed. Google Chrome’s developer tools certainly make following all that a lot simpler! I’ve updated the plugin with these improvements, which also enables us to pass arguments through, finally allowing:

[javascript]
$(‘#foo’).myplugin().publicMethodWithArguments(‘hello’);
[/javascript]

You can get the updated plugin here. Feedback welcomed!

4 responses to “Object Oriented jQuery Plugins Mk 2”

  1. majelbstoat says:

    Stoat – Where?: Object Oriented jQuery Plugins Mk 2 http://bit.ly/bfmmFP

    This comment was originally posted on Twitter

  2. Jianbinbi says:

    good codes, i add _rs to get the result, is that right? since i cannot get the value when using some methods
    var _rs;
    // Iterates through the set calling the specified function.
    function makeIteratorFunction(f, set) {
    return function() {
    for ( var i = 0; i < set.length; i++) { _rs = set[i][f].apply(set[i][f], arguments); return _rs; } }; }

  3. Trond Rognan says:

    First of all, great plugin!

    Being quite new to “advanced” jQuery I just wanted to point out that Jianbinbi’s addition (return statement) should be added to the plugin generator code, in order to get return values from public get-methods. Didn’t see the Mk2 post at first and spent some time debugging 🙂

    i.e. (simplified):

    function makeIteratorFunction(f, set) {
    return function() {
    for ( var i = 0; i < set.length; i++) {
    return set[i][f].apply(set[i][f], arguments);
    }
    };
    }

    • Jamie Talbot says:

      Hi Trond,

      Yes, you’re right, thanks very much. I had actually done this myself in my local code – it’s just hard to keep a bog up to date with the rapid changes 🙂 Glad you found it useful!

      Cheers,

      Jamie.

Leave a Reply

Your email address will not be published. Required fields are marked *