5

How to write chainable functions but do not pollute $.fn ? Write functions only for using inside my plugin. Is it possible?

$('.myclass').makeSomething().andOneMoreFunction().andLast();

It is correct approach?

UPD. The best solution in my case is extension method:

String.prototype.getMyLength = function(){return this.length;}

And now I can apply this function to any string like this:

var mystring = "test";
mystring.getMyLength();

Or

"teststring".getMyLength()

And make it chainable:

String.prototype.getMe = function(){return this;}
"string".getMe().getMe().getMe().getMe().getMe();

Thanks for answers!

Roman Bats
  • 1,775
  • 3
  • 30
  • 40

3 Answers3

5

You can chain all you want. If you define a $.fn yourself it is important that you return this at the end of you function.

If you want to write some javascript yourself you can also chain! It just depends on what you return. So if you return some other object, you can chain on from that object. The return value is used for this.

Example

var obj = {
    test : function(){ 
        alert("Y"); 
        return this; 
    },
    test2 : function(){ 
        alert("2"); 
        return this; 
    }
}
obj.test().test2(); // And so on since it returns this

jQuery Plugin API

$.fn.test = function(){
    var methods = {
        method0 : function(){
            alert("method0");
            return this;
        }
    };
    return methods;
}
var api = $("obj").test(); // Returns methods
api.method0(); // Calling a function from the returned methods.
// OR
$("obj").test().method0();

Above function is not jQuery chainable anymore. So you can't use the $("obj").test().addClass("test") because you return your own API!

Niels
  • 48,601
  • 4
  • 62
  • 81
  • 1
    But the question is 'how to do it without polluting `$.fn`'. I think that is very reasonable if you want to use those functions only internally in your plugin and want to avoid name clashes. – 11684 Feb 22 '13 at 17:02
  • 1
    Consider [`console.log` over `alert`](http://stackoverflow.com/q/8203473/1615483) – Paul S. Feb 22 '13 at 17:06
  • 1
    Does my example 2 answer the question? I've given 2 examples of using chaining. The second returns an API. So can also be used this way internally. Only depends on your return value. @PaulS. this is just psuedo code. – Niels Feb 22 '13 at 17:07
3

You can avoid pollution by using the first parameter of your plugin's function to specify the method of choice; for instance

(function () {
    var o = { // object holding your methods
        'bar': function () {console.log('bar', this); return this;},
        'foobar': function () {console.log('foobar', this); return this;}
    };
    $.fn.foo = function (method /*, args*/) {
        return o[method].apply(
            this,
            Array.prototype.slice.call(arguments, 1) // pass your args
        );
    };
}());

and then

$('something').foo('bar').foo('foobar');
/*
bar, thisobj
foobar, thisobj
*/

This way you keep access to the jQuery object as normal, too.

Paul S.
  • 64,864
  • 9
  • 122
  • 138
0

When you call a.foo(), the function foo is invoked with this set to a. You can use this to your advantage.

Also recall that the expression a.foo() evaluates to whatever you returnd from within the function.

So, just return this.

Then a.foo() evaluates back to a, and (a.foo()).bar() becomes equivalent to calling a.foo() then calling a.bar()... i.e. chained operations on a!

$.fn is not particularly magical — it simply uses the above logic in the same way that you are about to.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055