Search code examples
jqueryjquery-pluginsthischaining

why does a jquery plugin chained without parentheses return the function instead of obj for This?


I am creating a basic jquery plugin, I've already wrote some and quite familiar with it, but for expanding my plugin and adding some other methods to it, I like to use a dot like this:

$.fn.myplugin = function () {

};

$.fn.myplugin.render = function () {
    alert("hi");
    alert(this);
};

$("#test").myplugin.render();

the problem is that this returns the function instead of my jquery object, hmmm? any explanation or workaround? I don't want to change to myplugin_render or call myplugin().render()

jsfiddle demo


Solution

  • You can achive this by defining your plugin to be a property with a custom getter that will return plugin instance with all its methods binded to the original jQuery instance. Beware this method has a few downsides:

    • This wont work in IE<9. And there is no way to polyfill this syntax.
    • It will create a new plugin object on every call. Might be a performance issue.

    Working example http://jsfiddle.net/tarabyte/6LXLU/6/

    (function ($) {
        var methods = { //methods and properties you want
            render: function() {        
                alert(this[0].outerHTML);
            },
            log: function() {
                console.log(this);
            }
        },
            makePlugin = function(ctx) {
                var result = {}, name, value;
    
                for(name in methods) { //copy all properties
                    value = methods[name];
                    if('function' == typeof value) { //bind functions to current ctx.
                        value = $.proxy(value, ctx); //or value.bind(ctx) :)    
                    }
                    result[name] = value;                    
                }
    
                return result;
            };
        Object.defineProperty($.fn, 'myplugin', { //define a readonly property
            get: function() {
                return makePlugin(this); //create a binded copy of the plugin           
            }
        });
    })(jQuery);
    
    $("#test").myplugin.render(); 
    $("#test").myplugin.log();