jQuery - Plugin Development - Using Widget

jquery
jquery-plugin-development

Important:
http://www.tutorialspoint.com/jqueryui/jqueryui_widgetfactory.htm - done reading
https://code.tutsplus.com/tutorials/making-use-of-jquery-uis-widget-factory--net-29606 - done reading

https://api.jqueryui.com/jquery.widget/ - done reading
http://learn.jquery.com/jquery-ui/widget-factory/ - done reading
http://learn.jquery.com/jquery-ui/how-jquery-ui-works/ - done reading
https://learn.jquery.com/jquery-ui/widget-factory/how-to-use-the-widget-factory/ - done reading
https://learn.jquery.com/jquery-ui/widget-factory/widget-method-invocation/ - done reading
http://ajpiano.com/widgetfactory/#slide1 - done reading
http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/ - done reading

Books:
http://www.manning.com/vantoll/
https://www.packtpub.com/web-development/jquery-ui-themes-beginners-guide
https://www.packtpub.com/web-development/jquery-ui-cookbook

What are the advantages of using $.widget()?

While most existing jQuery plugins are stateless – that is, we call them on an element and that is the extent of our interaction with the plugin – there's a large set of functionality that doesn't fit into the basic plugin pattern. In order to fill this gap, jQuery UI has implemented a more advanced plugin system. The new system:

  1. can manages state
  2. allows multiple functions to be exposed via a single plugin
  3. provides various extension points.
  4. Creates your namespace
  5. Encapsulated class (jQuery.aj.filterable.prototype)
  6. Extends jQuery prototype (jQuery.fn.filterable)
  7. Merges defaults with user-supplied options
  8. Stores plugin instance in .data()
  9. Methods accessible via string - plugin( "foo" ) - or directly - .foo()
  10. Prevents against multiple instantiation
  11. Evented structure for handling setup, teardown, option changes
  12. Easily expose callbacks: ._trigger( "event" )
  13. Free pseudoselector! $( ":aj-filterable" )
  14. Inheritance! Widgets can extend from other widgets

This system is called the Widget Factory and is exposed as jQuery.widget as part of jQuery UI 1.8; however, it can be used independently of jQuery UI.

Can we use $.widget() independently of jQuery UI?

Yes. jQuery.widget as part of jQuery UI 1.8; however, it can be used independently of jQuery UI. https://learn.jquery.com/plugins/stateful-plugins-with-widget-factory/

How can we create a simple plugin using $.widget()?

(function($){
  $.widget( "nmk.progressbar", {
    _create: function() {
        var progress = this.options.value + "%";
        this.element.addClass( "progressbar" ).text( progress );
    }
 });
})(jQuery);

The name of the plugin must contain a namespace; in this case we've used the nmk namespace. There is a limitation that namespaces be exactly one level deep – that is, we can't use a namespace like nmk.foo.

The Widget Factory has provided two properties for us:

  1. this.element is a jQuery object containing exactly one element. If our plugin is called on a jQuery object containing multiple elements, a separate plugin instance will be created for each element, and each instance will have its own this.element.
  2. this.options is a hash containing key/value pairs for all of our plugin's options.

How can we initialize the widget?

In order to track the state of the widget, we must introduce a full life cycle for the widget. The life cycle starts when the widget is initialized. To initialize a widget, we simply call the plugin on one or more elements.

$( "#elem" ).progressbar();

This will initialize each element in the jQuery object, in this case the element with an id of "elem". Because progressbar() was called with no parameters, the widget was initialized with its default options. We can pass a set of options during initialization to override the defaults:

$( "#elem" ).progressbar({ value: 20 });

How can we pass options to our widgets?

$( "<div />" ).appendTo( "body" ).progressbar({ value: 20 });

How can we specify default options for our widget?

$.widget( "nmk.progressbar", {

    // Default options.
    options: {
        value: 0
    },

    _create: function() {
        var progress = this.options.value + "%";
        this.element.addClass( "progressbar" ).text( progress );
    }

});

How many options can we pass to our widget during initialization?

We can pass as many or as few options as we want during initialization. Any options that we don't pass will just use their default values. You can pass multiple options arguments. Those arguments will be merged into one object (similar to $.extend( true, target, object1, objectN )). This is useful for sharing options between instances, while overriding some properties for each one:

var options = { modal: true, show: "slow" };
$( "#dialog1" ).dialog( options );
$( "#dialog2" ).dialog( options, { autoOpen: false });

All options passed on init are deep-copied to ensure the objects can be modified later without affecting the widget. Arrays are the only exception, they are referenced as-is. This exception is in place to support data-binding, where the data source has to be kept as a reference.

The default values are stored on the widget's prototype, therefore we have the ability to override the values that jQuery UI sets. For example, after setting the following, all future progressbar instances will default to a value of 80:

$.ui.progressbar.prototype.options.value = 80;

The options are part of the widget's state, so we can set options after initialization as well.

Are options handled separately from states?

No. The options are part of the widget's state, so we can set options after initialization as well.

How can we add methods to our widgets?

Now that we can initialize our progress bar, we'll add the ability to perform actions by calling methods on our plugin instance. To define a plugin method, we just include the function in the object literal that we pass to jQuery.widget. We can also define "private" methods by prepending an underscore to the function name.

$.widget( "nmk.progressbar", {
    options: {
        value: 0
    },

    _create: function() {
        var progress = this.options.value + "%";
        this.element.addClass("progressbar").text( progress );
    },

    // Create a public method.
    value: function( value ) {

        // No value passed, act as a getter.
        if ( value === undefined ) {

            return this.options.value;

        // Value passed, act as a setter.
        } else {

            this.options.value = this._constrain( value );
            var progress = this.options.value + "%";
            this.element.text( progress );

        }

    },

    // Create a private method.
    _constrain: function( value ) {

        if ( value > 100 ) {
            value = 100;
        }

        if ( value < 0 ) {
            value = 0;
        }

        return value;
    }

});

How can we call a method on a plugin instance?

Now that the widget is initialized, we can query its state or perform actions on the widget. All actions after initialization take the form of a method call. To call a method on a widget, we pass the name of the method to the jQuery plugin. For example, to call the value() method on our progressbar widget, we would use:

