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 !

Jide
  • 1,130
  • 2
  • 12
  • 18
  • 3
    In 1.8, the $.widget() function accepts a base widget as the second parameter. http://docs.jquery.com/UI_Developer_Guide#The_widget_factory – itsadok Mar 07 '11 at 06:41

6 Answers6

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.

bullgare
  • 1,643
  • 1
  • 21
  • 32
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 !

Jide
  • 1,130
  • 2
  • 12
  • 18
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
        }
    }
});
macramole
  • 111
  • 1
  • 8
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.

C.S.
  • 422
  • 2
  • 9
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?

Community
  • 1
  • 1
Cheeso
  • 189,189
  • 101
  • 473
  • 713
  • 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. – Jide Mar 28 '10 at 14:18
  • I believe we should rather store the old function in the same namespace: `$.ui.autocomplete.prototype._originalRenderItem = $.ui.autocomplete.prototype._renderItem;`. – jjmontes Jan 03 '12 at 12:29
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();
} 
Corey Adler
  • 15,897
  • 18
  • 66
  • 80