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...
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
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.
Jquery .selector is deprecated, it's better to remeber string with selector value to some variable at the moment when you assign
function someModule($selector, selectorText) {
var $moduleSelector = $selector;
var moduleSelectorText = selectorText;
var onSelectorRefresh = function() {
$moduleSelector = $(moduleSelectorText);
}
}
https://api.jquery.com/selector/
If you use remove()
it will remove only a part of the DOM but not all the children or related, instead if you use empty()
on the element the problem is gone.
E.G.:
$('#parent .child).find('#foo').empty();
Maybe it can be useful to someone!