$( "#elem" ).progressbar( "value" );

If the method accepts parameters, we can pass them after the method name. For example, to pass the parameter 40 to the value() method, we can use:

$( "#elem" ).progressbar( "value", 40 );

To call a method on a plugin instance, you pass the name of the method to the jQuery plugin. If you are calling a method that accepts parameters, you simply pass those parameters after the method name.

var bar = $( "<div />" ).appendTo( "body").progressbar({ value: 20 });

// Get the current value.
alert( bar.progressbar( "value" ) );

// Update the value.
bar.progressbar( "value", 50 );

// Get the current value again.
alert( bar.progressbar( "value" ) );

Executing methods by passing the method name to the same jQuery function that was used to initialize the plugin may seem odd. This is done to prevent pollution of the jQuery namespace while maintaining the ability to chain method calls.

What is the purpose of this.element inside a jQuery plugin created using $.widget()?

this.element is a jQuery object containing exactly one element. If our plugin is called on a jQuery object containing multiple elements, a separate plugin instance will be created for each element, and each instance will have its own this.element.

What happens when our plugin (created using $.widget()) is invoked on a collection matching multiple elements?

The this.element property inside a jQuery plugin created using $.widget() is a jQuery object containing exactly one element. If our plugin is called on a jQuery object containing multiple elements, a separate plugin instance will be created for each element, and each instance will have its own this.element.

What is the purpose of this.options inside a jQuery plugin created using $.widget()?

this.options is a hash containing key/value pairs for all of our plugin's options.

How is a jQuery plugin created with jQuery.widget different from a standard jQuery plugin?

The new system manages state, allows multiple functions to be exposed via a single plugin, and provides various extension points. This system is called the Widget Factory and is exposed as jQuery.widget as part of jQuery UI 1.8; however, it can be used independently of jQuery UI. When our plugin gets called, it will create a new plugin instance and all functions will be executed within the context of that instance. This is different from a standard jQuery plugin in two important ways. First, the context is an object, not a DOM element. Second, the context is always a single object, never a collection.

$.widget( "nmk.progressbar", {

    _create: function() {
        var progress = this.options.value + "%";
        this.element.addClass( "progressbar" ).text( progress );
    }

});

What is the limitation on the name of the plugin specified when using $.widget() to create a plugin?

The name of the plugin must contain a namespace. There is a limitation that namespaces be exactly one level deep – that is, we can't use a namespace like nmk.foo.

What are the two properties that $.widget() provides to our plugin?

Widget Factory has provided two properties for us:

  1. this.element is a jQuery object containing exactly one element. If our plugin is called on a jQuery object containing multiple elements, a separate plugin instance will be created for each element, and each instance will have its own this.element.
  2. this.options is a hash containing key/value pairs for all of our plugin's options.

Should we use the ui namespace when creating a plugin using $.widget()?

No, we should not be using the ui namespace. The ui namespace is reserved for official jQuery UI plugins. When building your own plugins, you should create your own namespace. This makes it clear where the plugin came from and whether it is part of a larger collection.

What happens when we call jQuery.widget to create our plugin?

When we call jQuery.widget it extends jQuery by adding a method to jQuery.fn (the same way we'd create a standard plugin). The name of the function it adds is based on the name you pass to jQuery.widget, without the namespace; in our case it will create $.fn.progressbar. We do not define the method that is added under $.fn.progressbar. jQuery Widget automatically provides this method, and this method probably use closure and has logic to create a separate plugin instance for each matched elements.

The options passed to our plugin get set in this.options inside of our plugin instance.

When you call jQuery.widget, it creates a constructor function for your plugin and sets the object literal that you pass in as the prototype for your plugin instances. All of the functionality that automatically gets added to your plugin comes from a base widget prototype, which is defined as jQuery.Widget.prototype. When a plugin instance is created, it is stored on the original DOM element using jQuery.data, with the plugin's full name (the plugin's namespace, plus a hyphen, plus the plugin's name) as the key. For example the jQuery UI dialog widget uses a key of "ui-dialog".

Because the plugin instance is directly linked to the DOM element, you can access the plugin instance directly instead of going through the exposed plugin method if you want. This will allow you to call methods directly on the plugin instance instead of passing method names as strings and will also give you direct access to the plugin's properties.

var bar = $( "<div />")
    .appendTo( "body" )
    .progressbar()
    .data( "nmk-progressbar" );

// Call a method directly on the plugin instance.
bar.option( "value", 50 );

// Access properties on the plugin instance.
alert( bar.options.value );

How does $.widget help with allowing other developers to extend our plugin?

One of the biggest benefits of having a constructor and prototype for a plugin is the ease of extending the plugin. By adding or modifying methods on the plugin's prototype, we can modify the behavior of all instances of our plugin. For example, if we wanted to add a method to our progress bar to reset the progress to 0% we could add this method to the prototype and it would instantly be available to be called on any plugin instance.

$.nmk.progressbar.prototype.reset = function() {
    this._setOption( "value", 0 );
};

In other words, other developers would be able to add new methods, and overwrite our existing methods.

Why does jQuery.widget make the the option method automatically available to us?

It just does, perhaps so that we can change the options. One of the methods that is automatically available to our plugin is the option method. The option method allows you to get and set options after initialization. This method works exactly like jQuery's .css() and .attr() methods: you can pass just a name to use it as a getter, a name and value to use it as a single setter, or a hash of name/value pairs to set multiple values. When used as a getter, the plugin will return the current value of the option that corresponds to the name that was passed in. When used as a setter, the plugin's _setOption method will be called for each option that is being set. We can specify a _setOption method in our plugin to react to option changes.

How can our plugin react when an option is changed?

We can specify a _setOption method in our plugin to react to option changes.

$.widget( "nmk.progressbar", {

    options: {
        value: 0
    },

    _create: function() {
        this.element.addClass( "progressbar" );
        this._update();
    },

    _setOption: function( key, value ) {
        this.options[ key ] = value;
        this._update();
    },

    _update: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
    }

});

How can we add callbacks to our widget?

One of the easiest ways to make your plugin extensible is to add callbacks so users can react when the state of your plugin changes.

