11

If I want to tweak some of the capability of a jQuery UI object, by replacing one of the functions, how would I go about doing that?

Example: suppose I wanted to modify the way the jQuery autocomplete widget rendered the suggestions. There's a method on the autocomplete object that looks like this:

_renderItem: function( ul, item) {
    return $( "<li></li>" )
        .data( "item.autocomplete", item )
        .append( "<a>" + item.label + "</a>" )
        .appendTo( ul );
},

Could I replace this?

I think this might be called Monkey Patching.

How? What syntax would I use?

Cheeso
  • 189,189
  • 101
  • 473
  • 713

2 Answers2

19

I don't know about jQuery UI, but in general, this is how you redefine a function:

(function() {
   var _oldFunc = _renderItem;

   _renderItem = function(ul,item) {
      // do your thing
      // and optionally call the original function:
      return _oldFunc(ul,item);
   }
})();

The reason this is wrapped in an anonymous function is to create a closure for storing the original function. This way it can never interfere with global variables.


EDIT
To do this to a fn on a jQuery UI widget, use this syntax:

FYI: the way to grab the function is 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
  }; 
} 
Cheeso
  • 189,189
  • 101
  • 473
  • 713
Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223
  • 4
    monkey patching or, as Paul Irish explains, duck punching :) - http://paulirish.com/2010/duck-punching-with-jquery/ – Russ Cam Mar 12 '10 at 22:36
  • I get that part - the thing I am having trouble with is the jQuery-esque part. The way jQuery UI defines widgets and so on. – Cheeso Mar 12 '10 at 22:46
  • Nope! I didn't know there was such a thing. – Cheeso Mar 13 '10 at 01:08
  • 1
    So, inside this new function, how do I get an access to the this variable? – ulu May 10 '12 at 15:05
  • @Philippe Leybaert: Do you know where jQuery UI's position method reside? It's not limited to one particular widget. – Jinghui Niu Nov 24 '16 at 11:44
  • 1
    @ulu Although he didn't call `oldFn` in his overridden function, if you wanted to you could call `oldFn.apply(this, arguments)` to preserve the `this` argument. – Robert Feb 11 '20 at 07:14
1

I know it's an old question, but I just had to fix some bugs on an old project and had an issue with this kind of patch.

Better make the function available through the options object, and then put your specific logic there.

Patch:

(function monkeyPatchJQueryAutocomplete($) {

  /**
   * Proxies a private
   * prototype method to the
   * options Object
   *
   * @param  {Object} obj
   * @param  {String} funcName
   */
  function proxyPrivateMethodToOptions(obj, funcName) {
    var __super = obj.prototype[funcName];
    obj.prototype[funcName] = function() {
      if (this.options[funcName]) {
        return this.options[funcName].apply(this, arguments);
      }
      return __super.apply(this, arguments);
    };
  }

  // Make the private _renderItem
  // method available through the options Object
  proxyPrivateMethodToOptions($.ui.autocomplete, '_renderItem');

  // We can do this for other methods as well:
  proxyPrivateMethodToOptions($.ui.autocomplete, '_renderMenu');

}($));

Usage-Example:

$('.some-input').autocomplete({
  _renderItem: function(ul, item) {
    console.log('here we can reference the old func via: ', __super);
    return $("<li>")
      .append($("<a>").text(item.label))
      .appendTo(ul);
  }
});
HaNdTriX
  • 28,732
  • 11
  • 78
  • 85