There is a fundamental problem here: you are thinking about a single element. jQuery is all about element sets. this in your plugin is a jQuery instance that can contain 0..n matched elements. May be zero, one, 27, 342, etc. Thus, this[0].id does not make sense in a connected jQuery module, because you just get the id of the first matching element (even if it has one, there is no requirement for it to be) or error (as you discovered) when the set has no elements at all.
So, if you start thinking about your plug-in, dealing with a set of matched elements, which can be an empty set, a small set, or a large set, you will be on the right track.
Here is a specific example: letβs write a plugin that does a stupid thing: it turns an element into a color and then returns them to their original color after a timeout. We will use it as follows:
$("selector").plugin("newcolor", timeout)
If we think in terms of individual elements, our plugin will not work correctly:
// The "foo" plug-in thinks in terms of just one element $.fn.foo = function(color, time) { var self, oldColor; self = this; // Save the current color -- this is wrong oldColor = self.css("color"); // Set new color self.css("color", color); // Restore old color after timeout setTimeout(function() { self.css("color", oldColor); }, time); };
Now let's use it:
$("#theButton").click(function() { $(".foo").foo("blue", 1000); });
... with this HTML:
<div class="foo">This is the first "foo" div</div> <div class="foo" style="color: green">This is the second "foo" div</div> <div class="foo" style="color: red">This is the third "foo" div</div> <div><input type="button" id="theButton" value="Use foo"></div>
The problem is that, thinking in terms of one element, the plugin incorrectly preserves the color of only the first element; when he proceeds to "restore" the original color, he applies the first color of the element to all the others, which is incorrect. As a result, we get three divs with black text, where the two second ones should not be black. Live example | Source
Instead, if we were to think in terms of sets, we would do it like this (for example, without saying that this is the most beautiful code on the planet):
// The "bar" plug-in understands sets $.fn.bar = function(color, time) { var self; self = this; // Get the current color of each element self.each(function() { var entry = $(this); entry.data("oldColor", entry.css("color")); }); // Set new color self.css("color", color); // Restore old color after timeout setTimeout(function() { self.each(function() { var entry = $(this); entry.css("color", entry.data("oldColor")).removeData("oldColor"); }); }, time); };
We will use it like this (basically the same):
$("#theButton").click(function() { $(".bar").bar("blue", 1000); });
... with this HTML (basically the same):
<div class="bar">This is the first "bar" div</div> <div class="bar" style="color: green">This is the second "bar" div</div> <div class="bar" style="color: red">This is the third "bar" div</div> <div><input type="button" id="theButton" value="Use foo"></div>
Pay attention to how it saves the color of each element and the element itself through data . When restoring, restores each color of an element. Live example | Source