$.widget( "nmk.progressbar", {

    options: {
        value: 0
    },

    _create: function() {
        this.element.addClass( "progressbar" );
        this._update();
    },

    _setOption: function( key, value ) {
        this.options[ key ] = value;
        this._update();
    },

    _update: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
        if ( this.options.value == 100 ) {
            this._trigger( "complete", null, { value: 100 } );
        }
    }

});

In the above code, we add a callback to our progress bar to signify when the progress has reached 100%. The _trigger method takes three parameters:

  1. the name of the callback
  2. a native event object that initiated the callback
  3. a hash of data relevant to the event.

The callback name is the only required parameter, but the others can be very useful for users who want to implement custom functionality on top of your plugin. For example, if we were building a draggable plugin, we could pass the native mousemove event when triggering a drag callback; this would allow users to react to the drag based on the x/y coordinates provided by the event object.

Callback functions are essentially just additional options, so you can get and set them just like any other option. Whenever a callback is executed, a corresponding event is triggered as well. The event type is determined by concatenating the plugin name and the callback name. The callback and event both receive the same two parameters: an event object and a hash of data relevant to the event, as we'll see below.

var bar = $( "<div />" ).appendTo( "body" ).progressbar({

    complete: function( event, data ) {
        alert( "Callbacks are great!" );
    }

}).bind( "progressbarcomplete", function( event, data ) {

     alert( "Events bubble and support many handlers for extreme flexibility." );

     alert( "The progress bar value is " + data.value );

});

bar.progressbar( "option", "value", 100 );

All widgets have events associated with their various behaviors to notify you when the state is changing. For most widgets, when the events are triggered, the names are prefixed with the widget name and lowercased. For example, we can bind to progressbar's change event which is triggered whenever the value changes.

$( "#elem" ).bind( "progressbarchange", function() {
  alert( "The value has changed!" );
});

Each event has a corresponding callback, which is exposed as an option. We can hook into progressbar's change callback instead of binding to the progressbarchange event, if we want to.

$( "#elem" ).progressbar({
  change: function() {
    alert( "The value has changed!" );
  }
});

All widgets have a create event which is triggered upon instantiation.

How can we implement a cancellable callback?

If your plugin has functionality that you want to allow the user to prevent, the best way to support this is by creating cancelable callbacks. Users can cancel a callback, or its associated event, the same way they cancel any native event: by calling event.preventDefault() or using return false. If the user cancels the callback, the _trigger method will return false so you can implement the appropriate functionality within your plugin.

var bar = $( "<div />" ).appendTo( "body" ).progressbar({

    complete: function( event, data ) {
        alert( "Callbacks are great!" );
    }

}).bind( "progressbarcomplete", function( event, data ) {

     alert( "Events bubble and support many handlers for extreme flexibility." );

     alert( "The progress bar value is " + data.value );

});

bar.progressbar( "option", "value", 100 );

How can we allow the users to clean up?

In some cases, it will make sense to allow users to apply and then later unapply your plugin. You can accomplish this via the _destroy method. Within the _destroy method, you should undo anything your plugin may have done during initialization or later use. The _destroy method is automatically called if the element that your plugin instance is tied to is removed from the DOM, so this can be used for garbage collection as well. The base destroy method calls _destroy on the plugin instance.

$.widget( "nmk.progressbar", {

    options: {
        value: 0
    },

    _create: function() {
        this.element.addClass("progressbar");
        this._update();
    },

    _setOption: function( key, value ) {
        this.options[ key ] = value;
        this._update();
    },

    _update: function() {
        var progress = this.options.value + "%";
        this.element.text( progress );
        if ( this.options.value === 100 ) {
            this._trigger( "complete", null, { value: 100 } );
        }
    },

    _destroy: function() {
        this.element
            .removeClass( "progressbar" )
            .text( "" );
    }

});

Code examples:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>jQuery UI Widget - Default functionality</title>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <link rel="stylesheet" href="/resources/demos/style.css">
  <style>
  .custom-colorize {
    font-size: 20px;
    position: relative;
    width: 75px;
    height: 75px;
  }
  .custom-colorize-changer {
    font-size: 10px;
    position: absolute;
    right: 0;
    bottom: 0;
  }
  </style>
  <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script>
  $( function() {
    // the widget definition, where "custom" is the namespace,
    // "colorize" the widget name
    $.widget( "custom.colorize", {
      // default options
      options: {
        red: 255,
        green: 0,
        blue: 0,

        // Callbacks
        change: null,
        random: null
      },

      // The constructor
      _create: function() {
        this.element
          // add a class for theming
          .addClass( "custom-colorize" );

        this.changer = $( "<button>", {
          text: "change",
          "class": "custom-colorize-changer"
        })
        .appendTo( this.element )
        .button();

        // Bind click events on the changer button to the random method
        this._on( this.changer, {
          // _on won't call random when widget is disabled
          click: "random"
        });
        this._refresh();
      },

      // Called when created, and later when changing options
      _refresh: function() {
        this.element.css( "background-color", "rgb(" +
          this.options.red +"," +
          this.options.green + "," +
          this.options.blue + ")"
        );

        // Trigger a callback/event
        this._trigger( "change" );
      },

      // A public method to change the color to a random value
      // can be called directly via .colorize( "random" )
      random: function( event ) {
        var colors = {
          red: Math.floor( Math.random() * 256 ),
          green: Math.floor( Math.random() * 256 ),
          blue: Math.floor( Math.random() * 256 )
        };

        // Trigger an event, check if it's canceled
        if ( this._trigger( "random", event, colors ) !== false ) {
          this.option( colors );
        }
      },

      // Events bound via _on are removed automatically
      // revert other modifications here
      _destroy: function() {
        // remove generated elements
        this.changer.remove();

        this.element
          .removeClass( "custom-colorize" )
          .enableSelection()
          .css( "background-color", "transparent" );
      },

      // _setOptions is called with a hash of all options that are changing
      // always refresh when changing options
      _setOptions: function() {
        // _super and _superApply handle keeping the right this-context
        this._superApply( arguments );
        this._refresh();
      },

      // _setOption is called for each individual option that is changing
      _setOption: function( key, value ) {
        // prevent invalid color values
        if ( /red|green|blue/.test(key) && (value < 0 || value > 255) ) {
          return;
        }
        this._super( key, value );
      }
    });

    // Initialize with default options
    $( "#my-widget1" ).colorize();

    // Initialize with two customized options
    $( "#my-widget2" ).colorize({
      red: 60,
      blue: 60
    });

    // Initialize with custom green value
    // and a random callback to allow only colors with enough green
    $( "#my-widget3" ).colorize( {
      green: 128,
      random: function( event, ui ) {
        return ui.green > 128;
      }
    });

    // Click to toggle enabled/disabled
    $( "#disable" ).on( "click", function() {
      // use the custom selector created for each widget to find all instances
      // all instances are toggled together, so we can check the state from the first
      if ( $( ":custom-colorize" ).colorize( "option", "disabled" ) ) {
        $( ":custom-colorize" ).colorize( "enable" );
      } else {
        $( ":custom-colorize" ).colorize( "disable" );
      }
    });

    // Click to set options after initialization
    $( "#green" ).on( "click", function() {
      $( ":custom-colorize" ).colorize( "option", {
        red: 64,
        green: 250,
        blue: 8
      });
    });
  } );
  </script>
