How can I refresh a stored and snapshotted jquery selector variable

25,809

Solution 1

Yeah, it's a snapshot. Furthermore, removing an element from the page DOM tree isn't magically going to vanish all references to the element.

You can refresh it like so:

var a = $(".elem");

a = $(a.selector);

Mini-plugin:

$.fn.refresh = function() {
    return $(this.selector);
};

var a = $(".elem");

a = a.refresh();

This simple solution doesn't work with complex traversals though. You are going to have to make a parser for the .selector property to refresh the snapshot for those.

The format is like:

$("body").find("div").next(".sibling").prevAll().siblings().selector
//"body div.next(.sibling).prevAll().siblings()"

In-place mini-plugin:

$.fn.refresh = function() {
    var elems = $(this.selector);
    this.splice(0, this.length);
    this.push.apply( this, elems );
    return this;
};

var a = $(".elem");
a.refresh() //No assignment necessary

Solution 2

I also liked @Esailija solution, but seems that this.selector has some bugs with filter. So I modified to my needs, maybe it will be useful to someone

This was for jQuery 1.7.2 didn`t test refresh on filtered snapshots on higher versions

$.fn.refresh = function() { // refresh seletor
    var m = this.selector.match(/\.filter\([.\S+\d?(\,\s2)]*\)/); // catch filter string
    var elems = null;
    if (m != null) { // if no filter, then do the evarage workflow
        var filter = m[0].match(/\([.\S+\d?(\,\s2)]*\)/)[0].replace(/[\(\)']+/g,'');
        this.selector = this.selector.replace(m[0],''); // remove filter from selector
        elems = $(this.selector).filter(filter); // enable filter for it
    } else {
        elems = $(this.selector);
    }
    this.splice(0, this.length);
    this.push.apply( this, elems );
    return this;
};

Code is not so beautiful, but it worked for my filtered selectors.

Solution 3

Clean and generic solution worked properly with jQuery 3.4.1:

My solution is to do the following:

  1. Intercept the selector at the time of jQuery object initialization and in the same time maintain all other jQuery functionalities transparently all this using inheritance
  2. Build refresh plugin that make use of the new "selector" property we added during initialization

Definition:

$ = (function (originalJQuery) 
{
    return (function () 
    {
        var newJQuery = originalJQuery.apply(this, arguments);
        newJQuery.selector = arguments.length > 0 ? arguments[0] : null;
        return newJQuery;
    });
})($);

$.fn = $.prototype = jQuery.fn;

$.fn.refresh = function () 
{
    if (this.selector != null && (typeof this.selector === 'string' || this.selector instanceof String))
    {
        var elems = $(this.selector);
        this.splice(0, this.length);
        this.push.apply(this, elems);
    }
    return this;
};

Usage:

var myAnchors = $('p > a');
//Manipulate your DOM and make changes to be captured by the refresh plugin....
myAnchors.refresh();
//Now, myAnchors variable will hold a fresh snapshot 

Note: As optimization, object selectors don't need refresh as they are pass by reference by nature so, in refresh plugin, we only refresh if the selector is a string selector not object selector for clarification, consider the following code:

// Define a plain object
var foo = { foo: "bar", hello: "world" };
 
// Pass it to the jQuery function
var $foo = $( foo );
 
// Test accessing property values
var test1 = $foo.prop( "foo" ); // bar

// Change the original object
foo.foo = "koko";

// Test updated property value
var test2 = $foo.prop( "foo" ); // koko
Share:
25,809
Admin
Author by

Admin

Updated on April 14, 2021

Comments

  • Admin
    Admin about 3 years

    I ran yesterday in a problem with a jquery-selector I assigned to a variable and it's driving me mad.

    Here is a jsfiddle with testcase:

    • assign the .elem to my obj var
    • log both lengths to the console. Result => 4
    • Remove #3 from the DOM
    • log obj to the console => the removed #3 is still there and the length is still 4. I figured out that jquery query is snapshotted? to the variable and can't?won't? be updated
    • log .elem to the console.. yep Result => 3 and the #3 is gone
    • Now I update .elem with a new width of 300
    • logging obj & obj.width gives me 300.. So the snapshot has been updated ? What's interesting is that 3 of the 4 divs have the new width, but the removed #3 doesn't...

    Another test: Adding a li element to the domtree and logging obj and .elem. .elem does have the new li and obj doesn't, because it's still the old snapshot

    http://jsfiddle.net/CBDUK/1/

    Is there no way to update this obj with the new content? I don't want to make a new obj, because in my application there is a lot information saved in that object, I don't want to destroy...