In the last article I talked about MVC and doing some nifty Ajax functionalities with jQuery. In this article I will go over jQuery plugins, what they are and how to create them.

jQuery Plugins

jQuery has a plugin architecture which allows you to package up commonly used functions into a plugin. Chances are if you have a complex JavaScript function, someone has more than likely written a plugin to handle that particular functionality. The jQuery.com site has an extensive plugin library and it can sometimes be fun to browse through it to see what people have come up with.

Plugins are fairly easy to write, once you have gotten the basics of jQuery down. Here is a tooltip plugin that I wrote in just a few minutes.

   1: (function ($) {



   2:     $.fn.tooltip = function (options) { // make sure to name the function



   3:                                         // the same as your tooltip



   4:         var methods = {



   5:             



   6:             //initialize stuff



   7:             init: function (options) { },



   8:             



   9:             //destroy and clean up



  10:             destroy: function () {



  11:                 return this.each(function () {



  12:                     $(window).unbind("tooltip");



  13:                 })



  14:             }



  15:         };



  16:  



  17:         // default settings if they aren't passed in



  18:         var settings = {



  19:             'backgroundColor': 'red',



  20:             'color': 'blue',



  21:             'toolTipText': 'Hi',



  22:             'fontWeight': 'bold'



  23:         };



  24:  



  25:         // add the settings into the options



  26:         return this.each(function () {



  27:             if (options) {



  28:                 $.extend(settings, options);



  29:             }



  30:  



  31:             var $this = $(this);



  32:             $this.mouseenter(function (event) {



  33:                 $this.css("color", settings.colorEnter);



  34:                 



  35:                 // if the div#toolTip isn't in the DOM, create a new one



  36:                 if (!$("#toolTip").length) {



  37:                     // create the element



  38:                     $('
'
)



  39:                         // set the text to passed option



  40:                         .html(settings.toolTipText)



  41:                         // from the style sheet



  42:                         .addClass("toolTip")



  43:                         // insert the div into the DOM just after $this



  44:                         .insertAfter($this)



  45:                         // position the div



  46:                         .css({ "left": $this.width(),



  47:                         // set the backgroundColor



  48:                         "backgroundColor": settings.backgroundColor,



  49:                         // set the font



  50:                         "fontWeight": settings.fontWeight,



  51:                         // set the color



  52:                         "color": settings.color



  53:                     }); 



  54:                 }



  55:                 $("#toolTip").fadeIn(500);



  56:             });



  57:  



  58:             $this.mouseleave(function () {



  59:                 $this.css("color", settings.colorLeave);



  60:                 $("#toolTip").fadeOut(500);



  61:             });



  62:         });



  63:     };



  64: })(jQuery);




It's not a pretty thing, or even that functional, but it does show off how fast you can write a plugin. Let's take a look at how this plugin is implemented.



1. In the tag of your page include the references to your jQuery and JavaScript files.





   1: <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript">



   2: <script src="Scripts/jquery.tooltip.js" type="text/javascript">



   3: <script src="Scripts/AppScripts.js" type="text/javascript">




2. Somewhere on your page add an element that will call the plugin





   1: <div class="test">This is the element that will have the assignment</div>




3. In your custom JavaScript, attach the plugin to the element and pass in any options you need to.





   1: $(document).ready(function () {



   2:     $("div.test").tooltip({ "toolTipText": "Hello from ComponentOne", 



   3:         "color":"white" })



   4:         .click(function () { alert("hi"); });



   5: });




4. Add the following to your style sheet to style up the test div.





   1: .test{width:200px;



   2:    float:left;background:silver;



   3:    color:White;border:1px solid White;



   4:    cursor:pointer;padding:5px}




5. Open the page in a browser, then hover over the test div. If all goes well, you should see the following.



image



image



Obviously this isn't the world's greatest plugin, but does cover the basics of getting started. Information on building more functional plugins can be found at http://docs.jquery.com/Plugins/Authoring



TableSorter, a more functional plugin



Since we are working with tabular data in this application, I want to use a plugin that will modify an HTML table and make it sortable. Searching through the plugins library I found "TableSorter" at http://tablesorter.com. It is written by Christian Bach at www.lovepeacenukes.com and does a great job of providing a pretty nifty data grid from a static HTML Table.



Let's take a look.



image



