• 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.

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

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.

	// 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);
			}
		};
	}

and then calling that function:

	if (template) {
		for ( var i in template) {
			if (typeof (template[i]) == 'function') {
				result[i] = makeIteratorFunction(i, result);
			}
		}
	}

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:

$('#foo').myplugin().publicMethodWithArguments('hello');

You can get the updated plugin here. Feedback welcomed!