Introduction
jQuery is the most popular JavaScript library amongst web developers. If you have some knowledge of jQuery, you may be familiar with code
like
$("#someId").text("Something");
$("someTagName").hide();
Here text()
and hide()
are built-in jQuery functions. We will try to create something by which we can call our own defined function to do some cool
stuff using jQuery. The statement will look just like a normal jQuery statement. Example :
$("someTagName").myFunction(options) ;
Here myFunction()
is a user defined function.
These user defined functions bundled together are known as jQuery plugin. Many times during developing a web project
we need to create our own jQuery plugin. This tutorial will help you understand how to create a basic jQuery plugin with well known standards.
Prerequisite
Before going to start creating the plugin we need to understand some topics.
- Function Declaration and Function Expression.
- Immediately Invoked Function Expression
- jQuery in no conflict mode
Let's understand one by one.
In any JavaScript file if you write something like:
justFunction();
function justFunction()
{
alert("something");
}
This will call the justFunction()
and show an alert. Defining a function like that is known as function declaration.
Now there is another way to define a function
var anotherFunction = function() { alert ("something")}
Now if you write something like
anotherFunction();
var anotherFunction = function() { alert ("something"); }
Although anotherFunction
is a function here this will give an error in console. This is known as function expression.
The reason behind that is function declarations loads before any code is executed. While function expressions loads only when the interpreter reaches that line of code.
So if you try to call a function expression before it's loaded, you'll get an error.
But if you call a function declaration, it'll always work. Because no code can
be called until all declarations are loaded. So you will have to always call the function expression after it is defined.
var anotherFunction = function() { alert ("something"); }
anotherFunction();
Now a function expression can be called immediately by adding parenthesis after the
anonymous function like
var anotherFunction = function() { alert ("something"); }();
This code snippet and the above does the same thing (shows the alert). Now the anotherFunction
variable is not the same as above
because it is now assigned
with the value , that the anonymous function will return. Right now it is not returning anything so anotherFunction
is undefined.
So if you write something like
var anotherFunction = function() { alert ("something"); }();
anotherFunction();
This will give an error, because the anonymous function does not return any function. If its returns something like
var anotherFunction =
function() { alert ("something"); return "some string"; }();
anotherFunction
is now a string variable. And if:
var anotherFunction = function() { alert ("something"); return function(){
alert("somethingElse")
}; }();
Now anotherFunction
is a function and can be called like anotherFunction()
.
You can pass parameters to this function expression like
var anotherFunction = function(p1,p2) { console.log(p1);
console.log(p2); }(param1,param2 );
One of the main difference between a function expression and a function declaration is that A function expression can be called (invoked) immediately by using a set of parentheses,
but a function declaration cannot be.
Now if we don't want to assign the function expression to a variable, then we have to write it inside parenthesis.
(function() { alert ("something");});
And to call it we need to add another set of parenthesis at the end like
(function() { alert ("something"); }());
And same as earlier, we can also pass parameters to it like:
( function(param){ console.log(param); }(param));
This type of functions are called IIFE (Immediately Invoked Function Expression).
IFFE is just an anonymous function (no name attached to it) that is wrapped inside of a set of parentheses and called (invoked) immediately.
( function(){ }());
Now the reason behind discussing this is, all our plugins code will be inside a IIFE. To understand why this is done we have to understand another topic that
is jQuery in noConlict mode.
jQuery has a shorthand notation for the jQuery object that is the $
sign. Many JavaScript libraries use $
as a function or variable name,
just as jQuery does. If you need to use another JavaScript library alongside jQuery, you can replace the jQuery's default $
sign by any other name.
If you have included the jQuery file in the head section of your html page like this:
<head>
<script src="jquery-1.7.1.js" type="text/javascript"></script>
<script src="index.js" type="text/javascript"></script>
</head>
The index.js page loads immediately after the jQuery file. So you can change the '$'
sign by using this code
var jq = jQuery.noConflict();
jq(function()
{
jq("div p").hide();
}
);
This way there would not occur any conflict between, jQuery $
sign and other
JavaScript libraries $
sign.
Changing the default $
of jQuery may not be a matter of pleasure for many software developers because they are so much used to write jQuery codes using the
$
sign. There is a solution to this. If you don't need to mix codes of jQuery and other
JavaScript library then you can wrap all of your jQuery code
in an IIFE (Immediately Invoked Function Expression). Because our plugin is dependant only on jQuery, all our plugin codes will be inside this code block.
(function ($)
{
} (jQuery));
Here we pass the jQuery
object as parameter and receive it using the $
sign. So all the codes are inside a local scope and it will not conflict
with other libraries $
sign. There are more benefits to using IIFE’s than just local scoping. Here is a good article. Now we are set to create our jQuery plugin. In the next section we will create our own plugin.
Creating the jquery Plugin
For this short tutorial we need four files.
- index.html
- index.js
- jquery.myPlugin.js
- jquery-1.7.1.js
In the index.html file write some simple HTML code like this:
<html>
<head>
<title>Index</title>
<script src="jquery-1.7.1.js" type="text/javascript"></script>
<script src="index.js" type="text/javascript"></script>
<script src="jquery.myPlugin.js" type="text/javascript"></script>
</head>
<body>
<h1>First Header</h1>
<h1>Second Header</h1>
<h1>Third Header</h1>
<input id="btnChange" type="button" value="Change" />
</body>
</html>
jquery.myPlugin.js is the file where we will write all our jQuery plugin
code. OK, let's do a simple thing like changing the color of the headers to red.
So our plugin code will look like
(function($){
$.fn.makeChange = function(){
this.css({color : "red"});
};
}(jQuery));
and in the index.js file inside the form load event we bind the change
button click event and call our makeChamge
plugin function.
$(function(){
$("#btnChange").click(function(){
$("h1").makeChange();
});
});
If we now double click the index.html file then the page will look like this in browser:
Now if you click the Change button, it will look like this:
Yes, that means our plugin code is working. Now let's take a look at the plugin code again:
(function($){
$.fn.makeChange = function(){
this.css({color : "red"});
};
}(jQuery));
You can see that we have assigned the makeChange
function in to $.fn
.
$.fn
points to the jQuery.prototype
. Any method or property you add to it becomes available to all instances of the jQuery wrapped objects. Notice that to use .css()
, we use this
, not $( this )
. This is because our makeChange
function is a part
of the same object as .css()
.
Now let's add some more features like changing the text and font-style.
(function($){
$.fn.makeChange = function(){
this.css({color : "red",fontStyle: "italic"});
this.text("Header Text Changed");
};
}(jQuery));
Now if you load the page and click the Change button again you will see something like this
Now, jQuery supports a technique called chaining, that allows us to run multiple jQuery commands, one after the other, on the same element(s).
Statements like this is example of chaining:
$("#someId").css("color","red").slideUp(2000).slideDown(2000);
Because we are creating a jQuery plugin our makeChange
function should support chaining.
Lets try a chained statement in our index.js file
$("h1").makeChange().slideUp(2000);
Now now let's reload the index.html page and click the Change button:
As our chained statement suggests the headers should have been slid up and become invisible but this is not happening. So our makeChange
function does not support
chaining. To make it support chaining we need to return the element like this:
(function($){
$.fn.makeChange = function(){
this.css({color : "red",fontStyle: "italic"});
this.text("Header Text Changed");
return this;
};
}(jQuery));
Now if you reload the index.html page and click the Change button again, you will see the headers are sliding up with the speed you have given (here 2000 ms).
And eventually they will disappear.
So now we have added the chaining feature to our plugin.
Now let's try to get text of each header individually and edit it. So this simple peace of code should do it.
(function($){
$.fn.makeChange = function(){
var hText= this.text();
this.css({color : "red",fontStyle: "italic"});
this.text(hText+" With New Added Text");
return this;
};
}(jQuery));
Now after reloading the index.html page and clicking the Change button, we will see something like this:
This does not serve our purpose because we want the header text like "First Header With New Added Text".
What happening here is this.text()
function returning all text from the 3 headers. Now to solve this we need to use the jQuery each
iterator.
(function($){
$.fn.makeChange = function(){
return this.each( function(){
var hText= $(this).text();
$(this).css({color : "red",fontStyle: "italic"});
$(this).text(hText+" With New Added Text");
});
};
}(jQuery));
And now reloading the index.html page and clicking the Change button will give you:
It's important to use each
loop because our typical jQuery object will contain references to any number of DOM elements. If you want to manipulate specific element
then you must need each loop.
Notice that the this
element is inside the each
function is a jQuery wrapped element now because function context has changed.
We have wrapped the element three times here. The best practice is to wrap the this
element and assign it to a variable then reuse it.
(function($){
$.fn.makeChange = function(){
return this.each( function(){
var self= $(this);
var hText= self.text();
self.css({color : "red",fontStyle: "italic"});
self.text(hText+" With New Added Text");
});
};
}(jQuery));
Till now our jQuery plugin performs some static change upon elements. Now let's give the user opportunity to pass parameters. That means let's accept some options.
In the index.js file you can supply options like this:
$(function(){
$("#btnChange").click(function(){
$("h1").makeChange({color: "green",
text: "Text Supplied By Option" ,
fontStyle: "italic"
});
});
});
and in jquery.myPlugin.js, you can accept and use options like this:
(function($){
$.fn.makeChange = function(options){
return this.each( function(){
var self= $(this);
var hText= self.text();
self.css({color : options.color,fontStyle: options.fontStyle});
self.text(hText+" "+ options.text );
});
};
}(jQuery));
Now if you reload the index.html page and click the Change button, you will see this:
Now our plugin should have some default settings if no value is supplied. If a value is supplied then the default value will be overridden.
For this purpose we can use the $.extend
method. Now let's look at the code
(function($){
$.fn.makeChange = function(options){
var defaults = {
text: "Default Text",
color: null,
fontStyle: null
};
var settings = $.extend(defaults, options);
return this.each( function(){
var self= $(this);
var hText= self.text();
self.css({color : settings.color,fontStyle: settings.fontStyle});
self.text(hText+" "+ settings.text );
});
};
}(jQuery));
Here we have a defaults
variable which contains our default settings. options
contains the user defined settings.
$.extend
method merges the contents of two or more objects together into the first object. so the variable settings
contains the overall settings for the plugin.
Another important thing is that the default value for color
and fontStyle
is null.
So it's better to check if a value is passed to the options before performing any modification. So our plugin code will look like this
function($){
$.fn.makeChange = function(options){
var defaults = {
text: "Default Text",
color: null,
fontStyle: null
};
var settings = $.extend(defaults, options);
return this.each( function(){
var self= $(this);
var hText= self.text();
self.text(hText+" "+ settings.text );
if(settings.color)
{
self.css({color : settings.color});
}
if(settings.fontStyle)
{
self.css({fontStyle: settings.fontStyle});
}
});
};
}(jQuery));
Last thing is we can also pass functions in options. So in the index.js page, you can send your function like this:
$(function(){
$("#btnChange").click(function(){
$("h1").makeChange({color: "green",
text: "Text Supplied By Option",
fontStyle: "italic",
complete: function(){
alert("Done");
}
});
});
});
Here complete
is a function that you are supplying to the options. Now in our plugin code we need to call this function like this:
(function($){
$.fn.makeChange = function(options){
var defaults = {
text: "Default Text",
color: null,
fontStyle: null
};
var settings = $.extend(defaults, options);
return this.each( function(){
var self= $(this);
var hText= self.text();
self.text(hText+" "+ settings.text );
if(settings.color)
{
self.css({color : settings.color});
}
if(settings.fontStyle)
{
self.css({fontStyle: settings.fontStyle});
}
if($.isFunction( settings.complete ))
{
settings.complete.call(this);
}
});
};
}(jQuery));
Here first we have checked that if settings.complete
is supplied and it's
a function and then call it.
So if you reload index.html and click the Change button we will get three alerts for three headers.
So that's all for the article. Hope this will be of some help to you.