jQuery UI extension widgets
jQuery UI’s Widget Factory makes it easier to create widgets that extend the functionality of existing widgets. In this way, you can create powerful widgets based on existing ones, and you can also make subtle adjustments to the functions of existing widgets.
Note: Before studying this chapter, you need to understand what a widget factory is and how it works. If you are not familiar with this knowledge, please check out the How to Use Widget Factory chapter first.
Creating a widget extension
Creating a widget through the widget factory is done by passing the widget name and a prototype object to $.widget()
of. The following example creates a "superDialog" widget in the "custom" namespace.
$.widget( "custom.superDialog", {} );
To support extensions, $.widget()
optionally accepts the constructor of a widget used as a parent widget. When specifying a parent widget, pass it as the second argument, after the widget name and before the widget prototype object.
Just like the above example, we will also create a "superDialog" widget in the "custom" namespace. But this time what is passed is the constructor of jQuery UI's dialog widget ($.ui.dialog
), indicating that the superDialog widget should use jQuery UI's dialog widget as Parent widget.
$.widget( "custom.superDialog", $.ui.dialog, {} );
Here, the two widgets superDialog and dialog are essentially equivalent, except that their names and namespaces are different. To make our new widget more distinctive, we can add some methods to its prototype object.
The widget's prototype object is the last parameter passed to $.widget()
. So far, our examples have used an empty object. Now let's add a method to this object:
$.widget( "custom.superDialog", $.ui.dialog, { red: function() { this.element.css( "color", "red" ); } }); // Create a new <div>, convert it into a superDialog, and call the red() method. $( "<div>I am red</div>" ) .superDialog() .superDialog( "red" );
Now superDialog
has a red()
method, which will change its text color to red. Note how the Widget Factory automatically sets this
to an instance of the widget. For a list of all methods and properties available on an instance, visit the Widget Factory API documentation.
Extend existing methods
Sometimes, you need to adjust or add the behavior of existing widget methods. You can specify the method name as the name of the method that needs to be overridden on the prototype object. The following example overloads the open()
method of dialog. Since the dialog box is open by default, "open"
will be logged when this code is run.
$.widget( "custom.superDialog", $.ui.dialog, { open: function() { console.log( "open" ); } }); // Create a new <div>, and convert it into a superDialog. $( "<div>" ).superDialog();
When running this code, there is a problem. Since we have overridden the default behavior of open()
, the dialog is no longer displayed on the screen.
When we use a method on a prototype object, we actually overload the original method and use a new method in the prototype chain.
In order to make the parent widget method available, the widget factory (Widget Factory) provides two methods - _super()
and _superApply()
.
Use _super()
and _superApply()
to access the parent widget
_super()
and _superApply ()
The same method is called in the parent widget. See the example below. Just like the previous example, this example also overloads the open()
method to record "open"
. However, this time running _super()
calls dialog's open()
and opens 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()
are actually equivalent to the original Function.prototype.call()
and Function .prototype.apply()
method. Therefore, _super()
accepts a parameter list and _superApply()
accepts an array as parameter. The following example demonstrates the difference between the two.
$.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 ); } });
Redefine widgets
jQuery UI 1.9 added the ability to redefine widgets. Therefore, instead of creating a new widget, we only need to pass $.widget()
such an existing widget name and constructor. The example below adds the same record in open()
, but not by creating a new widget.
$.widget( "ui.dialog", $.ui.dialog, { open: function() { console.log( "open" ); return this._super(); } }); $( "<div>" ).dialog();
With this method, we can extend an existing widget method, but still access the original method using _super()
- none of this is done by creating a new widget Instead of using widgets, you can directly redefine the widgets.
Widgets and Polymorphism
When interacting between widget extensions and their plug-ins, it is important to note that the plug-ins of the parent widget cannot be used to call methods on child widget elements. The following example demonstrates this.
$.widget( "custom.superDialog", $.ui.dialog, {} ); var dialog = $( "<div>" ).superDialog(); // This works. dialog.superDialog( "close" ); // This doesn't. dialog.dialog( "close" );
In the above example, the parent component's plug-in, dialog()
, cannot call the close()
method on the superDialog element. To learn more about calling widget methods, see Widget Method Calling.
Customized Personalization Examples
So far, the examples we have seen all have methods that extend on the widget prototype. Methods overloaded on the prototype affect all instances of the widget.
To demonstrate this, look at the example below. Both sides of 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();
Sometimes you just need to change the behavior of a certain instance of a widget. In order to do this, you need to use normal JavaScript property assignment, get a reference to the instance, and override the method. The details are shown in the following examples.
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" );
The overloaded method technology of personalized instances is perfect for one-time customization.