35

One can use matchedset.find(selector) / matchedset.parents(selector) to get the descendants/ancestors of the current matched set filtered by a selector, but that doesn't include the matched set itself (if it happens to match the selector too). Is there a better (more concise and/or faster) way to get it than

matchedset.find(selector).add(matchedset.filter(selector))

and the respective for parents() ?

gsakkis
  • 1,569
  • 1
  • 15
  • 24

5 Answers5

45

You can do this:

matchedset.find('*').andSelf().filter(selector);

For parents:

matchedset.parents('*').andSelf().filter(selector);
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • Which is better? `.find('*')` or `.contents()` like in: http://stackoverflow.com/questions/364791/jquery-select-descendants-including-the-parent – Joe Sep 11 '12 at 19:55
  • 10
    Probably a good idea to note that andSelf is now deprecated and has been replaced with addBack() which also accepts a selector. http://api.jquery.com/addBack/ – Chris Spittles Feb 14 '13 at 09:07
17

I think your method is efficient in terms of execution time, but what you're probably asking for is syntactic sugar. For that, you could wrap it into a plugin:

  jQuery.fn.findAndSelf = function(selector) {
    return this.find(selector).add(this.filter(selector))
  }

Then use it like this:

$('.whatever').findAndSelf('.awesome')

If you wanted to get fancy you could create a plugin that works not only for 'find' but for 'parents' and 'children' and other selector-based plugins:

  jQuery.fn.withSelf = function(plugin, selector) {
    return this[plugin](selector).add(this.filter(selector))
  }

Then you'd supply as the first argument the traversal plugin you want to call:

$('.whatever').withSelf('find', '.awesome')
$('.whatever').withSelf('parents', '.awesome')

Just for kicks, another fun plugin that lets you call an arbitrary number of traversal plugins all at once:

  jQuery.fn.traverse = function(plugins, selector) {
    var set = new jQuery();
    $.each(plugins, function(i, val) {
      set.add(this[val](selector));
    }
    return set
  }

You could invoke this one with any combination of selector-based plugins, as follows:

$('.whatever').traverse(['find','filter'], '.awesome')
$('.whatever').traverse(['parents','find'], '.awesome')
$('.whatever').traverse(['parents', 'filter'], '.awesome')
Jeoff Wilks
  • 363
  • 3
  • 7
2

While Jeoff's solution is nice, sometimes it's nice to be able to iterate all the elements, including itself without a selector. This add-on is a bit more flexible:

$.fn.all = function(selector) {
    if(selector===window.undefined) return this.find('*').andSelf();
    return this.filter(selector).add(this.find(selector));
};
mpen
  • 272,448
  • 266
  • 850
  • 1,236
0

For parents you have closest(selector)

m0she
  • 444
  • 1
  • 4
  • 9
0

Look up the "andSelf()" function.

Pointy
  • 405,095
  • 59
  • 585
  • 614