James Daly
James Daly

Reputation: 1386

overriding of jQuery .end() method to accept parameters

UPDATE the current solution lives on this gist in case you ever need this type of functionality https://gist.github.com/jdaly13/5581538#file-gistfile1-js

I'm trying a little experimentation where I'm trying to override jQuery's core end method with my own method that just essentially adds functionality to it

for example if you are working with jQuery you might do something like this

$('h1.clickme').click(function () {
     $(this).next('div').css("width", "+=200").parent().next().hide().end().end()
      //this should traverse you back to the div after the h1 clicked
})

I want to override the jQuery end method by adding the ability to add a number parameter for example

.end(1) 

would do the same as

.end().end()

Here is what I have so far

(function(){

// Define overriding method.
jQuery.fn.end = function(no_of_times){
    var prevObject = "prevObject";
    if (!(arguments.length) || (typeof no_of_times !== "number")) {
        return this.prevObject || this.constructor(null);
    } else {
        if (no_of_times == 1) {
            return this.prevObject.prevObject || this.constructor(null)
        } else if (no_of_times == 2) {
            return this.prevObject.prevObject.prevObject || this.constructor(null)  
        } else if (no_of_times == 3) {
            return this.prevObject.prevObject.prevObject.prevObject || this.constructor(null)
        } else {
            //too many times can't type anymore
            return this.prevObject || this.constructor(null);
        }           
    }

}
})()

so I could call something like this

$('.promo-carousel').parent().prev().siblings('span').hide().end(2)

But obviously I don't think it's efficient to write out all those if statements Is there an easier way to do this? I'm sure the performance is about the same but I'm doing this more for readability sake

I thought of appending the prevObject variable with "prevObject" string based on the parameter passed something like this

if (!(arguments.length) || (typeof no_of_times !== "number")) {
            return this.prevObject || this.constructor(null);
        } else {
            for (i=0; i <= no_of_times; i++) {
                pObj += "prevObject."           
            }
            var prevObject = pObj.slice(0, prevObject.length -1)
            console.log(prevObject);
            return this.prevObject
        }

    }

But that snippet of code above didn't work Any help is appreciated as always

Upvotes: 1

Views: 139

Answers (4)

gion_13
gion_13

Reputation: 41533

Here's my solution : http://jsfiddle.net/QVxqY/
You don't have to reimplement any logic or keep track of the previous elements :

(function($){
    var originalEnd = $.fn.end;
    $.fn.end = function(n){
        if(!n)
            return originalEnd.call(this);
        return $.fn.end.call(originalEnd.call(this), n-1);
    }
})(jQuery);

Upvotes: 1

Kevin B
Kevin B

Reputation: 95022

You could just reuse the old method you are overriding:

(function($){
    var oldfn = $.fn.end;
    $.fn.end = function(times){
        times = times || 1; // default to 1 if nothing or 0 is passed in
        var ret = this;
        for (i=0;i<times;i++) {
            ret = oldfn.call(ret);
        }
        return ret;
    };
})(jQuery);

Upvotes: 0

droidpl
droidpl

Reputation: 5892

Something similar should work.

var prevObject = this.prevObject;
for(i = 0; i<no_of_times; i++) {
    prevObject = prevObject.prevObject;
}
return prevObject || this.constructor(null);

Upvotes: 1

Elliot Bonneville
Elliot Bonneville

Reputation: 53311

This should do the trick:

var prevObject = this.prevObject;

for(i = 1; i<no_of_times; i++) {
    prevObject = prevObject.prevObject;
    if(!prevObject) {
        prevObject = this.constructor(null);
        break
    }
}

Just get the prevObject of the prevObject each iteration of the loop, until prevObject is not found.

Upvotes: 2

Related Questions