I am writing my first jQuery plugin. Here’s the skeleton of the plugin:
(function( $ ) {
var methods = {
init : function( options ) {
var settings = $.extend( {
'id' : '#' + this[0].id,
'foo' : 3,
'bar' : 4,
}, options );
}
}
$.fn.MyPlugin = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on MyPlugin' );
}
};
})( jQuery );
I attach the plugin like this:
$( '#some-id' ).MyPlugin({
'something' : 'something
});
which works fine for one control on one page but when I start doing this:
$( '#some-id-2' ).MyPlugin({
'something' : 'something
});
$( '#some-id-3' ).MyPlugin({
'something' : 'something
});
I get the following error:
Uncaught TypeError: Cannot read property 'id' of undefined
because I get my ID from this which evaluates to [] for the any control that is not on the page I am currently on!
What’s the correct way to get the ID of the controls that the plugin is attached to?
Many thanks :).
There’s a fundamental issue here: You’re thinking about an individual element. jQuery is all about sets of elements. The
thisin your plug-in is a jQuery instance, which may have0..nmatched elements in it. Could be zero, one, 27, 342, etc. So doingthis[0].iddoesn’t really make sense in a jQuery plug-in, because you’d just get theidof the first matching element (if it even has one; there’s no requirement that it must), or an error (as you discovered) when there aren’t any elements in the set at all.So if you start thinking about your plug-in as dealing with a set of matched elements, which may be an empty set, a small set, or a large set, you’ll be on the right path.
Here’s a concrete example: Let’s write a plug-in that does a silly thing: It turns the element(s) a color, then reverts them to their original color after a timeout. We’ll use it like this:
If we’re thinking in terms of individual elements, our plug-in won’t work correctly:
Now let’s use it:
…with this HTML:
The problem here is that by thinking in terms of one element, the plug-in incorrectly saves the color of only the first element; when it goes to “restore” the original color, it applies the first element’s color to all the others, which is wrong. We end up with three divs using black text, where the second two shouldn’t be black. Live example | Source
Instead, if we think in terms of sets, we’d do it like this (for example; not saying this is the prettiest code on the planet):
We’ll use it like this (basically the same):
…with this HTML (basically the same):
Note how it’s saving each element’s color, and on the element itself via
data. When restoring, it restores each element’s color. Live example | Source