In the head tag of the HTML file place a reference to the TableSorter plugin right after the reference to the jQuery file.



image



In the View in which you want to show the table, write your code to render a table with the data you want to show. One thing about the TableSorter plugin is that it requires valid HTML tables complete with and tags. The following markup is written with the new MVC 3 Razor View Engine.





   1: <table id="studentTable" class="studentTable {sortlist: [[6,0]]}">



   2:     // sortlist is a function of the plugin which automatically sorts



   3:     // on a specific column



   4:     <thead>



   5:     <tr>            



   6:         <th>First Name</th>



   7:         <th>Last Name</th>



   8:         <th>Email</th>



   9:         <th class="{sorter: false}">Comments</th> 



  10:         // sorter class is a plugin option



  11:         <th>Submit Date</th>



  12:         <th>Approved Date</th>



  13:         <th>Approved</th>



  14:     </tr>



  15:     </thead>



  16:     <tbody>    



  17:     @foreach (var item in Model)



  18:     {        



  19:         var approvedDate = string.Empty;



  20:         if (item.ApprovedDate.HasValue) { 



  21:             approvedDate = item.ApprovedDate.Value.ToShortDateString(); 



  22:         }



  23:           <tr>               



  24:             <td>@item.FirstName</td>



  25:             <td>@item.LastName</td>



  26:             <td>@item.Email</td>



  27:             <td>@item.Comments</td>



  28:             <td>@item.SubmitDate.ToShortDateString()</td>



  29:             <td>@approvedDate</td>



  30:             <td>



  31:               <span style="display:none" class="hiddenSpan">@item.Approved</span>



  32:               @Html.Hidden("Approved", item.Approved)



  33:               @Html.Hidden("studentId", item.Id)



  34:               @{var chk = "chkGraphic chkUnChecked";}



  35:               @if (item.Approved.HasValue && item.Approved.Value.Equals(true))



  36:               {



  37:                   chk = "chkGraphic chkChecked";



  38:               }



  39:               <div class="@chk"></div>



  40:               <img src="../../Content/Images/ajax-loader.gif" 



  41:               class="ajaxLoader ajaxLoaderSmall" />



  42:             </td>



  43:         </tr>



  44:     }    



  45:     </tbody>



  46: </table>




Since we are rendering a table, we can use the $(document).ready(function(){});



Add the following in your custom JavaScript file:





   1: /// 



   2:  



   3: $(document).ready(function () {



   4:     $("#studentTable").tablesorter({ widgets: ['zebra'] });



   5:     // zebra is a "widget" included in the plugin which will alternate



   6:     // the row colors of the table



   7: });




Run the page and sort the columns. One thing to note in the markup is in the last column. The plugin sorts on the data contained in the columns of each row. Since I want to sort on "Approved", I add a hidden field with that data as the first element in the cell.



image



image



The TableSorter plugin has many more options than this brief demo show. If you want to explore it more, download it at http://tablesorter.com.



A Freebie



If you look at lines 30 - 42 in the markup you may be wondering what all the other stuff is, including the

. I wanted to spiff up the form and use graphics for the checkboxes, but still keep the functionality of a checkbox. Here is how to do it.



1. In the style sheet add the following classes.





   1: .chkGraphic{cursor:pointer;width:22px;height:22px;float:left;margin-right:5px}



   2: .chkChecked{background:url(Images/checkBoxOn.png)no-repeat}



   3: .chkUnChecked{background:url(Images/checkBoxOff.png)no-repeat}




2. In your custom JavaScript file, add the following functions.





   1: $("div.chkGraphic").live("click", function () { toggleGraphicCheckBox(this); });



   2:  



   3: function toggleGraphicCheckBox(elem) {



   4:     var $elem = $(elem);



   5:     $elem.siblings("img.ajaxLoader").show();



   6:     var valueField = $elem.siblings("input[type=hidden][name=Approved]");



   7:     if ($elem.hasClass("chkChecked")) {



   8:         $elem.removeClass("chkChecked").addClass("chkUnChecked");



   9:         valueField.val("False");



  10:     } else {



  11:         $elem.removeClass("chkUnChecked").addClass("chkChecked");



  12:         valueField.val("True");



  13:     }



  14:     $("span.hiddenSpan").html(valueField.val());



  15:     toggleStudentApproval($elem);



  16: }



  17:  



  18: function toggleStudentApproval(elem) {    



  19:     var approved = elem.siblings("input[type=hidden][name=Approved]").val();



  20:     var studentId = elem.siblings("input[type=hidden][name=studentId]").val();



  21:     $.ajax({



  22:         url: "/Home/GetStudent/"   studentId   "/"   approved,



  23:         type: "GET",



  24:         success: function (result) {



  25:             showStudentApproval(result, elem);



  26:         }



  27:     });



  28: }



  29:  



  30: function showStudentApproval(result, elem) {    



  31:     var id = result.Id;



  32:     var td = elem.parent("td").prev("td");



  33:     td.html("");



  34:     if (result.ApprovedDate != null)



  35:         td.html(result.ApprovedDate);



  36:     elem.siblings("img.ajaxLoader").fadeOut(500);



  37: }




