jMar"s Blog DevSmash Developer Portal

Sunday, February 3, 2008

Building Your First jQuery Plugin

So you were out on your quest to find the answer to life, the universe, and everything, when blam, you found jQuery. Yes, I know, you were expecting 42, but too all of our surprise, it was jQuery. So what's next? Build your own plugin!

While some are intimidated by the thought of creating their own plugin, the truth is that jQuery is built with an infinitely friendly plugin architecture. If you've gotten comfortable with the basics of jQuery coding, then you're certainly ready to develop your own plugin. This tutorial will take you step by step through creating your very own truncation plugin. Say, for example, you have a "tip of the day" widget on your home page. This plugin will let you truncate it to a specified length, with a link to expand it to view it's full content. Here's a working example:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit, odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum, feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet, dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.

Note that if JavaScript is disabled (or not supported) the content will simply display in it's entirety.

You ready? Let's dig in...

Step 1

The first step is to extend the actual jQuery object with the function that we wish to add. In our case, we wish to add "truncation" functionality. So here's where to start: create a jquery.truncate.js file and save it with the following code:

$.fn.truncate = function(options) {

   return this.each(function() {

   });
};

Now you may have heard that plugin developers should not user the $ alias, as this can result in conflicts with other libraries. This is only partially true. The following snippet is the same as the one above, except that we pass jQuery into the function, allowing us to use an alias we want. We'll stick with $.

(function($){
 $.fn.truncate = function() {

    return this.each(function() {

    });
 };
})(jQuery);
Step 2

Before we go any further, let's create a simple test page that we can use to test our plugin. Create a page and call it whatever_you_want.html. Insert the following code. As you can see I placed both the jQuery library and the plugin inside a folder named js. Note that we are already invoking our plugin in this snippet, although we have not yet coded any behavior.

<html>
<head>
 <title>Truncation Plugin Test</title>
 <script src="js/jquery.js" type="text/javascript"></script>
 <script src="js/jquery.truncate.js" type="text/javascript"></script>
 
 <script type="text/javascript">
  $().ready(function() {
   $('.tip').truncate();
  });
 </script>
</head>
<body>
 <div class="tip" style="width:200px;background-color:#ccc;padding:10px;">
  Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit,
  odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum,
  feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit
  pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet,
  dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh
  ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris
  odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.
 </div>
</body>
</html>
Step 3

The next thing we want to do is provide a mechanism for the user to customize the plugin. While we want to make the plugin as flexible as possible, we should also provide defaults so that the user isn't forced into providing a long list of parameters. We can easily do this using jQuery's extend method. Update your plugin to match the following:

(function($){
 $.fn.truncate = function(options) {

  var defaults = {
   length: 300,
   minTrail: 20,
   moreText: "more",
   lessText: "less",
   ellipsisText: "..."
  };
  var options = $.extend(defaults, options);
    
  return this.each(function() {

  });
 };
})(jQuery);

For now we won't override any of the defaults in our test page, but we'll demonstrate this later.

Step 4

So that takes care of all the preliminary considerations. Let's get to coding the plugin's functionality. As you've already seen, the plugin is returning this.each(...). This line will execute the contained anonymous function on each item in the jQuery array. So, if for example we called $('p').truncate(), the code we're about to write would execute on every p tag.

Since I'm assuming a comfortable understanding of jQuery, I won't explain in detail how the function's code actually works. If anything in the code is not obvious, you should refer to the documentation or ask a question in the comments. To complete your plugin, update it to match the following:

(function($){
 $.fn.truncate = function(options) {
    
  var defaults = {
   length: 300,
   minTrail: 20,
   moreText: "more",
   lessText: "less",
   ellipsisText: "..."
  };
  
  var options = $.extend(defaults, options);
    
  return this.each(function() {
   obj = $(this);
   var body = obj.html();
   
   if(body.length > options.length + options.minTrail) {
    var splitLocation = body.indexOf(' ', options.length);
    if(splitLocation != -1) {
     // truncate tip
     var splitLocation = body.indexOf(' ', options.length);
     var str1 = body.substring(0, splitLocation);
     var str2 = body.substring(splitLocation, body.length - 1);
     obj.html(str1 + '<span class="truncate_ellipsis">' + options.ellipsisText + 
      '</span>' + '<span  class="truncate_more">' + str2 + '</span>');
     obj.find('.truncate_more').css("display", "none");
     
     // insert more link
     obj.append(
      '<div class="clearboth">' +
       '<a href="#" class="truncate_more_link">' +  options.moreText + '</a>' + 
      '</div>'
     );

     // set onclick event for more/less link
     var moreLink = $('.truncate_more_link', obj);
     var moreContent = $('.truncate_more', obj);
     var ellipsis = $('.truncate_ellipsis', obj);
     moreLink.click(function() {
      if(moreLink.text() == options.moreText) {
       moreContent.show('normal');
       moreLink.text(options.lessText);
       ellipsis.css("display", "none");
      } else {
       moreContent.hide('normal');
       moreLink.text(options.moreText);
       ellipsis.css("display", "inline");
      }
      return false;
       });
    }
   } // end if
   
  });
 };
})(jQuery);

