A jQuery find that also finds the root element — Daniel Nouri's Blog
March 14, 2011 | categories: jQuery, Web, Python, JavaScript, Programming | 5 Comments
jQuery's find method is arguably the most used method in jQuery applications. Yet, when using .find() recently, I found out that it makes a rather weird exception for root element(s) of a document, that is, it ignores them.
Consider this example from the comments in the find API:
'<div id="one"><div id="two"></div></div>'"#one"
el will be empty here, because <div id="one"> is the root element. It would work if the element were nested inside, say, another div.
In a recent project that uses .find() to apply progressive enhancement to parts of the page that have been updated through Ajax, this became a pain.
Consider this success callback function that
- replaces parts of the page with updated content from the server
- re-enables Ajax forms on the updated content
function success
"#content"replaceWith
enableAjaxForms"#content"
function enableAjaxForms
"form.ajax"ajaxForm
success success
As long as the server returns a document with a form that's not the root element, this will work. But when we return HTML that has a form element as the root, our enableAjaxForms function will silently fail to find the form:
<form class="ajax" <!-- form.ajax is root, .find() won't find it --> <div> ... </div> </form>
What do? There's another function in jQuery that filters on the root elements. It's called .filter() and finds only the root elements. So this will work:
'<div id="one"><div id="two"></div></div>'filter"#one"
To get the results we want, we need to combine .filter() and .find(). We don't care whether the element we're looking for is at the root or not.
So here's a rather simple implementation of a jQuery.find2 method that'll return both root and child elements as the result of our query:
find2 functionselector
return filterselectorselector
And finally, this is how you would use it. That is, just like you use .find() really:
'<div class="one"><div class="one"></div></div>' find2".one" // will match both divs