How to extend a jquery ui widget ? (1.7)
Asked Answered
P

6

30

I would like to create a custom version of the sortable widget. I have been searching for documentation, but could not find something really accurate. The best information I found was : http://jqueryui.pbworks.com/Widget-factory.

I tried :

$.widget("ui.customsortable", $.extend($.ui.sortable, {
  _init: function() {
    $.widget.prototype._init.apply(this, arguments);
  }
}));

But $.widget.prototype._init is not the function I want to call I guess since it is the $.widget prototype.

Then, I tried something I read here and there :

var _init = $.ui.sortable.prototype._init; 

$.widget("ui.customsortable", $.extend($.ui.sortable, {
  _init: function() {
    _init.apply(this, arguments);
  },
}));

But :

  • I can't believe I have to store all methods I want to override like this, it is so ugly.
  • It throws an error ("this.refresh is not a function"), which means the refresh method does not exist. Does that mean I would have to recreate all methods I want to override ? What's the point of extending in that case ?

Am I missing something here ?

Thanks for your help !

Pearly answered 26/3, 2010 at 17:18 Comment(1)
In 1.8, the $.widget() function accepts a base widget as the second parameter. docs.jquery.com/UI_Developer_Guide#The_widget_factoryUnconcerned
P
22

After several tries, I finally found out how to do this easily :

$.widget("ui.customsortable", $.extend({}, $.ui.sortable.prototype, {

  _init: function(){
    this.element.data('sortable', this.element.data('customsortable'));
    return $.ui.sortable.prototype._init.apply(this, arguments);
  }

  // Override other methods here.

}));

$.ui.customsortable.defaults = $.extend({}, $.ui.sortable.defaults);

The key is to copy data from your custom widget to the original one. Don't forget to use $.ui.sortable.prototype.[overriden method].apply(this, arguments); in each overriden method.

Holly crap !

Pearly answered 11/5, 2010 at 18:8 Comment(0)
B
28

These are kinda strange answers. There is an optional second parameter - basewidget to inherit from. It's easy. No need to work with prototype and so on.

$.widget( "ui.customsortable", $.ui.sortable, {

  _init: function() {
    this.element.data('sortable', this.element.data('customsortable'));
    // or whatever you want
  }
} );

The second parameter is $.ui.sortable. I think it's all you need.

Bandoline answered 14/3, 2012 at 12:33 Comment(0)
P
22

After several tries, I finally found out how to do this easily :

$.widget("ui.customsortable", $.extend({}, $.ui.sortable.prototype, {

  _init: function(){
    this.element.data('sortable', this.element.data('customsortable'));
    return $.ui.sortable.prototype._init.apply(this, arguments);
  }

  // Override other methods here.

}));

$.ui.customsortable.defaults = $.extend({}, $.ui.sortable.defaults);

The key is to copy data from your custom widget to the original one. Don't forget to use $.ui.sortable.prototype.[overriden method].apply(this, arguments); in each overriden method.

Holly crap !

Pearly answered 11/5, 2010 at 18:8 Comment(0)
P
3

Regarding the selected solution above:

$.widget("ui.customsortable", $.extend(true, {}, $.ui.sortable.prototype, {

If you are extending one objects options into another, the [deep] flag of true will give you the desired results.

Pandowdy answered 13/1, 2012 at 18:23 Comment(0)
W
3

I'm using this in order to predefine start, stop and update functions:

$.widget('ui.custom_sortable_or_any_other_name', $.ui.sortable, {
    _init: function() {
        this.element.children().css('position', 'relative'); //for example
    },
    options : {
        start: function (event, ui) {   
            ui.item.addClass('noclick'); //ui.item get's the item, that's my point
        },
        stop: function (event, ui) {            
        },
        update: function (event, ui) {
            $.ajax(); //some ajax you might want to do
        }
    }
});
Woodberry answered 3/10, 2012 at 15:41 Comment(0)
F
2

I don't know just what you're after, when you say "extend a widget". In my case I wanted to change how the widget rendered itself, and fiddling with the CSS classes didn't satisfy. It was not a case of extending the behavior of a widget, but rather modifying the behavior of a widget.

So I over-rode the render method. The widget in question was the jQueryUI autocomplete, and the over-ride looked like this:

function monkeyPatchAutocomplete() {  

  // don't really need this, but in case I did, I could store it and chain  
  var oldFn = $.ui.autocomplete.prototype._renderItem;  

  $.ui.autocomplete.prototype._renderItem = function( ul, item) {  
     // whatever 
  };  
}  

I just called that in $(document).ready().


related:
- Can I replace or modify a function on a jQuery UI widget? How?
- jQueryUI: how can I custom-format the Autocomplete plug-in results?

Fated answered 26/3, 2010 at 18:41 Comment(2)
Thank you for your answer. Unfortunately, I don't want to modify the existing widget, since I want the original widget to stay intact. Another way to achieve what you do would be : $.extend($.ui.sortable.prototype, { ... }); I want to create a new widget based on an existing one, with inheritance, in the logic of OO programming.Pearly
I believe we should rather store the old function in the same namespace: $.ui.autocomplete.prototype._originalRenderItem = $.ui.autocomplete.prototype._renderItem;.Tessietessier
W
2

I used this one time:

$.ui.buttonset.prototype.value = function() {
     return this.element.find('#' + this.element.find('label[aria-pressed="true"]').attr('for')).val();
} 
Witchcraft answered 5/3, 2012 at 16:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.