</head>
<body>

<div>
  <div id="my-widget1">color me</div>
  <div id="my-widget2">color me</div>
  <div id="my-widget3">color me</div>
  <button id="disable">Toggle disabled option</button>
  <button id="green">Go green</button>
</div>

</body>
</html>

The above code example is from: https://jqueryui.com/widget/

What is the signature of $.widget() utility method?

$.widget( name [, base ], prototype )
  1. name: (String) The name of the widget to create, including the namespace.
  2. base: (Function) The base widget to inherit from. This must be a constructor that can be instantiated with the `new` keyword. Defaults to jQuery.Widget.
  3. prototype: The object to use as a prototype for the widget.

Can we create a widget the inherit from another widget?

Yes. You can create new widgets from scratch, using just the $.Widget object as a base to inherit from, or you can explicitly inherit from existing jQuery UI or third-party widgets. Defining a widget with the same name as you inherit from even allows you to extend widgets in place.

Can we define a widget with the same name as another existing widget?

Yes. Defining a widget with the same name as you inherit from even allows you to extend widgets in place.

How can we retrieve the widget instance from the DOM element after initialization?

The widget's instance can be retrieved from a given element using the instance() method.

$( "#elem" ).progressbar( "instance" );

If the instance() method is called on an element that is not associated with the widget, undefined is returned. The instance is stored using jQuery.data() with the widget's full name as the key. Therefore, the :data selector can also determine whether an element has a given widget bound to it.

$( "#elem" ).is( ":data('ui-progressbar')" ); // true
$( "#elem" ).is( ":data('ui-draggable')" ); // false

Unlike instance(), :data can be used even if the widget being tested for has not loaded.

$( "#elem" ).nonExistentWidget( "instance" ); // TypeError
$( "#elem" ).is( ":data('ui-nonExistentWidget')" ); // false

Under the hoods, every instance of every widget is stored on the element using jQuery.data(). To retrieve the instance object, call jQuery.data() using the widget's full name as the key:

var dialog = $( ".selector" ).data( "ui-dialog" );

After you have a reference to the instance object, methods can be invoked on it directly:

var dialog = $( ".selector" ).data( "ui-dialog" );
dialog.close();

In jQuery UI 1.11, the new instance() method will make this process even easier:

$( ".selector" ).dialog( "instance" ).close();

How can we use :data to get a list of all elements that are instances of a given widget?

You can also use :data to get a list of all elements that are instances of a given widget.

$( ":data('ui-progressbar')" );

What are the properties that each widget have?

  1. defaultElement: An element to use when a widget instance is constructed without providing an element. For example, since the progressbar's defaultElement is "<div>", $.ui.progressbar({ value: 50 }) instantiates a progressbar widget instance on a newly created <div>.
  2. document: A jQuery object containing the document that the widget's element is within. Useful if you need to interact with widgets within iframes.
  3. element: A jQuery object containing the element used to instantiate the widget. If you select multiple elements and call .myWidget(), a separate widget instance will be created for each element. Therefore, this property will always contain one element.
  4. namespace: The location on the global jQuery object that the widget's prototype is stored on. For example a namespace of "ui" indicates that the widget's prototype is stored on $.ui.
  5. options: An object containing the options currently being used by the widget. On instantiation, any options provided by the user will automatically be merged with any default values defined in $.myNamespace.myWidget.prototype.options. User specified options override the defaults.
  6. uuid: A unique integer identifier for the widget.
  7. version: The string version of the widget. For jQuery UI widgets this will be set to the version of jQuery UI the widget is using. Widget developers have to set this property in their prototype explicitly.
  8. widgetEventPrefix: The prefix prepended to the name of events fired from this widget. For example the widgetEventPrefix of the draggable widget is "drag", therefore when a draggable is created, the name of the event fired is "dragcreate". By default the widgetEventPrefix of a widget is its name. Note: This property is deprecated and will be removed in a later release. Event names will be changed to widgetName:eventName (e.g. "draggable:create").
  9. widgetFullName: The full name of the widget including the namespace. For $.widget( "myNamespace.myWidget", {} ), widgetFullName will be "myNamespace-myWidget".
  10. widgetName: The name of the widget. For $.widget( "myNamespace.myWidget", {} ), widgetName will be "myWidget".
  11. window: A jQuery object containing the window that the widget's element is within. Useful if you need to interact with widgets within iframes.

How can we change the theme for a widget?

Initialize a progressbar widget with the classes option specified, changing the theming for the ui-progressbar class:

$( ".selector" ).progressbar({
  classes: {
    "ui-progressbar": "highlight"
  }
});

Get or set the classes option, after initialization:

// Getter
var classes = $( ".selector" ).widget( "option", "classes" );

// Setter, override all classes
$( ".selector" ).widget( "option", "classes", { "custom-header": "icon-warning" } );

// Setter, override just one class
$( ".selector" ).widget( "option", "classes.custom-header", "icon-warning" );

Read more about classes from https://api.jqueryui.com/jquery.widget/ (search for "Additional (thematic) classes ")

