78

I'm a fairly new jQuery user looking to extend an existing jQuery plugin that does about 75% of what I need. I've tried to do my homework on this. I've checked out the following questions on stackoverflow:

I've read up on the extend method. However, all of thise homework has left me confused. I'm working with the fullcalendar plugin and need to modify some of the behavior as well as add new event hooks. Am I stuck with doing this in the plugin closure itself? Am I missing something obvious?

Ideally we would be able to separate our code from the plugin code to allow for a possible upgrade. Any help would be greatly appreciated, especially pointers on where I'm missing some information or opinions on whether the solutions already presented in other Stack Overflow questions make sense. To me they contradict each other and I'm still left confused.

Community
  • 1
  • 1
justkt
  • 14,610
  • 8
  • 42
  • 62
  • justkt, Can you post some example code of how you extended the fullcalendar plugin? I'm currently trying to do the same thing but am getting stumped and not able to call any of the functions I've supposedly added. – Matt McCormick Jun 29 '12 at 08:30
  • @MattMcCormick - did you try the accepted answer listed below? – justkt Jun 29 '12 at 12:36
  • Ah, I was including .prototype. I didn't need that. Now I just have $.extend(true, $.fullCalendar, extensionMethods); and it works! Ideally I would like to extend the Event object but that is not namespaced so I don't see how that would be possible. This works for now though. – Matt McCormick Jun 30 '12 at 05:35
  • 2
    See http://msdn.microsoft.com/en-us/library/hh404085.aspx (Inheritance chapter) – katrin Oct 04 '12 at 10:03

7 Answers7

86

I just had the same problem trying to extend jquery UI plugins, and here is the solution I found (found it through jquery.ui.widget.js):


(function($) {
/**
 *  Namespace: the namespace the plugin is located under
 *  pluginName: the name of the plugin
 */
    var extensionMethods = {
        /*
         * retrieve the id of the element
         * this is some context within the existing plugin
         */
        showId: function(){
            return this.element[0].id;
        }
    };

    $.extend(true, $[ Namespace ][ pluginName ].prototype, extensionMethods);


})(jQuery);

hope this helps, please ask if you have any questions.

Jared Scott
  • 1,045
  • 10
  • 11
  • 2
    So to clarify, if I wanted to extend jQuery UI's autocomplete, then the `Namespace` would be "ui" and the `pluginName` would be "autocomplete"? – Matt Huggins Nov 21 '11 at 23:55
  • 1
    I think I answered my own question. I found in the autocomplete source where it calls `jQuery.widget("ui.autocomplete", ...)`, and in the widget source where it splits at the ".", with namespace being index 0, and pluginName being index 1. So in other words, it looks like I was right. :) – Matt Huggins Nov 21 '11 at 23:58
  • 4
    @Jared - I ended up taking your advice here to extend jQuery UI autocomplete. I describe my goals here: http://www.matthuggins.com/articles/extending-jquery-uis-autocomplete-to-improve-success , and I have the full code here: https://github.com/mhuggins/jquery-ui-autocomplete-hints . If you have any suggestions for improvement, I'd love to hear them! – Matt Huggins Dec 04 '11 at 18:31
  • 4
    How to find Namespace and pluginName? – Pablo S G Pacheco May 10 '14 at 01:59
18

I had the same issue and came here, then Jared Scott's answer inspired me.

(function($) {

    var fullCalendarOrg = $.fn.fullCalendar;

    $.fn.fullCalendar = function(options) {
        if(typeof options === "object") {
            options = $.extend(true, options, {
                // locale
                isRTL: false,
                firstDay: 1,
                // some more options
            });
        }

        var args = Array.prototype.slice.call(arguments,0);
        return fullCalendarOrg.apply(this, args);
    }

})(jQuery);
Yasin Uslu
  • 546
  • 6
  • 17
3
$.fn.APluginName=function(param1,param2)
{
  return this.each(function()
    {
      //access element like 
      // var elm=$(this);
    });
}

// sample plugin
$.fn.DoubleWidth=function()
  {
    return this.each(function()
      {
        var _doublWidth=$(this).width() * 2;
        $(this).width(_doubleWidth);
      });
  }

//

<div style="width:200px" id='div!'>some text</div>

// using custom plugin

$('#div1').DoubleWidth();

/// above written type of utils usually work of dom elements /////////////// custom utils

(function($){
  var _someLocalVar;
  $.Afunction=function(param1,param2) {
    // do something
  }
})(jquery);

// access above util as

$.Afunction();

// this type of utils usually extend javascript

Wei Liu
  • 555
  • 8
  • 24
Praveen Prasad
  • 31,561
  • 18
  • 73
  • 106
  • 1
    Thats not what hes asking - hes asking how best to extend an already existing plugin in a way that allows for updating the underlying plugin hes using as the base while adding the functionality he wants on top of it. – prodigitalson Jan 12 '10 at 18:13
3

Ive found that with a lot of plugins the methods are protected/private (ie in the closures scope). If yo need to modify the functionality of the methods/functions then your out of luck unless youre willing to fork it. Now if you dont need to change any of these methods/functions then you can use $.extend($.fn.pluginName, {/*your methods/properties*/};

Another thing ive ended up doing before is simply using the plugin as a property of my plugin instead of trying to extend it.

What it all really comes down to is how the plugin you want to extend is coded.

prodigitalson
  • 60,050
  • 10
  • 100
  • 114
  • In the main extension is all I want to do, but in some cases it's things like adding event handlers on DOM elements created inside of the plugin. In other cases, I need to override behavior inside of existing methods. The more I read, the less I see a clean way to do this. Any other thoughts? – justkt Jan 13 '10 at 16:20
  • Well if those mehods are ones in the pubic API (which they dont seem to be) then you could use the method i mentioned above to replace the function definition. Other than that there is no clean way. You will just have to fork it for your uses and hack away. – prodigitalson Jan 13 '10 at 17:35
  • 2
    @prodigitalson public* API ;) – Niks Dec 04 '13 at 09:54
1

My approach in rewriting jQuery plugins has been to move methods and variables that need to be accessed to the options block and call the 'extend'

// in the plugin js file
$.jCal = function (target, opt) {
    opt = $.extend({
       someFunctionWeWantToExpose: function() {
           // 'this' refers to 'opt', which is where are our required members can be found
       }
    }

    // do all sorts of things here to initialize

    return opt; // the plugin initialisation returns an extended options object
}


////// elsewhere /////

var calendar = $("#cal1").jCal();
calendar.someFunctionWeWantToExpose();
hvdd
  • 514
  • 4
  • 7
1

Example similar to Jared Scott`s answer, but making a copy of original object prototype gives the ability to call parent method:

(function($) {

    var original = $.extend(true, {}, $.cg.combogrid.prototype);

    var extension = {
        _renderHeader: function(ul, colModel) {
            original._renderHeader.apply(this, arguments);

            //do something else here...
        }
    };

    $.extend(true, $.cg.combogrid.prototype, extension);

})(jQuery);
marcini
  • 99
  • 1
  • 6
0

jQuery Widget can be extended using jQuery Widget Factory.

(function ($) {
    "use strict";

    define([
        "jquery",
        "widget"
    ], function ($, widget) {
        $.widget("custom.yourWidget", $.fn.fullCalendar, {
            yourFunction: function () {
                // your code here
            }
        });

        return $.custom.yourWidget;
    });
}(jQuery));

Check out jQuery Documentation to learn more:
Widget Factory API
Extending Widgets with the Widget Factory

Max
  • 130
  • 3
  • 10