Reputation: 28869
The jQuery find(..) traversal method doesn't include the current node - it starts with the children of the current node. What is the best way to call a find operation that includes the current node in its matching algorithm? Looking through the docs nothing immediately jumps out at me.
Upvotes: 153
Views: 36392
Reputation: 6810
For jQuery 1.8 and up, you can use .addBack()
. It takes a selector so you don't need to filter the result:
object.find('selector').addBack('selector')
Prior to jQuery 1.8 you were stuck with .andSelf()
, (now deprecated and removed) which then needed filtering:
object.find('selector').andSelf().filter('selector')
Upvotes: 171
Reputation: 34697
I was trying to find a solution which does not repeat itself (i.e. not entering the same selector twice).
And this tiny jQuery extention does it:
jQuery.fn.findWithSelf = function(...args) {
return this.pushStack(this.find(...args).add(this.filter(...args)));
};
It combines find()
(only descendants) with filter()
(only current set) and supports whatever arguments both eat. The pushStack()
allows for .end()
to work as expected.
Use like this:
$(element).findWithSelf('.target')
Upvotes: 2
Reputation: 4159
Define
$.fn.findSelf = function(selector) {
var result = this.find(selector);
this.each(function() {
if ($(this).is(selector)) {
result.add($(this));
}
});
return result;
};
then use
$.findSelf(selector);
instead of
$find(selector);
Sadly jQuery does not have this built-in. Really strange for so many years of development. My AJAX handlers weren't applied to some top elements due to how .find() works.
Upvotes: 10
Reputation: 8559
In case you are looking for exactly one element, either current element or one inside it, you can use:
result = elem.is(selector) ? elem : elem.find(selector);
In case you are looking for multiple elements you can use:
result = elem.filter(selector).add(elem.find(selector));
The use of andSelf
/andBack
is pretty rare, not sure why. Perhaps because of the performance issues some guys mentioned before me.
(I now noticed that Tgr already gave that second solution)
Upvotes: 3
Reputation: 388
If you are strictly looking in the current node(s) the you just simply do
$(html).filter('selector')
Upvotes: 1
Reputation: 1253
If you want the chaining to work properly use the snippet below.
$.fn.findBack = function(expr) {
var r = this.find(expr);
if (this.is(expr)) r = r.add(this);
return this.pushStack(r);
};
After the call of the end function it returns the #foo element.
$('#foo')
.findBack('.red')
.css('color', 'red')
.end()
.removeAttr('id');
Without defining extra plugins, you are stuck with this.
$('#foo')
.find('.red')
.addBack('.red')
.css('color', 'red')
.end()
.end()
.removeAttr('id');
Upvotes: 3
Reputation: 51
The accepted answer is very inefficient and filters the set of elements that are already matched.
//find descendants that match the selector
var $selection = $context.find(selector);
//filter the parent/context based on the selector and add it
$selection = $selection.add($context.filter(selector);
Upvotes: 5
Reputation: 6692
Here's the right (but sad) truth:
$(selector).parent().find(oSelector).filter($(selector).find('*'))
http://jsfiddle.net/SergeJcqmn/MeQb8/2/
Upvotes: -2
Reputation: 10241
I know this is an old question, but there's a more correct way. If order is important, for example when you're matching a selector like :first
, I wrote up a little function that will return the exact same result as if find()
actually included the current set of elements:
$.fn.findAll = function(selector) {
var $result = $();
for(var i = 0; i < this.length; i++) {
$result = $result.add(this.eq(i).filter(selector));
$result = $result.add(this.eq(i).find(selector));
}
return $result.filter(selector);
};
It's not going to be efficient by any means, but it's the best I've come up with to maintain proper order.
Upvotes: 3
Reputation: 28160
$('selector').find('otherSelector').add($('selector').filter('otherSelector'))
You can store $('selector')
in a variable for speedup. You can even write a custom function for this if you need it a lot:
$.fn.andFind = function(expr) {
return this.find(expr).add(this.filter(expr));
};
$('selector').andFind('otherSelector')
Upvotes: 5
Reputation: 630409
You can't do this directly, the closest I can think of is using .andSelf()
and calling .filter()
, like this:
$(selector).find(oSelector).andSelf().filter(oSelector)
//or...
$(selector).find('*').andSelf().filter(oSelector);
Unfortunately .andSelf()
doesn't take a selector, which would be handy.
Upvotes: 41