You'll notice that whenever I needed to select an element within the plugin, I always used obj as my context (e.g., moreLink = $('.truncate_more_link', obj)). This is necessary to constrain any selections to the current truncated element. Without setting the context like this, you will get unpredictable results.

So that's it - your first jQuery plugin! We're not quite finished though, since I promised we'd demonstrate overriding the default options. In the following example, every option has been over ridden, although it is perfectly valid to override fewer. Just replace the script in your test page with this:

$().ready(function() {
 $('.tip').truncate( {
  length: 120,
  minTrail: 10,
  moreText: 'show more',
  lessText: 'show less',
  ellipsisText: " [there's more...]"
 });
});

This code will give you something like this:

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Etiam fringilla, purus a ultrices blandit, odio ante scelerisque neque, vitae imperdiet odio velit ac nisl. Sed tortor metus, placerat condimentum, feugiat in, feugiat adipiscing, mi. Donec pulvinar sem vitae leo. Vestibulum eget lectus et ligula hendrerit pharetra. Sed porta justo ac nisl. Aliquam nisi erat, pellentesque sed, sagittis eu, fringilla sit amet, dolor. Nam ac mi. Pellentesque pede purus, mattis aliquet, semper nec, cursus a, orci. Duis bibendum nibh ac massa. Integer eu tortor. Aenean convallis quam at nunc. Nunc mollis tincidunt nisi. Suspendisse mauris odio, iaculis ut, feugiat vitae, ultrices in, tortor. Quisque at elit. In hac habitasse platea dictumst.

Well... I hope you found this helpful. If you have any questions beyond what I've explained, please just ask in the comments. Thanks for reading!

Update! (2/26/2008)

The plugin that we just developed above has now been added to the jQuery plugin repository under the name of jTruncate. The home page is located here on my blog. It is now an evolving beast, so check there for any updates.



83 comments:

Henrik said...

I found you through the learning jQuery site. Looking good, keep up the good work, I just subscribed to the jQuery category.

Jeremy Martin said...

@henrik
Thanks for the comment. I'm still new to blogger here, but I'll try and keep the content coming!

amir said...

great tutorial !
thanks !

Anonymous said...

very helpful. two beers extra credit

Anonymous said...

it is ovv... great helpful.
thanks lots

Anonymous said...

Hello,
Thanks for this helpful artcile.
i tried to integrate this plugin code with Ajax. and it worked only with Firefox. while IE7 didn't make it

Alien said...

nice tutorial! thanks!!

yorsal said...

great job

Adam said...

I appreciate this sort of tutorial and I've found it rather helpful. There is, I think something missing, at least if I compare it to the jQuery UI plugins.

jQuery UI has undergone a number of revisions to the syntax but I think the current syntax will remain stable and would be worth including in your tutorial.

Specifically, I'd like to see a discussion on how to add methods to your plugin. For exmaple, if this was a jQuery UI widget you'd do:

$('really_long').truncate();
$('really_long').truncate("open"); //"expand" ???
$('really_long').truncate("close"); //"contract" ???
$('really_long').truncate("destroy");

This handles the full life cycle of the the widget and allows for programatic control.

Jeremy Martin said...

@Adam
Sorry for the looong delay in responding. I absolutely agree - this type of a plugin should be integrated with the UI API (at the time of writing this tutorial, UI was still premature).

When I'm done with the next release of kwicks, I should use this as an opportunity to do a follow up tutorial on UI plugin development (although I might wait until 1.5 is released). Thanks for the suggestion!

Different Adam said...

This is probably the best plugin tutorial that I have ever read. You just can't beat keeping it simple and straight forward.

Jeremy Martin said...

@Different Adam
Thank you - that's much appreciated!

John Tantalo said...

Jeremy, can you comment on using the alternate form of jQuery.extend, where no target is specified?

From the docs: If no target is specified, the JQuery namespace itself is extended. This can be useful for plugin authors wishing to add new methods to JQuery.

