2

I'm wondering what the best way is to find children of an element in jQuery, but also include the parent in the 'find'.

Here's my simplified basic HTML setup:

<div id="container">
    <form id="form1"> <!-- form 1 content --> </form>
    <form id="form2"> <!-- form 2 content --> </form>
</div>

And I want a function like this...

function getForms ($container) 
{
    // Option 1
    var $allForms = $container.find('form').andSelf().filter('form');

    // Option 2
    var $allForms = $container.find('form');
    if ($container.is('form')) $allForms.add($container);

    // Should return all the forms in the container if passed $('#container')
    // Or return just one form if passed $('#form1')
    return $allForms;
}

I'm fairly certain that both option 1 or 2 will work. Does anyone know which option above is more efficient? Are there other options which are more elegant or more efficient?

EDIT: I wasn't happy with the .is() in option 2 because it didn't work when the container had multiple jQuery objects in it. So I came up with something like this:

// Option 3
function getContainerElements ($container, selector) {
    return $container.find(selector).add($container.filter(selector));
}

I haven't tested it too much, but I think it'll work for all general cases.

Luke
  • 14,840
  • 10
  • 84
  • 92
  • 2
    This might fit better over on http://codereview.stackexchange.com/ – j08691 Oct 26 '12 at 20:37
  • 1
    My guess (without actually benchmarking it) would be #2 is more efficient. In #1 you are adding the container, and then filtering the whole list and *potentially* removing it again. Option #2 check it before adding it and doesn't have to filter the list again to remove it. – Matt Burland Oct 26 '12 at 20:41
  • `var $allForms = $container.find('form').andSelf()` – SpYk3HH Oct 26 '12 at 20:41
  • 1
    @SpYk3HH: I think the point is that `$container` may or may not be a form. – Matt Burland Oct 26 '12 at 20:44
  • @Luke, are the `
    ` elements always immediate children of `$container`, or do you want to also support descendants?
    – Frédéric Hamidi Oct 26 '12 at 20:45
  • @MattBurland It would'nt matter if it is a form or not, he said he wanted all child elements (forms) and self. Thus, the filter is unnecessary. – SpYk3HH Oct 26 '12 at 20:45
  • Thanks! It's too bad that *andSelf* didn't take in a selector as an argument which acted like a filter. Then we could have `var $allForms = $container.find('form').andSelf('form')`. – Luke Oct 26 '12 at 20:52
  • @Luke, I have a solution that approximates that, but it works best if the `
    ` elements are direct children of the container. Is it the case?
    – Frédéric Hamidi Oct 26 '12 at 20:53
  • @FrédéricHamidi - I would like it so that the
    s can be any descendants of the container. In fact you could call it like `getForms($('body'))` to get all forms on the page, wherever they might be.
    – Luke Oct 26 '12 at 20:55
  • @Luke, ah, that's too bad. I suppose forms can also be nested more than two levels deep (e.g. you can have a form containing a form containing a form)? – Frédéric Hamidi Oct 26 '12 at 20:56
  • In this case, forms shouldn't be nested ([link](http://stackoverflow.com/questions/379610/can-you-nest-html-forms) ), but this could be generalized for other tags that can be nested. – Luke Oct 26 '12 at 21:05
  • Then I can think of nothing more efficient than your second solution (provided you fix it, see my comment under bukfixart's answer). – Frédéric Hamidi Oct 26 '12 at 21:07
  • Would this also work? `$allForms = $container.parent().find('form')` – Luke Oct 26 '12 at 21:23
  • @Luke, it would also match `$container`'s sibling forms, and it would not work if `$container` is the `` element (which does not have a parent). Even if this still meets your requirements, it might prove less efficient than your second option if `$container` has a lot of siblings who have a lot of descendants. – Frédéric Hamidi Oct 26 '12 at 21:34
  • *Rectification:* My last comment was partially wrong, the parent of the `` element is the `document`, which can be wrapped by jQuery, so the solution would not work if `$container` is `$(document)` instead. My apologies for the mistake. – Frédéric Hamidi Oct 26 '12 at 21:44
  • Your title has got little to do with the actual question. You seem to want a selector then go on to ask for performance graphs... which is it? – PandaWood Aug 06 '15 at 05:46

1 Answers1

1

Option 2 is better according to JSPerf tests (Tested in Chrome on linux)

You can see the results here and the tests if you want to try it in different browsers: http://jsperf.com/children-and-self

Note: I've updated this test to use divs instead of forms (because forms inside other forms don't work: Form inside a form, is that alright?) and we want to test the case where the parent should be added to get the real performance impact as per comment below

enter image description here

EDIT

Added third option performance as requested in comment

Community
  • 1
  • 1
Craig MacGregor
  • 4,319
  • 1
  • 18
  • 13
  • 1
    But in your test the container is never a form, so the `if` block never gets executed. It's an unfair comparison, I think. – pimvdb Oct 26 '12 at 21:10
  • @pimvdb Thanks that's very true. Must be Friday! Also forms cannot be nested so it probably better to use a different example since the title is about self and children, not specific to form elements. I'll update the tests... – Craig MacGregor Oct 26 '12 at 21:23
  • @CraigMacGregor - Would you be able to test my Option 3 in the edit above? I really appreciate the benchmarking tests. – Luke Oct 30 '12 at 22:14
  • @pimvdb I've added the third option for you. Enjoy :) – Craig MacGregor Oct 31 '12 at 13:21
  • Sorry, for someone reading this question looking for an independent answer, this is not it. The selector to answer the question is... ? – PandaWood Aug 06 '15 at 05:44