Developing a JQuery Plugin from Scratch

We will explore building a not trivial JQuery plugin and will implement the Scroll to Top functionality seen in certain websites. Our plugin will be a very basic version of a popular JQuery plugin called ScrollUp. Let’s dive in by creating a long HTML page to demonstrate the functionality of plugin.

<html>
	<head>
		<title>ScrollUp plugin demo</title>
		<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
		<script src="scrollup.js"></script>		
		<link rel="stylesheet" href="site.css">		
	</head>
	<body>
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. </p>
		...
		<a id="scrollLink" href="">Scroll To Top</a>
		<script>
			$(function(){
				$("#scrollLink").scrollUp();
			});
		</script>
	</body>
</html>

The above HTML is straight forward, it has JQuery and our plugin script as reference and is linked with site.css for common styling. The dummy text paragraph should be repeated many times to demonstrate the plugin functionality. We have placed a link at the bottom for scrolling to top. Inside the DOM Ready event of JQuery we trigger calling our yet to be created plugin. let’s give an outline to our plugin in the referenced scrollup.js file. The basic plugin creation reaquirement is to define plugin on the $.fn object.

(function($){	
	$.fn.scrollUp = function(){
		console.log("scrollUp plugin has called by the first customer!");
		this.click(function(event){
			$("html, body").animate({scrollTop: 0}, 2000);
			event.preventDefault();			
		});
		return this; // Let's not break the jQuery chain	
	}
})(jQuery)

Inside the plugin function this refers to the elements we have selected and applied scrollUp plugin method. In this (no pun intended) case it is our anchor element with id scrollLink. We are attaching a click handler on the passed in element and the handler will animate the scrollTop property of html and body to 0. Voila we have made our first version of plugin, in very very crude form and on clicking the link, the page scrolls to top in 2 seconds as the duration parameter to animate function we specified is 2000 milli seconds.

Now to see the link, we have to scroll right to the bottom and we can’t use the scroll to top functionality when we are some way from the top. Let’s fix that by showing the link always at the bottom right edge of the browser. We will make this change in the plugin code.

(function($){	
	$.fn.scrollUp = function(){
		this.click(function(event){
			$("html, body").animate({scrollTop: 0}, 2000);
			event.preventDefault();			
		});
		this.css({"bottom": "20px", "right": "20px", "position": "fixed"}); // This line is the only change
		return this; 
	}
})(jQuery)

Let’s move these position related data as HTML5 data attributes. This is just to introduce the data concept in JQuery and the same effect could have equally and elegantly achieved through CSS.

<a id="scrollLink" data-position="fixed" data-bottom="20px" data-right="20px" href="">Scroll To Top</a>

data method in JQuery allows to retrieve the HTML5 data attribute values easily by giving the attribute name as the parameter. In our case retreiving the position data one by one is tedious and hence we will use data method with no keys passed in so that we will get an object that contains all of the data attribute keys and values.

(function($){	
	$.fn.scrollUp = function(){
		this.click(function(event){
			$("html, body").animate({scrollTop: 0}, 2000);
			event.preventDefault();			
		});
		console.log(this.data()); // Let's verify it in console
		this.css(this.data()); // and then plug it data from HTML5 data attributes
		return this; 
	}
})(jQuery)

Our next move is to place two anchor links (on both sides of the text) to see how our plugin will perform. The HTML need to be changed and we will move from id to class for accomodating the tow links.

<html>
	<head>
		<title>ScrollUp plugin demo</title>
		<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
		<script src="scrollup.js"></script>		
		<link rel="stylesheet" href="site.css">
	</head>
	<body>
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. </p>
		...		
		<a class="scrollLink" data-position="fixed" data-bottom="20px" data-left="20px" href="">Scroll To Top</a>
		<a class="scrollLink" data-position="fixed" data-bottom="20px" data-right="20px" href="">Scroll To Top</a>
		<script>
			$(function(){
				$(".scrollLink").scrollUp();
			});
		</script>
	</body>
</html>

Refreshing the browser we will see that both anchor buttons are placed on the left side of the page. Although our plugin did work for single element it failed with more than one element. This is beacuse our plugin code is developed on the assumption of one element passed to the plugin function. Let’s fix that one.

(function($){	
	$.fn.scrollUp = function(){
		return this.each(function(){
			$(this).click(function(event){
			$("html, body").animate({scrollTop: 0}, 2000);
				event.preventDefault();			
			});
			console.log($(this).data());
			$(this).css($(this).data());
		});		
	}
})(jQuery)

this inside our plugin may be more than one element (as in our current case) so we are seeking the help of each method to iterate through our elements. Inside the each method, this points to the element and we have to wrap it to a JQuery element for accessing the JQuery methods. each method is a chainable method and hence it will return the passed elements back and we will also return it from our plugin to make our plugin also a chainable one.

One more problem in our plugin is that the link to scroll up is shown always and we need to display it if the user has scrolled down at least a pre-specified unit of length. We need to change our plugin as follows.

(function($){	
	$.fn.scrollUp = function(){
		
		var defaults = {
			scrollDuration: 2000,
			scrollTop: 400
		};

		return this.each(function(){

			$(this).click(function(event){
			$("html, body").animate({scrollTop: 0}, defaults.scrollDuration);
				event.preventDefault();			
			});

			console.log($(this).data());
			$(this).css($(this).data());
			$(this).hide();
			var link = $(this);
			$(window).scroll(function(){
				console.log($(window).scrollTop());
				if ($(window).scrollTop() > defaults.scrollTop) {
					link.fadeIn();
				}else{
					link.hide();
				};
			});			

		});

		
	}
})(jQuery)

As a measure of code cleanup we have refactored our hard coded scrollDuration and the number of pixels that must be scrolled for the links to appear in to a defaults object. In the above code we have attached a scroll event handler to the window and inside that handler we are checking the scrollTop of window against the default scrolTop value. If the scrollTop of window is greater than the default one we will display(through fadeIn animation) the link and otherwise we will hide it.

Before concluding the post, we will introduce the extend method in jJQuery. It will merge the properties of one or more objects with the first passed in object. This is handy for providing the means to overwrite our plugin’s default properties.

(function($){	
	$.fn.scrollUp = function(options){
		
		var defaults = {
			scrollDuration: 2000,
			scrollTop: 400
		};

		var o = {};
		$.extend(o, defaults, options);

		return this.each(function(){

			$(this).click(function(event){
			$("html, body").animate({scrollTop: 0}, o.scrollDuration);
				event.preventDefault();			
			});

			console.log($(this).data());
			$(this).css($(this).data());
			$(this).hide();
			var link = $(this);
			$(window).scroll(function(){
				console.log($(window).scrollTop());
				if ($(window).scrollTop() > o.scrollTop) {
					link.fadeIn();
				}else{
					link.hide();
				};
			});			

		});

		
	}
})(jQuery)
<script>
			$(function(){
				$(".scrollLink").scrollUp({
					scrollDuration: 4000,
					scrollTop: 800
				});
			});
</script>

The HTML is also changed to illustrate the overwriting of default property values of our plugin.

Although JQuery is easy to digest, its plugin development is a bit obscure and not easy to grasp in the first two or three tries. The aim of this post is to make the idea of plugin development in JQuery a little bit clear. - Suhair
comments powered by Disqus