Upgrade to Pro — share decks privately, control downloads, hide ads and more …

jQuery Plugins: Beginner to Advanced

Doug Neiner
October 28, 2011

jQuery Plugins: Beginner to Advanced

You may think that jQuery plugins are just pieces of code that other developers release and you use. However, jQuery plugins are an incredible way to structure your website and web application code to be as reusable as possible. In this workshop you will learn how to write your first jQuery plugin, how to add more advanced options and functionality to your plugins, how to minimize configuration by writing contextual code, and finally, how to write advanced widgets using the jQuery UI Widget Factory. No prior plugin knowledge is required for this course, but a basic understanding of jQuery is required.

Doug Neiner

October 28, 2011
Tweet

More Decks by Doug Neiner

Other Decks in Programming

Transcript

  1. WRITING JQUERY PLUGINS DOUG NEINER Crystal Ruby, Olivia, Cody Not

    pictured: Ditto the cat Jasper the dog My Family
  2. WRITING JQUERY PLUGINS DOUG NEINER WHAT IS A JQUERY PLUGIN?

    • An awesome library approved by the jQuery team and used by millions? • Code you found useful and decided to release to the public? • Something other people write, and you use?
  3. WRITING JQUERY PLUGINS DOUG NEINER WHAT IS A JQUERY PLUGIN?

    • A jQuery plugin is any reusable piece of JavaScript code that depends on jQuery. • Many jQuery plugins extend $.fn to provide functionality to jQuery result sets. • It is simply another method of code organization. • You should be writing and using your plugins in your projects now!
  4. WRITING JQUERY PLUGINS DOUG NEINER STEP 1: PROTECT THE $

    // Out here, $ may not be equal to jQuery ( function ( $ ) { ! // In here, $ is equal to jQuery }( jQuery )); IIFE: IMMEDIATELY INVOKING FUNCTION EXPRESSION
  5. WRITING JQUERY PLUGINS DOUG NEINER STEP 2: ADD THE PLUGIN

    METHOD ( function ( $ ) { $.fn.myPlugin = function () { }; }( jQuery )); BE SURE TO PICK A UNIQUE NAME TO AVOID CONFLICTS
  6. WRITING JQUERY PLUGINS DOUG NEINER JQUERY MAGIC • In order

    to run this: $( "div.findSomething" ).doSomething(); • This method would be defined: $.fn.doSomething • Its not magic, its the prototype of jQuery • $.fn is just an alias for the prototype
  7. WRITING JQUERY PLUGINS DOUG NEINER STEP 3: RETURN THIS (

    function ( $ ) { $.fn.myPlugin = function () { ! return this.each( function ( i, el ) { ! }); }; }( jQuery )); CHAINING DEPENDS ON YOU HONORING THE SYSTEM
  8. WRITING JQUERY PLUGINS DOUG NEINER MORE MAGIC: CHAINING • this

    is already a jQuery object • End the plugin by returning this to support chaining • 90% of the time, you want to support chaining • $( "#el" ).show().yourPlugin().delay( 900 ).slideUp(); • For the other 10%, there is only one situation where you shouldn't support chaining: • If your plugin method needs to return a value, it cannot chain
  9. WRITING JQUERY PLUGINS DOUG NEINER STEP 3A: ADD CODE (

    function ( $ ) { $.fn.myPlugin = function () { ! return this.each( function ( i, el ) { ! ! // Your code goes here ! ! // this == el, so $( el ) to use jQuery methods ! ! $( el ).addClass( "button" ) ! ! .append( "<span></span>" ); ! }); }; }( jQuery ));
  10. WRITING JQUERY PLUGINS DOUG NEINER WAIT! EACH ISN'T ALWAYS NEEDED

    ( function ( $ ) { $.fn.myPlugin = function () { ! return this.addClass( "button" ) ! ! .append( "<span></span>" ); }; }( jQuery )); IMPLICIT ITERATION IS RESPONSIBLE FOR THIS
  11. WRITING JQUERY PLUGINS DOUG NEINER STEP 3B: ADD MORE CODE

    ( function ( $ ) { $.fn.myPlugin = function () { ! return this.each( function ( i, el ) { ! ! var $el = $( el ); ! ! if ( !$el.hasClass( "button" ) { ! ! ! $el.addClass( "button" ) ! ! ! .append( "<span></span>" ); ! ! } ! }); }; }( jQuery ));
  12. WRITING JQUERY PLUGINS DOUG NEINER STEP 4A: ADDING OPTIONS (

    function ( $ ) { $.fn.myPlugin = function () { ! return this.each( function ( i, el ) { ! ! var $el = $( el ); ! ! if ( !$el.hasClass( "button" ) { ! ! ! $el.addClass( "button" ) ! ! ! .append( "<span></span>" ); ! ! } ! }); }; $.fn.myPlugin.defaults = { ! buttonClass: "button", ! iconMarkup: "<span></span>" }; }( jQuery ));
  13. WRITING JQUERY PLUGINS DOUG NEINER STEP 4B: MERGING OPTIONS (

    function ( $ ) { $.fn.myPlugin = function ( options ) { ! options = $.extend( {}, $.fn.myPlugin.defaults, options ); ! return this.each( function ( i, el ) { ! ! var $el = $( el ); ! ! if ( !$el.hasClass( "button" ) { ! ! ! $el.addClass( "button" ) ! ! ! .append( "<span></span>" ); ! ! } ! }); }; $.fn.myPlugin.defaults = { ! buttonClass: "button", ! iconMarkup: "<span></span>" };
  14. WRITING JQUERY PLUGINS DOUG NEINER STEP 4C: USING OPTIONS (

    function ( $ ) { $.fn.myPlugin = function ( options ) { ! options = $.extend( {}, $.fn.myPlugin.defaults, options ); ! return this.each( function ( i, el ) { ! ! var $el = $( el ); ! ! if ( !$el.hasClass( options.buttonClass ) { ! ! ! $el.addClass( options.buttonClass ) ! ! ! .append( options.iconMarkup ); ! ! } ! }); }; $.fn.myPlugin.defaults = { ! buttonClass: "button", ! iconMarkup: "<span></span>" }; }( jQuery ));
  15. WRITING JQUERY PLUGINS DOUG NEINER BASIC PLUGIN REVIEW 1. Protect

    $ by wrapping the plugin in an IIFE 2. Add your method to $.fn 3. Be sure to return this 4. Add options to further abstract the code
  16. WRITING JQUERY PLUGINS DOUG NEINER WHAT ABOUT $.EXTEND… // Some

    plugins use this form of adding to $.fn $.extend( $.fn, { myPlugin: function () { return this; } }); 1. Good if you plan to add a ton of plugin methods 2. Don't add a ton of plugin methods
  17. WRITING JQUERY PLUGINS DOUG NEINER CRAFTING AN API // Though

    less common, some times adding additional // parameters (in addition to options) is a smart decision $.fn.myPlugin = function ( required, options ) { … }); $.fn.option = function ( key, value ) { … }); .option(); // Returns all the options (Breaks the chain) .option( key ); // Returns just the key (Breaks the chain) .option( key, value ); // Sets the value .option( { "key": val, "key2": val }); // Sets multiple values IN THE END, ITS UP TO YOU: BUT FOLLOWING CONVENTIONS MAKES IT EASIER TO RELEASE LATER
  18. WRITING JQUERY PLUGINS DOUG NEINER WRITE A SIMPLE JQUERY PLUGIN

    • Ideas • Abstract a complex animation • Make a plugin that enhances markup for a form • Make a plugin that checks if a form is valid
  19. WRITING JQUERY PLUGINS DOUG NEINER ( function ( $ )

    { $.fn.myPlugin = function ( options ) { ! options = $.extend( {}, $.fn.myPlugin.defaults, options ); ! ! return this.each( function ( i, el ) { ! ! var $el = $( el ); ! ! if ( !$el.hasClass( options.buttonClass ) { ! ! ! $el.addClass( options.buttonClass ) ! ! ! .append( options.iconMarkup ); ! ! } ! }); }; $.fn.myPlugin.defaults = { ! buttonClass: "button", ! iconMarkup: "<span></span>" }; }( jQuery ));
  20. WRITING JQUERY PLUGINS DOUG NEINER VALUE OF A PLUGIN •

    A plugin is only as powerful as its API, and the options your support. • More options != more power • Too many options can bloat your plugin, so add them carefully and with a lot of thought.
  21. WRITING JQUERY PLUGINS DOUG NEINER TYPES OF OPTIONS • Plain

    value options • Strings and Numbers • DOM Selection options • String selector, DOM object, jQuery Object • Callbacks • Fire after certain events • Rich Callbacks • The plugin depends on the callback for functionality
  22. WRITING JQUERY PLUGINS DOUG NEINER PLAIN VALUE options = {

    animSpeed: 5000, // Defaults to 5 seconds defaultText: "RIA Unleashed is awesome!" } DEFAULT USE IN PLUGIN $( el ).slideDown( options.animSpeed, function () { this.innerHTML = options.defaultText; });
  23. WRITING JQUERY PLUGINS DOUG NEINER DOM SELECTION defaults = {

    listItems: "ul li", listItems: liObj, listItems: $( "ul li" ) }; DEFAULT USE IN PLUGIN var items = options.listItems; if ( items && !items.jquery ) { items = $( items ); }
  24. WRITING JQUERY PLUGINS DOUG NEINER CALLBACKS defaults = { onClick:

    null }; DEFAULT USE IN PLUGIN $( el ).click( function ( e ) { e.preventDefault(); // Do something if ( $.isFunction( options.onClick ) ) { options.onClick.apply( this, arguments ); } });
  25. WRITING JQUERY PLUGINS DOUG NEINER CALLBACKS (ALT) defaults = {

    onClick: $.noop // $.noop == function () { } }; DEFAULT USE IN PLUGIN $( el ).click( function ( e ) { e.preventDefault(); // Do something options.onClick.apply( this, arguments ); });
  26. WRITING JQUERY PLUGINS DOUG NEINER RICH CALLBACKS defaults = {

    renderItem: function ( text, type ) { return "<span class='" + type + "'>" + text + "</span>"; } }; DEFAULT USE IN PLUGIN $.each( keys, function ( key, text ) { var html = options.renderItem( item, key ); // Do something });
  27. WRITING JQUERY PLUGINS DOUG NEINER LIMITATIONS OF BASIC PLUGINS •

    They don't maintain state very well • Very difficult to influence after the plugin has run • They don't tend to be able to be destroyed • They cannot be 'inherited' to adjust function
  28. WRITING JQUERY PLUGINS DOUG NEINER THE WIDGET FACTORY • Part

    of jQuery UI: jquery.ui.widget.js • If you are using jQuery UI, you already can use it • Can be included in your own plugins (only 1.14KB minified and gzipped) for projects not use jQuery UI • Provides a rich API for stateful plugins (widgets) • Provides a unified API – allows users to use your plugin easier
  29. WRITING JQUERY PLUGINS DOUG NEINER DEFINING A WIDGET $.widget( "namespace.pluginName",

    { options: { key: "value" }, … methods go here … });
  30. WRITING JQUERY PLUGINS DOUG NEINER WHAT WE GET FOR FREE

    // Our widget object: $.namespace.pluginName; // A jQuery plugin for creating/interacting with our widget $.fn.pluginName; // A custom selector (Though use sparingly) $( ":namespace-pluginName" );
  31. WRITING JQUERY PLUGINS DOUG NEINER THE WIDGET API // First

    call, with options, creates the widget $( "div" ).pluginName( { key: "value" } ); // Subsequent calls modify or call methods on the widget // Set an option $( "div" ).pluginName( "option", "key", "newValue" ); // Get an option $( "div" ).pluginName( "option", "key" ); // Run a method $( "div" ).pluginName( "myMethod", "parameter1" ); // Destroy the widget $( "div" ).pluginName( "destroy" );
  32. WRITING JQUERY PLUGINS DOUG NEINER BASIC LIFE CYCLE • _create()

    • _init() • _setOptions & _setOption called as options are changed • destroy() Called directly or when element is removed
  33. WRITING JQUERY PLUGINS DOUG NEINER SPECIAL PROPERTIES • this.element the

    jQuery wrapped DOM element the widget was created on. • this.options Allows you to quickly access the options on the widget • this.widgetName The "pluginName" portion of your widget • this.widgetEventPrefix Also the "pluginName" portion of your widget • this.widgetBaseClass "namespace-pluginName" - just like the declaration but with a dash instead of a dot.
  34. WRITING JQUERY PLUGINS DOUG NEINER SETUP AND TEARDOWN $.widget( "namespace.pluginName",

    { options: { key: "value" }, // No "super" version of this worth calling _create: function () { this.element.addClass( this.widgetBaseClass ); }, … methods go here … destroy: function () { this.element.removeClass( this.widgetBaseClass ); $.Widget.prototype.destroy.apply( this, arguments ); } });
  35. WRITING JQUERY PLUGINS DOUG NEINER CALLING "SUPER" // In jQuery

    UI 1.8.x, this is how you call a "super" method methodName: function () { $.Widget.prototype.methodName.apply( this, arguments ); }
  36. WRITING JQUERY PLUGINS DOUG NEINER OPTIONS $( "div" ).pluginName( "option",

    hash OR key, value ); EVERY OPTION SHOULD BE CHANGEABLE AT RUN TIME _setOptions: function ( values ) { $.Widget.prototype._setOptions.apply( this, arguments ); // Do something once after options are set }, _setOption: function ( key, value ) { $.Widget.prototype._setOption.apply( this, arguments ); if ( key === "visible" ) { // Do something specific } }
  37. WRITING JQUERY PLUGINS DOUG NEINER PUBLIC AND "PRIVATE" METHODS •

    Any method starting with an `_` underscore, cannot be called using the .pluginName( "method") syntax • Methods without an underscore can be called using that syntax
  38. WRITING JQUERY PLUGINS DOUG NEINER EVENT BINDING this.element.bind( "click." +

    this.widgetName, function () { // Do something }); this.element.delegate( "ul li", "click." + this.widgetName, function () { // Do something }); this.element.bind( "click." + this.widgetName, function () { // Do something });
  39. WRITING JQUERY PLUGINS DOUG NEINER 50% complete Submit Question text

    here Yes No Question text here Yes No Question text here Yes No Question text here Yes No Question text here Yes No Question text here Yes No Question text here Yes No Question text here Yes No
  40. WRITING JQUERY PLUGINS DOUG NEINER $.widget( "namespace.pluginName", { options: {

    key: "value" }, // No "super" version of this worth calling _create: function () { this.element.addClass( this.widgetBaseClass ); }, … methods go here … destroy: function () { this.element.removeClass( this.widgetBaseClass ); $.Widget.prototype.destroy.apply( this, arguments ); } });