Is this the preferred method of writing plugins, or is it overly complicated for beginners?

Jeremy Martin said...

@John
Certainly - when you provide $.extend with a target, like we did in the above example, it "extends" the target parameter with the methods/properties in the object1 parameter. That is how we simultaneously updated/added to our defaults with the options provided by the user.

In the case where no target is provided, jQuery assumes that jQuery itself is the target. In that sense, you could consider the following two statements to be equal:

jQuery.extend(someObj);

and...

jQuery.extend(jQuery, someObj);

As the documentations specifies, this is a useful syntax for modifying the jQuery object itself, which in *most* cases would be used for adding new utility methods, like these.

Regarding your second question, I did attempt to make this example conform to the guidelines and recommendations provided here, so I would say, yes, this is the preferred methods for writing plugins (although always refer to the docs themselves, as they get updated and this post does not!).

I hope that helps clarify things - let me know if you have any further questions!

coderbari said...

Great tutorial.I was looking to find a guide on building plugin and found this page.Thanks a lot amigo.

terminals-blocks said...

I just subscribed to the jQuery category.

Jahedur Rahman said...

Great!!! It helped me :)
Thanks.

Developer said...

very good and very easy.

thanks

Marcelo Kanzaki said...

I got confused, you've used two variables with the same name.

var options = $.extend...

and the 'options' parameter used by the plugin to customize it.

When you reference 'options' later, i don't know which one is each.

Jozef Pohorelec said...

There should be something like this:

options = $.extend(defaults, options);

instead of:

var options = $.extend(defaults, options);

reykats said...

Well good enough... But mine is better than yours... Hehehhe

Anonymous said...

Very helpful tutorial.
Thanks for your work! Now all things are clear! Weel done!

Anonymous said...

hi there,

I want to call a jquery function from my .cs page. I have made a plugin called jquery.xyz.js.
I have registered it on my aspx page. i have made a function in this plugin as follows :

$.extend($.fn, {
SelectMenuProcess: function(MainElemID) {
return this.each(function() {
document.getElementById("check").className = "section-" + MainElemID;

});

}
});

Iam calling this function from the .cs page as follows:

this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "startup", "[script type=\"text/javascript\"]SelectMenuProcess('" + Request["Tab"] + "');[/script]");

When i execute this code, firebug shows error ie "SelectMenuProcess" is undefined.

Hardy said...

Good guide! I'm going to try my own plugin for JQuery now! This post helped a lot!

Anky said...

very nice tutorial.

Иван said...

thanx a lot man, very helpfull!

Somel said...

Thanks for this article which is really helpful for me because I am just first start to build my own jQuery plugin.

Osama said...

Thanks man, really its a helpful article

Raviv M-G said...

Hi,

Great post. Really helpful to me in learning to be author plugins.

One thing that I would note is that you may want to encourage people to have:

var obj = $(this);

instead of just

obj = $(this);

Sometimes you want multiple instances of the same plugin on a single page and if obj variable is global then the two instances will overlap and interfere with each other.

Thanks again,
Raviv

John said...

create tutorial! Thanks!

Paamayim said...

Very useful tutorial :)

Could you please explain, if you know how is done, I could specify an event handler to bind to "obj" ?

Where to put the function implementation?

return this.each(function() {
$(this).keyup(update);
});

where should I put the update() function and any other helper funciotn I'm gonna use? Is right after "(function($){" correct?

Thanks

Prashant Nair said...

This is really good and helpful...cheers Jeremy!

zara said...

Very cool. Tnx a lot!

herry monster said...

Thanks

Winston said...

Very nice tutorial. Good job mate

Eng.Mohammed said...

thank you very much .. it's very useful for me

Anonymous said...

Thanks, this has helped a lot!

fimseyretir said...

I found you through the learning jQuery site. Looking good, keep up the good work, I just subscribed to the jQuery category.

Anonymous said...

Thanks for this, it's a great plugin. The only thing that's not working quite right is that after using show(), the content in the div drops a line, and the element's display is set to "block". Is there any way to get around this?

Thanks again.

Jameshd said...

Very useful tutorial, thanks... bit easier to follow for us newbies!

Anonymous said...

This is just great tutorial! There is one strange behaviour though. I have div which contains many paragraphs and it truncates and expands only the first paragraph and leaves the rest untouched. Is there any easy way to fix this?

david said...

Thanks for this, it's a great plugin. The only thing that's not working quite right is that after using show(), the content in the div drops a line, and the element's display is set to "block". Is there any way to get around this?

Thanks again.

you can use
moreContent.css("display","inline");
instead of
moreContent.show("normal");
but there will be no animation