How can we disable the widget right after initialization?

Initialize the widget with the disabled option specified:

$( ".selector" ).widget({
  disabled: true
});

How can we get or set the disabled option?

// Getter
var disabled = $( ".selector" ).widget( "option", "disabled" );

// Setter
$( ".selector" ).widget( "option", "disabled", true );

What is the purpose of the hide option?

If and how to animate the hiding of the element.

Type: Boolean or Number or String or Object. Default is null.

  1. Boolean: When set to false, no animation will be used and the element will be hidden immediately. When set to true, the element will fade out with the default duration and the default easing.
  2. Number: The element will fade out with the specified duration and the default easing.
  3. String: The element will be hidden using the specified effect. The value can either be the name of a built-in jQuery animation method, such as "slideUp", or the name of a jQuery UI effect, such as "fold". In either case the effect will be used with the default duration and the default easing.
  4. Object: If the value is an object, then effect, delay, duration, and easing properties may be provided. If the effect property contains the name of a jQuery method, then that method will be used; otherwise it is assumed to be the name of a jQuery UI effect. When using a jQuery UI effect that supports additional settings, you may include those settings in the object and they will be passed to the effect. If duration or easing is omitted, then the default values will be used. If effect is omitted, then "fadeOut" will be used. If delay is omitted, then no delay is used.
// Initialize:
$( ".selector" ).widget({
  hide: { effect: "explode", duration: 1000 }
});

// Getter
var hide = $( ".selector" ).widget( "option", "hide" );

// Setter
$( ".selector" ).widget( "option", "hide", { effect: "explode", duration: 1000 } );

What is the purpose of the show option?

If and how to animate the showing of the element.

Type: Boolean or Number or String or Object. Default is null.

  1. Boolean: When set to false, no animation will be used and the element will be shown immediately. When set to true, the element will fade in with the default duration and the default easing.
  2. Number: The element will fade in with the specified duration and the default easing.
  3. String: The element will be shown using the specified effect. The value can either be the name of a built-in jQuery animation method, such as "slideDown", or the name of a jQuery UI effect, such as "fold". In either case the effect will be used with the default duration and the default easing.
  4. Object: If the value is an object, then effect, delay, duration, and easing properties may be provided. If the effect property contains the name of a jQuery method, then that method will be used; otherwise it is assumed to be the name of a jQuery UI effect. When using a jQuery UI effect that supports additional settings, you may include those settings in the object and they will be passed to the effect. If duration or easing is omitted, then the default values will be used. If effect is omitted, then "fadeIn" will be used. If delay is omitted, then no delay is used.
// Initialize:
$( ".selector" ).widget({
  show: { effect: "blind", duration: 800 }
});

// Getter
var show = $( ".selector" ).widget( "option", "show" );

// Setter
$( ".selector" ).widget( "option", "show", { effect: "blind", duration: 800 } );

What is the purpose and signature of the _addClass method?

Add classes to an element of the widget. This provides a hook for the user to add additional classes or replace default styling classes, through the classes option. It also provides automatic removal of these classes when a widget is destroyed, as long as you're using _addClass(), _removeClass() and _toggleClass() together. This can heavily simplify the implementation of custom _destroy() methods.

_addClass( [element ], keys [, extra ] )
  1. element: (jQuery wrapped set containing just one DOM element for this instance). The element to add the classes to. Defaults to this.element.
  2. keys: (String). The classes to add, as a space-delimited list. If a property of the classes option matches a key, the value will be added as well. When you only need the extra argument, you can skip this argument by specifying null.
  3. extra: (String). Additional classes to add, required for layout or other reasons. Unlike the keys argument, these aren't associated with any properties of the classes option. Just like keys, they will also be automatically removed when destroying the widget.

To add the ui-progressbar class to the widget's element (this.element):

this._addClass( "ui-progressbar" );

Will also add any additional classes specified through the classes option for the given class. To add the demo-popup-header class to the specified element (here referencing this.popup):

this._addClass( this.popup, "demo-popup-header", "ui-front" );

This will also add any additional classes specified through the classes option for the given class. In addition, it will always add the ui-front class. To adds the ui-helper-hidden-accessible class to the specified element:

this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

Uses null for the keys argument to skip it.

**This is a method provided by the base class $.Widget. Perhaps we can redefine this _addClass method as part of the prototype object that is used with the $.widget() utility method just like the _create method.

What is the purpose of the _create() method?

The _create() method is the widget's constructor. There are no parameters, but this.element and this.options are already set. This method does not accept any arguments.

What is the purpose and signature of the _delay() method?

Invokes the provided function after a specified delay. Keeps this context correct. Essentially setTimeout(). Returns the timeout ID for use with clearTimeout().

_delay( fn [, delay ] )
  1. fn: (Function or String). The function to invoke. Can also be the name of a method on the widget.
  2. delay: (Number). The number of milliseconds to wait before invoking the function. Defaults to 0.
this._delay( this._foo, 100 );

What is the purpose of the _destroy() method of the $.Widget base class?

The public destroy() method cleans up all common data, events, etc. and then delegates out to _destroy() for custom, widget-specific, cleanup.

What is the purpose and signature of the _focusable() method of the $.Widget base class?

Sets up element to apply the ui-state-focus class on focus.

_focusable( element )

The event handlers are automatically cleaned up on destroy.

  1. element: (jQuery). The element(s) to apply the focusable behavior to.
// Apply focusable styling to a set of elements within the widget.
this._focusable( this.element.find( ".my-items" ) );

What is the purpose of the _getCreateEventData() method of the $.Widget base class?

All widgets trigger the create event. By default, no data is provided in the event, but this method can return an object which will be passed as the create event's data. This method does not accept any arguments.

// Pass the widget's options to create event handlers as an argument.
_getCreateEventData: function() {
  return this.options;
}

What is the purpose of the _getCreateOptions() method of the $.Widget base class?

This method allows the widget to define a custom method for defining options during instantiation. The user-provided options override the options returned by this method, which override the default options. This method does not accept any arguments.

// Make the widget element's id attribute available as an option.
_getCreateOptions: function() {
  return { id: this.element.attr( "id" ) };
}