Here's the markup again.





   30: <td>



   32:  <span style="display:none" class="hiddenSpan">@item.Approved</span>



   33:  @Html.Hidden("Approved", item.Approved)



   34:  @Html.Hidden("studentId", item.Id)



   35:  @{var chk = "chkGraphic chkUnChecked";}



   36:  @if (item.Approved.HasValue && item.Approved.Value.Equals(true))



   37:  {



   38:     chk = "chkGraphic chkChecked";



   39:  }



  40:  <div class="@chk"></div>



  41:  <img src="../../Content/Images/ajax-loader.gif" 



  42:        class="ajaxLoader ajaxLoaderSmall" />



  43: </td>




Now based on what you've read so far in this and the previous articles, take a look at all the code and see if you can figure out what will happen when the graphical checkbox is clicked. Add a comment to this article and let me know what you think it will do.



Just for grins and giggles, I converted the JavaScript above to a plugin, jquery.graphicCheckBox.js





   1: (function ($) {



   2:     $.fn.graphicCheckBox = function (options) {



   3:     var methods = {



   4:         // initialize stuff



   5:         init: function (options) { },



   6:         //destroy and clean up



   7:         destroy: function () {



   8:             return this.each(function () {



   9:                 $(window).undbind("graphicCheckBox");



  10:             })



  11:         }



  12:     };



  13:     // default settings if they aren't passed in



  14:     var settings = {



  15:         'checked': 'chkChecked',



  16:         'unchecked': 'chkUnChecked',



  17:         'urlToAction': '/Home/GetStudent/'



  18:     };



  19:         // add the settings into the options



  20:     return this.each(function () {



  21:         if (options) {



  22:             $.extend(settings, options);



  23:         }



  24:  



  25:         var $this = $(this);



  26:         $this.click(function (event) {



  27:             $this.siblings("img.ajaxLoader").show();



  28:             var valueField = $this.siblings("input[type=hidden][name=Approved]");



  29:             if ($this.hasClass(settings.checked)) {



  30:                 $this.removeClass(settings.checked).addClass(settings.unchecked);



  31:                 valueField.val("False");



  32:             } else {



  33:                 $this.removeClass(settings.unchecked).addClass(settings.checked);



  34:                 valueField.val("True");



  35:             }



  36:             $("span.hiddenSpan").html(valueField.val());



  37:             toggleApproval($this);



  38:         });



  39:     });



  40:     function toggleApproval(elem) {



  41:         var approved = elem.siblings("input[type=hidden][name=Approved]").val();



  42:         var id = elem.siblings("input[type=hidden][name=studentId]").val();



  43:         $.ajax({



  44:             url: settings.urlToAction   id   "/"   approved,



  45:             type: "GET",



  46:             success: function (result) {



  47:                 showApproval(result, elem);



  48:             }



  49:         });



  50:     }



  51:     function showApproval (result, elem) {



  52:         var id = result.Id;



  53:         var hid = elem.siblings("input[type=hidden][name=studentId]").val();



  54:         var td = elem.parent("td").prev("td");



  55:         td.html("");



  56:         if (result.ApprovedDate != null)



  57:             td.html(result.ApprovedDate);



  58:         elem.siblings("img.ajaxLoader").fadeOut(500);



  59:     }



  60: }



  61: })(jQuery);




In this article we talked about extending jQuery with plugins, how to write a simple plugin, and explored a fully functional table sorter plugin. I even threw in a groovy freebie for you.



Happy Programming,



James