5

How can I copy the stack of a jQuery object to another jQuery object, so I can use end in my plugins even when returning totally unrelated objects? Example:

$(myselector)
    .next()             // Destructive operation
        .doSomething()
    .end()              // Goes back to "myselector"
    .doSomethingElse(); // Works fine!

$.fn.myPlugin = function() {
    return $(unrelated); // No stack, can't call "end" on it
};

$(myselector)
    .myPlugin()         // Destructive operation
        .doSomething()
    .end()              // Goes back to nowhere, since the stack is empty
    .doSomethingElse(); // Doesn't work

I'd like to modify the $(unrelated) object to include this's stack, so the second example would work. Here's a complete example in jsFiddle.

mgibsonbr
  • 21,755
  • 7
  • 70
  • 112
  • 1
    http://api.jquery.com/pushStack/ – zzzzBov Feb 06 '12 at 01:13
  • @zzzzBov Internals! Didn't even know this category existed in the api... Only looked at [api.jquery.com/end/](http://api.jquery.com/end/) and related, and having found no useful reference to "stack", gave up! Thanks – mgibsonbr Feb 06 '12 at 01:37

3 Answers3

2
$.fn.myPlugin = function(related) {
    if ( related == "getRelated" )
        return this.pushStack($(this.data("related")).get()); // Want to preserve stack
    return this.data("related",related);
};

You need to push the element to the stack so that end() gets back to it.

Bruno Silva
  • 3,077
  • 18
  • 20
  • Thanks, `pushStack` worked fine! But why the `get`, is it really necessary? (my example is jsFiddle worked both with and without it) – mgibsonbr Feb 06 '12 at 01:13
  • 1
    I added get() because, without get(), it would be the same as doing something like $($(domElement)) which will return the same as $(domElement). – Bruno Silva Feb 06 '12 at 01:21
  • Oh, I get it, this is to prevent the original object being modified (in case I'm relying on its stack in other parts of the code), right? Haven't thought about that, thanks! (although in this example it's unnecessary, since it's not a domElement but a selector that's stored in data; but it's good to be aware of that possibility) – mgibsonbr Feb 06 '12 at 01:29
0

To me it looks like the way you are writing the plugin disturbs the logic of jQuery since you are returning something that jQuery might not expect. That is just a guess though, since I do not know jQuery well at all.

Maybe you can do what you want in .doSomething() instead?

Leo
  • 4,136
  • 6
  • 48
  • 72
  • AFAIK jQuery doesn't rely on `end` in its methods, it's more for user convenience. It allows chaining invocation in a way that comes close to declarative syntax. So, what I want to do doesn't "break" anything, just extends it in unforeseen ways... – mgibsonbr Feb 06 '12 at 01:24
0

If you look at the data on $( '#a' ) it's just a string saying '#c' not an actual jQuery Object. I updated the code for you http://jsfiddle.net/89gkD/3/

whitneyit
  • 1,226
  • 8
  • 17
  • Thanks, but notice how I wrap it in `$()` before I return it. (The proof that it works this way is that C actually turned green - it's the `end` that didn't work) Anyway, that was just an example, a practical use of this technique might return just about anything (for instance: an id-less element dynamically created by the plugin and unrelated to it in the DOM). – mgibsonbr Feb 06 '12 at 01:18