What is the purpose of the _hide() method of the $.Widget base class?

Hides an element immediately, using built-in animation methods, or using custom effects. See the hide option for possible option values.

  1. element: (jQuery). The element(s) to hide.
  2. option: (Object). The properties defining how to hide the element.
  3. callback: (Function). Callback to invoke after the element has been fully hidden.
// Pass along the hide option for custom animations.
this._hide( this.element, this.options.hide, function() {

  // Remove the element from the DOM when it's fully hidden.
  $( this ).remove();
});

What is the purpose and signature of the _hoverable() method of the $.Widget base class?

Sets up element to apply the ui-state-hover class on hover. The event handlers are automatically cleaned up on destroy.

  1. element: (jQuery). The element(s) to apply the hoverable behavior to.
// Apply hoverable styling to all <div>s within the element on hover.
this._hoverable( this.element.find( "div" ) );

What is the purpose of the _init() method of the $.Widget base class?

Widgets have the concept of initialization that is distinct from creation. Any time the plugin is called with no arguments or with only an option hash, the widget is initialized; this includes when the widget is created.

Initialization should only be handled if there is a logical action to perform on successive calls to the widget with no arguments. This method does not accept any arguments.

// Call the open() method if the autoOpen option is set.
_init: function() {
  if ( this.options.autoOpen ) {
    this.open();
  }
}

What is the purpose and signature of the _off() method of the $.Widget base class?

Unbinds event handlers from the specified element(s).

_off( element, eventName )
  1. element: (jQuery). The element(s) to unbind the event handlers from. Unlike the _on() method, the elements are required for _off().
  2. eventName: (String). One or more space-separated event types.
// Unbind all click events from the widget's element.
this._off( this.element, "click" );

What is the purpose and signature of the _on() method of the $.Widget base class?

Binds event handlers to the specified element(s). Delegation is supported via selectors inside the event names, e.g., "click .foo". The _on() method provides several benefits of direct event binding:

  1. Maintains proper this context inside the handlers.
  2. Automatically handles disabled widgets: If the widget is disabled or the event occurs on an element with the ui-state-disabled class, the event handler is not invoked. Can be overridden with the suppressDisabledCheck parameter.
  3. Event handlers are automatically namespaced and cleaned up on destroy.
_on( [suppressDisabledCheck ] [, element ], handlers )
  1. suppressDisabledCheck (default: false). Type: (Boolean). Whether or not to bypass the disabled check.
  2. element: (jQuery). Which element(s) to bind the event handlers to. If no element is provided, this.element is used for non-delegated events and the widget element is used for delegated events.
  3. handlers: (Object). An object in which the keys represent the event type and optional selector for delegation, and the values represent a handler function to be called for the event.
// Prevent the default action of all links clicked within the widget's element.
this._on( this.element, {
  "click a": function( event ) {
    event.preventDefault();
  }
});

What is the purpose of the _removeClass() method of the $.Widget base class?

Remove classes from an element of the widget. The arguments are the same as for the _addClass() method, the same semantics apply, just in reverse.

_removeClass( [element ], keys [, extra ] )
  1. element: (jQuery). The element to remove the classes from. Defaults to this.element.
  2. keys: (String). The classes to remove, as a space-delimited list. If a property of the classes option matches a key, the value will be removed as well. When you only need the extra argument, you can skip this argument by specifying null.
  3. extra: (String). Additional classes to remove, required for layout or other reasons. Unlike the keys argument, these aren't associated with any properties of the classes option.

To remove the ui-progressbar class from the widget's element (this.element):

this._removeClass( "ui-progressbar" );

This will also remove any additional classes specified through the classes option for the given class. To remove the demo-popup-header class from the specified element (here referencing this.popup):

this._removeClass( this.popup, "demo-popup-header", "ui-front" );

This will also remove any additional classes specified through the classes option for the given class. In addition, it will also remove the ui-front class. To remove the ui-helper-hidden-accessible class from the specified element:

this._removeClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

Uses null for the keys argument to skip it.

What is the purpose and signature of the _setOption() method of the $.Widget base class?

Called from the _setOptions() method for each individual option. Widget state should be updated based on changes.

_setOption( key, value )
  1. key: (String). The name of the option to set.
  2. value: (Object). A value to set for the option.
// Update a widget's element when its height or width option changes.
_setOption: function( key, value ) {
  if ( key === "width" ) {
    this.element.width( value );
  }
  if ( key === "height" ) {
    this.element.height( value );
  }
  this._super( key, value );
}
_setOptions( options )

Called whenever the option() method is called, regardless of the form in which the option() method was called. Overriding this is useful if you can defer processor-intensive changes for multiple option changes.

  1. options: (Object). An object containing options to set, with the name of the option as the key and the option value as the value.
// Call a resize() method if the height or width options change.
_setOptions: function( options ) {
  var that = this,
    resize = false;

  $.each( options, function( key, value ) {
    that._setOption( key, value );
    if ( key === "height" || key === "width" ) {
      resize = true;
    }
  });

  if ( resize ) {
    this.resize();
  }
}

What is the purpose and signature of the _show() method of the $.Widget base class?

Shows an element immediately, using built-in animation methods, or using custom effects. See the show option for possible option values.

  1. element: (jQuery). The element(s) to show.
  2. option: (Object). The properties defining how to show the element.
  3. callback: (Function). Callback to invoke after the element has been fully shown.
