|
| 1 | +--- |
| 2 | +title: Extending Widgets with the Widget Factory |
| 3 | +level: intermediate |
| 4 | +--- |
| 5 | + |
| 6 | +jQuery UI's widget factory makes it easy to build widgets that extend the functionality of existing widgets. Doing so allows you to build powerful widgets on top of an existing base, as well as make small tweaks to an existing widget's functionality. |
| 7 | + |
| 8 | +### Creating Widget Extensions |
| 9 | + |
| 10 | +Creating widgets with the widget factory is done by passing the name of the widget and a prototype object to `$.widget`. The following creats a "myWidget" widget in the "myNamespace" namespace. |
| 11 | + |
| 12 | +``` |
| 13 | +$.widget( "myNamespace.myWidget" {} ); |
| 14 | +``` |
| 15 | + |
| 16 | +`$.widget` also accepts the constructor of a widget to extend as an optional parameter. For instance, the constructor of [jQuery UI's dialog widget](http://jqueryui.com/dialog/) is `$.ui.dialog`. |
| 17 | + |
| 18 | +When specifying a base widget, pass it as a second argument - after the widget's name, and before the widget's prototype object. The following creates a "superDialog" widget based on the dialog widget in the `"my"` namespace. |
| 19 | + |
| 20 | +``` |
| 21 | +$.widget( "my.superDialog", $.ui.dialog, {} ); |
| 22 | +``` |
| 23 | + |
| 24 | +Here superDialog and dialog are essentially equivalent widgets with different names and namepaces. To make our new widget more interesting we can add methods to its prototype. |
| 25 | + |
| 26 | +The prototype object to use for a widget is the final argument passed to `$.widget`. To this point our examples have been using an empty object. Let's add a method to the prototype: |
| 27 | + |
| 28 | +``` |
| 29 | +$.widget( "my.superDialog", $.ui.dialog, { |
| 30 | + red: function() { |
| 31 | + this.element.css( "color", "red" ); |
| 32 | + } |
| 33 | +}); |
| 34 | +
|
| 35 | +// Create a new <div>, convert it into a superDialog, and call the red method. |
| 36 | +$( "<div>I am red</div>" ) |
| 37 | + .superDialog() |
| 38 | + .superDialog( "red" ); |
| 39 | +``` |
| 40 | + |
| 41 | +Now the `superDialog` has a `red()` method that will change its text red. Note how the widget factory automatically sets `this` equal to the widget's instance. For a full list of the methods and properties available on the instance see [the widget factory's API documentation](http://api.jqueryui.com/jquery.widget/). |
| 42 | + |
| 43 | +### Extending Existing Methods |
| 44 | + |
| 45 | +Sometimes you need to tweak or add to the behavior of existing widget methods. The do this, specify a method with the same name on the prototype object passed to `$.widget`. The following overrides dialog's [`open()` method](http://api.jqueryui.com/dialog/#method-open). Since dialogs automatically open by default, `"open"` will be logged when this code runs. |
| 46 | + |
| 47 | +``` |
| 48 | +$.widget( "my.superDialog", $.ui.dialog, { |
| 49 | + open: function() { |
| 50 | + console.log( "open" ); |
| 51 | + } |
| 52 | +}); |
| 53 | +
|
| 54 | +// Create a new <div>, and convert it into a superDialog |
| 55 | +$( "<div>" ).superDialog(); |
| 56 | +``` |
| 57 | + |
| 58 | +While this runs, there's a problem. Since we overrode the default behavior of `open()`, the dialog no longer displays on the screen. |
| 59 | + |
| 60 | +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. |
| 61 | + |
| 62 | +The original `show()` method is still available at `$.ui.dialog.prototype.open()`, and can be invoked. The following creates a new widget with an `open()` method that logs `"Opened"` then calls dialog's `open()`. |
| 63 | + |
| 64 | +``` |
| 65 | +$.widget( "my.superDialog", $.ui.dialog, { |
| 66 | + open: function() { |
| 67 | + console.log( "Opened" ); |
| 68 | + return $.ui.dialog.prototype.open.apply( this, arguments ); |
| 69 | + } |
| 70 | +}); |
| 71 | +
|
| 72 | +$( "#dialog" ).superDialog(); |
| 73 | +``` |
| 74 | + |
| 75 | +### Using _super to Access Parents |
| 76 | + |
| 77 | +Referencing the parent widget's prototype methods is a bit verbose, therefore in [jQuery UI 1.9](http://jqueryui.com/upgrade-guide/1.9/) the [`_super()` method](http://api.jqueryui.com/jquery.widget/#method-_super) was introduced. |
| 78 | + |
| 79 | +`_super()` invokes the method of the same name from the parent widget with the same set of arguments. Therefore we can replace our call to `$.ui.dialog.prototype.open()` with one to `_super()`. |
| 80 | + |
| 81 | +``` |
| 82 | +$.widget( "my.superDialog", $.ui.dialog, { |
| 83 | + open: function() { |
| 84 | + console.log( "Opened" ); |
| 85 | + return this._super(); |
| 86 | + } |
| 87 | +}); |
| 88 | +
|
| 89 | +$( "#dialog" ).superDialog(); |
| 90 | +``` |
| 91 | + |
| 92 | +### Redefining Widgets |
| 93 | + |
| 94 | +Another feature added in jQuery UI 1.9 was the ability for widgets to redefine themselves. 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. |
| 95 | + |
| 96 | +``` |
| 97 | +$.widget( "ui.dialog", $.ui.dialog, { |
| 98 | + open: function() { |
| 99 | + console.log( "Opened" ); |
| 100 | + return this._super(); |
| 101 | + } |
| 102 | +}); |
| 103 | +
|
| 104 | +$( "#dialog" ).dialog(); |
| 105 | +``` |
| 106 | + |
| 107 | +Now you can extend an existing widget's method, and still have access to the original methods using `_super()`. |
0 commit comments