Anonymous said...

Very Nice article. really helpful. This article really helped me to create my first jquery plugin. Many Many thanks to you.


Thanks & Regards
Rahul Anand

abskomol said...

Very nice article. Thankyou jMar

whisher said...

Hi,
Good article the jquery documentation is not very friendly :)
Just a remark
[The first step is to extend the actual jQuery object]
You mean the actual jQuery function
alert(typeof $); // function
jQuery.fn is a shortcut for jQuery.prototype
http://groups.google.com/group/jquery-dev/browse_thread/thread/8a4c4d0f89e328bb
Bye.

Aaron Godin said...

In JavaScript, functions are objects. So in all honesty it's perfectly fine to say "the jQuery object" since, although it's a function, it performs more like an object to the actual user.

helium said...

That is a fantastic tutorial, honestly, thanks alot, making my plugin now!

Lorem Ipsum said...

very happy to watch your tut, because for some days I am try to learn how to build jquery plugins but did not find as organized as this tutorial. Thank you

Drew Noakes said...

Thanks for this. Note the 'copy to clipboard' function didn't work for me in Chrome on Win7 x64.

True Religion said...

Wow..a really fantastic tutorial, honestly, thanks alot, making my plugin now!

Tariq Azam said...

It cannot be described more easily. Very easy to understand and follow. Great tutorial. Keep up the good work mate.

Marco Vuillermoz said...

You are who I like to call a professional!

alex said...

great tutorial jeremy
i already got my plugin up and running
http://alex-web.gr/plugins/jStopIE/

Anonymous said...

easy to understand and well structured.
Great Work thanks!

yipwt said...

Thanks,

Was searching for jQuery plugin tutorial, and yours is presented in an easy to understand manner.

Thumbs up!

Anonymous said...

Thanks a ton for this great bolog :) loved It...going to design new plugins from now ...

Jay Goldberg said...

I'm pretty experienced in jQuery, but have been hesitant to write my own plugin - turns out it's much easier than I though. Excellent Post!

Vivekanand said...

Hi Author,

This is not working when we have number of paragraph tags placed in a div container. Only first instance of paragraph is taking into consideration.

Could you please let me know how we can resolve this one.

Thanks,
Vivek

AnJi said...

Thanks for the tutorial.. very helpful. I never thought writing a plugin in jQuery is this simple :).

Anonymous said...

thanks chachu.

bondy said...

very kind of you, brother. thanks for the vivid tutorial!

Tony Lea said...

Muchos Props. Tutorial was very helpful ;) Thanks

rohijs said...

nice blog. i found it very usefull with jquery plugins.

George.Collins said...

I know this is ancient, but still it's what google took me to...

You don't need to wrap "this" in a jQuery object within the anonymous function - it's already the jQuery object that the function was called on:

http://docs.jquery.com/Plugins/Authoring#Context

George.Collins said...

Doh!

Sorry, that's the first "this" - you are quite correct.

"this" within functions called on .each item do have to be wrapped in $(this)

Anonymous said...

Good Tutorial....
Keep going....

Vincent Catalano said...

Awesome tutorial! Thanks a lot!

Anonymous said...

Just read your post about jQuery plugins and found it very helpful.

Unknown said...

How did you register the .name domain?

Unknown said...

How did you register the .name domain name?

Anonymous said...

That's a great post, I would also introduce some class like prototyping though and remove some of the work out of the main each loop. Here are some guidelines I always follow that I have posted on my site: http://www.websanova.com/tutorials/jquery/10-simple-guidelines-for-writing-jquery-plugins

jonBuckner said...

Blimey,
All that code just to get rid of some text

I thought jquery was 'write less do more'
I'm new to jquery and JavaScript and this makes it
seem really daunting

how would you even begin to create such code?

Yours sincerely
Mr overwhelmed

Anonymous said...

made my life easy.. thanks

Anonymous said...

Hey I've included your kwicks for jquery navigation plugin in
jQuer.in
Search Less,Do More

Abg Isa said...
This comment has been removed by the author.
Abg Isa said...
This comment has been removed by the author.
Abg Isa said...
This comment has been removed by the author.
Anonymous said...

Have you got do it with text 'testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest'
- I tried expander with this text, but can not. Please help find the reason

Anonymous said...

Only words that i could say "Simply Superb!!".

jigolo said...

jQuery site. Looking good, keep up the good work, thanks very good

Chris Callander said...

Brilliant. Many thanks.

Chris Callander said...

Brilliant. Many thanks.

ofis mobilyaları said...

very helpful. two beers extra credit