Categories
jQuery

Creating jQuery Plugins

Update: I was able to get permission to release the iScroll plugin! Check it out here.

Not too long ago I decided to write a jQuery plugin for making the use of iScroll a little less painful. Since I made the plugin at work I’m not really at liberty to share it. But what I can share is a step by step tutorial for creating a jQuery plugin of your own. Let’s get started.

Step 1: Scope

If you’ve been writing Javascript with jQuery for any amount of time, you find out pretty quickly that proper scoping is very important. You also learn that the $ symbol isn’t reliable. So what’s a coder to do? Make sure that your scope is contained within an anonymous function, and that you pass the jQuery object into that function.

(function($) {
	console.log($(document).jquery);
})(jQuery);

If you paste this code into your console (assuming jQuery is included), you should receive a print out of what version of jQuery you’re using.

Step 2: Functions

Now that you have the basic wrapper written, we need to write some real code. Before we start, there are 3 things you need to know.

  1. Functions are attached to the $.fn object.
  2. There may be more than one element passed into your function (plugin)
  3. We want to keep the chain alive if possible. (See jQuery Chaining if you have questions)

So, let’s write a function that adds the class “bob” to every item in the set. Yes, we could just use the .addClass() method, but then we wouldn’t need to write a plugin would we?

(function($) {
	$.fn.addBob = function() {  //Add the function
		return this.each(function() { //Loop over each element in the set and return them to keep the chain alive.
			var $this = $(this);
			$this.addClass("bob");
		});
	};
})(jQuery);

Step 3: Options

So let’s say you need to pass some options to your plugin. You know, like Bob’s last name, or if we should remove Bob. To accomplish this, all you do is create a defaultOptions object and load it with defaults. Then you use the $.extend function to overwrite it’s values with values passed in as a function parameter.

(function($) {
	$.fn.addBob = function(customOptions) {  //Add the function
		var options = $.extend({}, $.fn.addBob.defaultOptions, customOptions);
		return this.each(function() { //Loop over each element in the set and return them to keep the chain alive.
			var $this = $(this);
 
			//Determine what name to use.
			var name = "";
			if(options.lastName != "") {
				name = "bob-" + options.lastName;
			} else {
				name = "bob";
			}
 
			//Are we removing items?
			if(options.remove) {
				$this.removeClass(name);
			} else {
				$this.addClass(name);
			}
		});
	};
 
	$.fn.addBob.defaultOptions = {
		lastName : "",
		remove : false	
	};
})(jQuery);

Step 4: Running your plugin

Now that you’ve written your plugin, you need to run it!
Before

<ol id='x'>
	<li></li>
	<li></li>
</ol>
<ol id='y'>
	<li></li>
	<li></li>
</ol>

JS

	$("#x li, #y li").addBob({lastName: "awesome"});

After

<ol id='x'>
	<li class='bob-awesome'></li>
	<li class='bob-awesome'></li>
</ol>
<ol id='y'>
	<li class='bob-awesome'></li>
	<li class='bob-awesome'></li>
</ol>

JS

	$("#y li").addBob({lastName: "awesome", remove: true});

After

<ol id='x'>
	<li class='bob-awesome'></li>
	<li class='bob-awesome'></li>
</ol>
<ol id='y'>
	<li></li>
	<li></li>
</ol>

That’s all there is to it. If you have any questions, leave a comment and I’ll get back to you as soon as I can.

Categories
jQuery

jQuery Chaining

jQuery is the jewel in the crown that is web development. Once you discover it, Javascript is no longer a chore to write, hell, it might even be considered fun! Sure being able to select elements by ID, class, or type is great, but what about all the other stuff? What about chaining? I’ve heard such great stuff about it!

Chaining

The first thing you need to know about chaining is that you chain actions on to collections. A collection is what is returned when you select something using jQuery.

$("input");  //Collection of all input elements on the page.

When most people start using jQuery, they do something like this:

$("input").val("123");
$("input").addClass("awesome");
$("input").attr("data-bind", "15");

Yes, this code will work, but it’s inefficient. Every time you perform a selection, jQuery must traverse the DOM and find all the input elements. If you use chaining, it will simply use the collection of input elements that it already has.

$("input")
	.val("123")
	.addClass("awesome")
	.attr("data-bind", "15");

So why does this work? Because each method that you call in the chain returns the collection. So in this case “val()”, “addClass()”, and “attr()” all return “$(input)”. However, not all methods support chaining. For instance, the “text()” method breaks the chain, so if you’re going to use it, do it at the end.
What if you want to keep the chain alive though? No problem. You can simply back-out of the destructive action using the “end()” method.

Before

<ol id='mylist'>
	<li>
	</li>
	<li>
	</li>
	<li>
	</li>
</ol>

Javascript

$('#mylist')
	.find('>li')
		.filter(':last')
			.addClass('Meow')
		.end()
		.filter(':first')
			.addClass('Mix')
		.end()
		.addClass('catfood')
	.end()
	.addClass('thelist');

After

<ol id='mylist' class='thelist'>
	<li class='Mix catfood'>
	</li>
	<li class='catfood'>
	</li>
	<li class='Meow catfood'>
	</li>
</ol>

While sometimes confusing, you can see that chaining is often the most efficient way to handle modifying the DOM.

Writing Chainable Plugins/Functions

Now that you know all about chaining, you’ll probably want to write your own chainable plugins/functions. It’s very easy to do this, since all you need to do is return the jQuery object at the end of the function.

In this example, we’ll write a plugin that attaches a second counter to an element.

Plugin

(function($) {
	$.fn.count = function() {
		return this.each(function() {  //We do an 'each', because the collection may have more than one item in it.
			var self = $(this);  //
			self.html('0');
			var theInterval = window.setInterval(function() {
				var c = parseFloat(self.text());
				self.html(c + 1);
			}, 1000);
		});
	}
}) (jQuery);

HTML

<div>
	<span id='test'></span>
</div>

Execution

$("#test").count().parent().addClass('counters'); //Chaining still works :)