Getting the id of the control my jQuery plugin is connected to

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 connect the plugin as follows:

 $( '#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 identifier from this , which evaluates to [] for any control that is not on the page that I'm online on.

What is the correct way to get the identifier of the controls the plugin is connected to?

Many thanks:).

+4
source share
2 answers

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

+11
source

You must implement your plugin with each , then you will not have problems with empty jQuery objects:

 $.fn.MyPlugin = function( method ) { this.each(function() { 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' ); } }); }; 
+1
source

Source: https://habr.com/ru/post/1396842/


All Articles