How to Create a Basic Plugin

Contact Us or call 1-877-932-8228
How to Create a Basic Plugin

How to Create a Basic Plugin

The typical approach for creating a plugin is as follows:

(function($){
	$.fn.myNewPlugin = function() {
		return this.each(function(){
			// do something
		});
	};
}(jQuery));

The outer wrapper is an immediately-invoked function, inside which we create the plugin:

(function($){
	//...
}(jQuery));

This has the effect of creating a "private" scope that allows us to extend jQuery using the dollar symbol without having to risk the possibility that the dollar has been overwritten by another library. Although it is not required that you establish the plugin this way, this is the conventional approach.

The most important aspect of creating a plugin is to assign the method to the base jQuery object, which is what this part accomplishes:

$.fn.myNewPlugin = function() { ... }

$.fn is the base object containing all the jQuery collection methods. Any methods we add to this base object will be available to anything retrieved with $(selector).

The this keyword within the new plugin refers to the jQuery object on which the plugin is being called.

Your typical jQuery object will contain references to any number of DOM elements, which is why jQuery objects are often referred to as collections.

To do something with a collection we need to loop through it, which is most easily achieved using jQuery's each() method:

$.fn.myNewPlugin = function() {
	return this.each(function(){
		// perform operations an individual elements
		// which will be available as this
	});
};

jQuery's each() method, like most other jQuery methods, returns a jQuery object, thus enabling what we've all come to know and love as "chaining", for example: $(...).css().attr(...). We wouldn't want to break this convention, so we return the this object. Within this loop you can do whatever you want with each element.

Here's an example of a small plugin using some of the techniques we've discussed, intended to show a hyperlink's url as part of its displayed text:

(function($){
	$.fn.showLinkLocations0 = function() {
		return this.each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		});
	};
}(jQuery));

This code appends text to every element it finds, showing that elements' href attribute in parentheses. The problem with this approach is that it will do that indiscriminately, regardless of whether an element is actually an a tag or not. Since we have no control over what selector is used, this will cause a problem.

(function($){
	$.fn.showLinkLocations1 = function() {
		return this.filter('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end();
	};
}(jQuery));

Now we are filtering the elements, and only operating on a tags. Note the call to end() at the end of the chain, which ends the most recent filtering operation in the current chain and returns the set of matched elements to its previous state. filter() will produce a subset of the original set, but whoever uses the function would probably rather have it return the original set.

Testing Our Plugin

OK, great, so we're done. Open up jqy-plugins/Demos/showLinkLocation.html and let's see what different versions of the demo look like...

Version 1 of our Plugin

From the screenshot below, you can see how the plugin works when invoking the showLinkLocations1() function. Note that not every link is affected. We select all elements with css class ".special", and links with this class do get changed. But, links within the <div class="special"> do not. filter finds a subset of the current set of elements, but does not select descendants of the current set. We would probably like a tags that are contained within any selected elements to be changed as well.

Show Link Locations 1

Version 2 of our Plugin

(function($){
	$.fn.showLinkLocations2 = function() {
		return this.find('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end();
	};
}(jQuery));

This version uses find instead of filter, and finds all descendant a tags (notice the screenshot below). But, now the problem is reversed -- find will produce only descendant elements within the original selection, and omit the a tags that directly selected by the query.

Show Link Locations 2

Final Version of our Plugin

So, we need to use both approaches, as shown below.

Code Sample:

jqy-plugins/Demos/showLinkLocation.html
<html>
<head>
<style>
.redText { color: red; }
</style>
<script src="../../jqy-libs/jquery.js"></script> 
<script src="../../jqy-libs/fix-console.js"></script> 
</head>
<body>
<div>
	<a class="special" href="http://www.webucator.com/">Webucator</a>
	<a class="special" href="index.html">Home</a>
	<a class="special" href="more.html">More</a>
</div>
<p class="special">This is special, too!</p>
<div class="special">
	<a href="http://www.webucator.com/">Webucator</a>
	<a href="index.html">Home</a>
	<a href="more.html">More</a>
</div>
<div>
	<a href="http://www.webucator.com/">Webucator</a>
	<a href="index.html">Home</a>
	<a href="more.html">More</a>
</div>
<p>This is not special!</p>
<script>
// filter only
(function($){
	$.fn.showLinkLocations1 = function() {
		return this.filter('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end();
	};
}(jQuery));

// find only
(function($){
	$.fn.showLinkLocations2 = function() {
		return this.find('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end();
	};
}(jQuery));

// both find and filter
(function($){
	$.fn.showLinkLocations = function() {
		return this.find('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end().filter('a').each(function(){
			$(this).append(' (' + $(this).attr('href') + ')');
		}).end();
	};
}(jQuery));
    
// Usage example:
$('.special').showLinkLocations().css( { fontSize: '20pt'} );
</script>
</body>
</html>

This plugin first finds all the a descendants of a selection, then backs up and uses filter, and then backs up again to return the original selection (which is confirmed by the font size change in the one p.special element).

Show Link Locations Final Version

Here's another example of a plugin. This one doesn't require us to loop through every element with the each() method. Instead, we're simply going to delegate to other jQuery methods directly:

(function($){
	$.fn.fadeInAndAddClass = function(duration, className) {
		return this.fadeIn(duration, function(){
			$(this).addClass(className);
		});
	};
}(jQuery));

// Usage example:
$('a').fadeInAndAddClass(400, 'finishedFading');
Next