11
votes

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?

2

2 Answers

19
votes

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
  }; 
} 
1
votes

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);
  }
});