// Pass along the show option for custom animations.
this._show( this.element, this.options.show, function() {

  // Focus the element when it's fully visible.
  this.focus();
}

What is the purpose and signature of the _super() method of the $.Widget base class?

Invokes the method of the same name from the parent widget, with any specified arguments. Essentially .call().

  1. arg: (Object). Zero to many arguments to pass to the parent widget's method.
// Handle title option updates and call the parent widget's _setOption() to update the internal storage of the option.
_setOption: function( key, value ) {
  if ( key === "title" ) {
    this.element.find( "h3" ).text( value );
  }
  this._super( key, value );
}

What is the purpose and signature of the _superApply() method of the $.Widget base class?

Invokes the method of the same name from the parent widget, with the array of arguments. Essentially .apply().

  1. arguments: (Array). Array of arguments to pass to the parent method.
// Handle title option updates and call the parent widget's _setOption() to update the internal storage of the option.
_setOption: function( key, value ) {
  if ( key === "title" ) {
    this.element.find( "h3" ).text( value );
  }
  this._superApply( arguments );
}

What is the purpose and signature of the _toggleClass() method of the $.Widget class?

Toggle classes of an element of the widget. The arguments are the same as for the _addClass() and _removeClass() methods, except for the additional boolean argument that specifies to add or remove classes. Unlike jQuery's .toggleClass() method, the boolean add argument is always required.

  1. element: (jQuery). The element to toogle the classes on. Defaults to this.element.
  2. keys: (String). The classes to toogle, as a space-delimited list. If a property of the classes option matches a key, the value will be toggled as well. When you only need the extra argument, you can skip this argument by specifying null.
  3. extra: (String). Additional classes to toggle, required for layout or other reasons. Unlike the keys argument, these aren't associated with any properties of the classes option. Just like keys, they will also be automatically removed when destroying the widget.
  4. add: (Boolean). Indicates whether to add or remove the specified classes, where a boolean true indicates that classes should be added, a boolean false indicates that classes should be removed.
// Toggle the ui-state-disabled class on the widget's element (this.element).
this._toggleClass( null, "ui-state-disabled", !!value );

What is the purpose and signature of the _trigger() method of the $.Widget base class?

Triggers an event and its associated callback. The option with the name equal to type is invoked as the callback. The event name is the lowercase concatenation of the widget name and type. When providing data, you must provide all three parameters. If there is no event to pass along, just pass null.

If the default action is prevented, false will be returned, otherwise true. Preventing the default action happens when the handler returns false or calls event.preventDefault().

_trigger( type [, event ] [, data ] )
  1. type: (String). The type should match the name of a callback option. The full event type will be generated automatically.
  2. event: (Event). The original event that caused this event to occur; useful for providing context to the listener.
  3. data: (Object). A hash of data associated with the event.
// Trigger a search event whenever a key is pressed.
this._on( this.element, {
  keydown: function( event ) {

    // Pass the original event so that the custom search event has
    // useful information, such as keyCode
    this._trigger( "search", event, {

      // Pass additional information unique to this event
      value: this.element.val()
    });
  }
});

What is the purpose of the destroy() method?

Removes the widget functionality completely. This will return the element back to its pre-init state. This method does not accept any arguments.

What is the purpose of the disable() method?

Disables the widget.

What is the purpose of the enable() method?

Enable the widget.

What is the purpose of the instance() method?

Retrieves the widget's instance object. If the element does not have an associated instance, undefined is returned. Unlike other widget methods, instance() is safe to call on any element after the widget plugin has loaded.

What is the purpose and signature of the option() method?

Gets the value currently associated with the specified optionName. For options that have objects as their value, you can get the value of a specific key by using dot notation. For example, "foo.bar" would get the value of the bar property on the foo option.

option( optionName ) // Gets the value currently associated with the specified optionName
option() // Gets an object containing key/value pairs representing the current widget options hash
option( optionName, value ) // Sets the value of the widget option associated with the specified optionName.
option( options ) // Sets one or more options for the widget.
  1. optionName: (String). The name of the option to get.
  2. value: (Object). A value to set for the option.
  3. options: (Object). A map of option-value pairs to set.

What is the purpose of the widget() method?

Returns a jQuery object containing the original element or other relevant generated element. This method does not accept any arguments.

What is the purpose and signature of the create event?

This event is triggered when the widget is created.

create( event, ui )
  1. event: (Event)
  2. ui: (Object)

The ui object is empty but included for consistency with other events.

// Initialize the widget with the create callback specified:
$( ".selector" ).widget({
  create: function( event, ui ) {}
});

// Bind an event listener to the widgetcreate event:
$( ".selector" ).on( "widgetcreate", function( event, ui ) {} );

What is the return type for each widget method?

Most methods invoked through the widget's plugin will return a jQuery object so the method call can be chained with additional jQuery methods. This is even true of methods that return undefined when invoked on the instance. This is shown in the example below.

var dialog = $( ".selector" ).dialog();

// Instance invocation - returns undefined
dialog.data( "ui-dialog" ).close();

// Plugin invocation - returns a jQuery object
dialog.dialog( "close" );

// Therefore, plugin method invocation makes it possible to
// chain method calls with other jQuery functions
dialog.dialog( "close" )
    .css( "color", "red" );

The exception to this are methods that return information about the widget. For example dialog's isOpen() method:

$( ".selector" )
    .dialog( "isOpen" )
    // This will throw a TypeError
    .css( "color", "red" );

This produces a TypeError error as isOpen() returns a boolean, not a jQuery object.

How can we extend or overwrite an existing method?

Sometimes you need to tweak or add to the behavior of existing widget methods. The do this, specify a method with the same name as the method you want to override on the prototype object. The following example overrides dialog's open() method. Since dialogs automatically open by default, "open" will be logged when this code runs.

$.widget( "custom.superDialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
    }
});

// Create a new <div>, and convert it into a superDialog.
$( "<div>" ).superDialog();

While this runs, there's a problem. Since we overrode the default behavior of open(), the dialog no longer displays on the screen. When we place methods on the prototype object, we are not actually overriding the original method - rather, we are placing a new method at a higher level in the prototype chain. To make the parent's methods available, the widget factory provides two methods - _super() and _superApply().

_super() and _superApply() invoke methods of the same name in the parent widget. Refer to the following example. Like the previous one, this example also overrides the open() method to log "open". However, this time _super() is run to invoke dialog's open() and open the dialog.

$.widget( "custom.superDialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );

        // Invoke the parent widget's open().
        return this._super();
    }
});

$( "<div>" ).superDialog();

_super() and _superApply() were designed to behave like the native Function.prototype.call() and Function.prototype.apply() methods. Therefore, _super() accepts an argument list, and _superApply() accepts a single array of arguments. This difference is shown in the example below.

$.widget( "custom.superDialog", $.ui.dialog, {
    _setOption: function( key, value ) {

        // Both invoke dialog's setOption() method. _super() requires the arguments
        // be passed as an argument list, _superApply() as a single array.
        this._super( key, value );
        this._superApply( arguments );
    }
});

