views:

43

answers:

2

Hi all:

Does anyone know how to tell if a cached jQuery object has gone stale, e.g. is no longer in the DOM? For example:

var $cached_elem = $('.the_button');

// .. and then later

$cached_elem.text('updating...');

I have recently encountered the situation where the $cached_elem is removed from the DOM due to some other event. So what I would like to do:

if ( $cache_elem.isStillInDOM() ){
  // now do time consuming stuff with $cached_elem in DOM 
}

Before anyone offers, I have already employed this, which is a fair analog for what I'm trying to do:

if ( $cached_elem.is(':visible') === true ){ ... }

However, this is not really the same thing and could fail in some cases.

So can anyone think of a simple way to check directly if a cached jQuery object is "stale"? I may be forced to write a plugin if not ...

A: 

If the selector hasn't changed, just reinitialize it:

var $cached_elem = $('.the_button');
// code that might remove some elements of $cached_elem
$cached_elem = $('.the_button');

If you want to avoid duplicating the selector string, use the selector property of the original jQuery object:

var $cached_elem = $('.the_button');
// code that might remove some elements of $cached_elem
$cached_elem = $($cached_elem.selector);
if ($cached_elem.length) {
  // element still exists
}
Jimmy Cuadra
Yes, of course. But we're not using jQuery like that. We want to define the selector once, and then not worry about the original selector method for a number of good reasons. Examples include needing to refactor the caching mecha mechanism or the ability to introduce errors when the selector is duplicated in two or more places. Better if we could just say if $cached_elem.isStillInDOM() ) or if ( $cached_elem.isStale() ){...
Michael Mikowski
Why not just use a variable for the selector then? That way, if you need to change it in the future, there's no risk of forgetting to change one occurrence of it. You could even use the selector property of the original jQuery object: `$cached_elem = $($cached_elem.selector);`
Jimmy Cuadra
Aha! That's the property I'm looking for, I think. So would this work: if ( $($cached_elem).selector).length < 1 ){ .... }?
Michael Mikowski
Your first closing paren is in the wrong place, but otherwise, yes. `if ($($cached_elem.selector).length) { // element still exists }` I have updated my answer to show this.
Jimmy Cuadra
+2  A: 

if($elem.closest('body').length > 0) seems like it could do the trick.

jsFiddle example

Edit: Updated in response to Yi Jiang's comment so that it will return correctly if its parent element is removed

Edit 2: Updated in response to lonesomeday's comment - changed parents() to 'closest()` for performance improvement

Steve Greatrex
But what if I, say, remove the *parent* of the element? What you need to do I think is to detect if `body` is still one of the parent of the element in question, like this: http://jsfiddle.net/D9L8M/1/
Yi Jiang
Good point - code updated to reflect that
Steve Greatrex
`$elem.closest('body').length` should be that little bit faster. You could also select on `'html`' if you were removing, say, a `link` element from the `head`.
lonesomeday
@lonesomeday - updated; @Yi Jiang - sorry about getting the name wrong! ;)
Steve Greatrex
I like this too. Thanks!
Michael Mikowski
@Michael Mikowski - if it solved your problem, can you accept that answer?
Steve Greatrex
@Steve Greatex answer accepted, although the other answer is also quite intriguing. However, this seems "cleaner".
Michael Mikowski