tigrou
tigrou

Reputation: 4526

Difference between using the widget factory vs $.extend() to extend a widget?

In jQueryUI, the Widget factory can be use to extend the functionality of existing widgets. This is be useful to tweak private methods (like _renderItem) for example.

$.widget( "ui.autocomplete", $.ui.autocomplete, {
    _renderItem: function( ul, item ) {

    }
});

Another way (which AFAIK give similar results) is to use jQuery.extend() method :

$.extend( $.ui.autocomplete, {
    _renderItem: function( ul, item ) {

    },
});

jQueryUI implementation seems to use both in some places (line 3335, or search for "live region extension" in the js file )

My question is : is there any difference between these two ways of extending a widget and which one should I better use, as good practice ?

Upvotes: 1

Views: 382

Answers (1)

Richard Scarrott
Richard Scarrott

Reputation: 7073

Using $.extend as you have there won't work because you're adding methods directly to the constructor function, you'd need to add the methods to either the constructor's prototype or directly on an instance.

The following would work however:

$.extend($.ui.autocomplete.prototype, {
    foo: true
});

This will mutate the original autocomplete class so as a side effect of this any instances instantiated before the extend will also be mutated, i.e.

var instance = $('input').autocomplete().data('uiAutocomplete');
console.log(instance.foo); // undefined
$.extend($.ui.autocomplete.prototype, { foo: true });
console.log(instance.foo); // true

On the other hand the widget factory will create a new 'class' which inherits from the existing $.ui.autocomplete (which just happens to override the reference to the original autocomplete constructor):

var instance = $('input').autocomplete().data('uiAutocomplete');
console.log(instance.foo); // undefined
$.widget('ui.autocomplete', $.ui.autocomplete, { foo: true });
console.log(instance.foo); // undefined (still)

The widget factory will also let you store the constructor in a separate namespace so you could use both the original and the extended constructor at once:

$.widget('foo.autocomplete', $.ui.autocomplete, { foo: true });
console.log($.foo.autocomplete !== $.ui.autocomplete); // true

You would need to manually re-bridge the original constructor to a jQuery plugin to be able to instantiate it in a 'jQuery way':

$.widget.bridge('originalAutocomplete', $.ui.autocomplete);
$('input').autocomplete(); // instanceof $.foo.autocomplete && instanceof $.ui.autocomplete
$('input').originalAutocomplete(); // instance of $.ui.autocomplete only

In short... $.widget would more commonly be recommended as a best practice vs $.extend, but it depends on your use case.

Upvotes: 1

Related Questions