How can we redefine a widget in place?

jQuery UI 1.9 added the ability for us to redefine widgets in place. Therefore, instead of creating a new widget, we can pass $.widget() an existing widget's name and constructor. The following example adds the same logging in open(), but doesn't create a new widget to do so.

$.widget( "ui.dialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
        return this._super();
    }
});

$( "<div>" ).dialog();

With this approach you can extend an existing widget's method and still have access to the original methods using _super() - all without creating a new widget.

Can a parent widget be used to invoke methods on elements that are child widgets like traditional polymorphism?

No. One word of warning when interacting with widget extensions and their plugins. The parent widget's plugin cannot be used to invoke methods on elements that are child widgets. This is shown in the example below.

$.widget( "custom.superDialog", $.ui.dialog, {} );

var dialog = $( "<div>" ).superDialog();

// This works.
dialog.superDialog( "close" );

// This doesn't.
dialog.dialog( "close" );

How can we customize individual widget instances?

All the examples we have looked at so far have extended methods on the widget's prototype. Methods overridden on the prototype affect all instances of the widget. To show this, refer to the example below; both instances of the dialog use the same open() method.

$.widget( "ui.dialog", $.ui.dialog, {
    open: function() {
        console.log( "open" );
        return this._super();
    }
});

// Create two dialogs, both use the same open(), therefore "open" is logged twice.
$( "<div>" ).dialog();
$( "<div>" ).dialog();

While this is powerful, sometimes you only need to change the behavior for a single instance of the widget. To do this, obtain a reference to the instance and override the method using normal JavaScript property assignment. The example below shows this.

var dialogInstance = $( "<div>" )
    .dialog()

    // Retrieve the dialog's instance and store it.
    .data( "ui-dialog" );

// Override the close() method for this dialog
dialogInstance.close = function() {
    console.log( "close" );
};

// Create a second dialog
$( "<div>" ).dialog();

// Select both dialogs and call close() on each of them.
// "close" will only be logged once.
$( ":data(ui-dialog)" ).dialog( "close" );

This technique of overriding methods for individual instances is perfect for one-off customizations.

How can we use the 'classes' option?

As of the 1.12 release, the jQuery UI widget factory includes a means of managing CSS class names through the classes option. This article will give you an overview of how the classes option works, and discuss what you can do with it. The classes option is used to map structural class names to theme-related class names that you define. To see what this means let's look at an example. The code below uses the classes option to create a red dialog:

<style>
    .custom-red { background: red; }
</style>
<script>
    var dialog = $( "<div>Red</div>" ).dialog({
        classes: {
            "ui-dialog": "custom-red"
        }
    });
</script>

Here, the presentational custom-red class name is associated with the structural ui-dialog class name. Now, whenever the dialog applies the ui-dialog class name, it will also add a custom-red class name. However, something other than adding the custom-red class has happened here, which isn't immediately obvious. This code also removes the existing default value which was "ui-corner-all". You can associate multiple class names by including multiple space-delimited class names in the object's value. For instance the following code creates a dialog that is red and still has rounded corners:

<style>
    .custom-red { background: red; }
</style>
<script>
    var dialog = $( "<div>Big and red</div>" ).dialog({
        classes: {
            "ui-dialog": "ui-corner-all custom-red"
        }
    });
</script>

To get a full list of the class names you can use with the classes option, check the API documentation for the jQuery UI widget you're interested in. For example, here's the list of classes for the dialog width: http://api.jqueryui.com/dialog/#theming

The classes option works like any other widget factory option, which means all the widget factory option mechanisms still apply. For instance, the following code uses the option() method to remove all class names currently associated with the ui-dialog class name:

dialog.dialog( "option", "classes.ui-dialog", null );

And the following creates a widget extension that automatically associates the custom-red class with the ui-dialog class:

<style>
    .custom-red { background: red; }
</style>
<script>
    $.widget( "custom.dialog", $.ui.dialog, {
        options: {
            classes: {
                "ui-dialog": "ui-corner-all custom-red custom-big"
            }
        }
    });
    $( "<div>Big and red</div>" ).dialog();
</script>

As an added benefit, the widget factory also removes any class names specified in the classes option when the widget is destroyed.

As the previous examples show, the classes option provides a quick way to associate theme-related class names with the structural class names used within a widget. This approach works for simple cases, but it can also be used to adapt third-party themes to work with widget-factory-built widgets. For example, if you're using Bootstrap and jQuery UI together, you can use the following code to create a jQuery UI dialog that uses Bootstrap's theming:

$.extend( $.ui.dialog.prototype.options.classes, {
    "ui-dialog": "modal-content",
    "ui-dialog-titlebar": "modal-header",
    "ui-dialog-title": "modal-title",
    "ui-dialog-titlebar-close": "close",
    "ui-dialog-content": "modal-body",
    "ui-dialog-buttonpane": "modal-footer"
});

For more examples of this approach, check out Alexander Schmitz's repo that adapts jQuery UI to work with Boostrap using the classes option.

The introduction of the classes option takes us one step further in the split between structural and theme-related classes, making it easier than ever to make jQuery UI widgets match the look and feel of your existing site. At the same time, this allows jQuery UI to be used alongside other CSS frameworks, just like jQuery can be used alongside other JavaScript frameworks.

What is the purpose of the widget common method?

Some widgets generate wrapper elements, or elements disconnected from the original element. In these cases, the widget method will return the generated element. In cases like the progressbar, where there is no generated wrapper, the widget method returns the original element.

$( "#elem" ).progressbar( "widget" );

How can we implement an event in our plugin using $.widget()?

All widgets have events associated with their various behaviors to notify you when the state is changing. For most widgets, when the events are triggered, the names are prefixed with the widget name. For example, we can bind to progressbar's change event which is triggered whenever the value changes.

$( "#elem" ).bind( "progressbarchange", function() {
    alert( "The value has changed!" );
});

Each event has a corresponding callback, which is exposed as an option. We can hook into progressbar's change callback instead of binding to the progressbarchange event, if we wanted to.

$( "#elem" ).progressbar({
    change: function() {
        alert( "The value has changed!" );
    }
});
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License