Looking for jQuery find(..) method that includes the current node

Jquery

Jquery Problem Overview


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.

Jquery Solutions


Solution 1 - Jquery

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')

Solution 2 - Jquery

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.

Solution 3 - Jquery

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.

Solution 4 - Jquery

$('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')

Solution 5 - Jquery

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);

Solution 6 - Jquery

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');

Solution 7 - Jquery

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)

Solution 8 - Jquery

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.

Solution 9 - Jquery

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')

Solution 10 - Jquery

I think andSelf is what you want:

obj.find(selector).andSelf()

Note that this will always add back the current node, whether or not it matches the selector.

Solution 11 - Jquery

If you are strictly looking in the current node(s) the you just simply do

$(html).filter('selector')

Solution 12 - Jquery

Here's the right (but sad) truth:

$(selector).parent().find(oSelector).filter($(selector).find('*'))

http://jsfiddle.net/SergeJcqmn/MeQb8/2/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohn KView Question on Stackoverflow
Solution 1 - JqueryRobertView Answer on Stackoverflow
Solution 2 - JqueryNick CraverView Answer on Stackoverflow
Solution 3 - JqueryDmitriy SintsovView Answer on Stackoverflow
Solution 4 - JqueryTgrView Answer on Stackoverflow
Solution 5 - JqueryerikrestificarView Answer on Stackoverflow
Solution 6 - JquerySeregPieView Answer on Stackoverflow
Solution 7 - JqueryoriadamView Answer on Stackoverflow
Solution 8 - JqueryJustin WarkentinView Answer on Stackoverflow
Solution 9 - JqueryRobert SiemerView Answer on Stackoverflow
Solution 10 - JqueryinterjayView Answer on Stackoverflow
Solution 11 - JquerymikewasmikeView Answer on Stackoverflow
Solution 12 - JquerySergeView Answer on Stackoverflow