6

Let's assume we have this HTML structure:

<div id='test-div'>
    <div class='random-class-1'>
        <div class='useless-element-1'>
        </div>
        <div class='useless-element-2'>
        </div>
        <p>Just a paragraph, and useless</p>
    </div>
    <div class='random-class-2'>
        <div class='useless-element-3'>
        </div>
        <div class='useless-element-4'>
        </div>
        <div class='useless-element-5'>
        </div>
    </div>
</div>

I need to select all children "DIV elements" (not grandchildren) inside the first DIV (in this example with id='test-div'), not from document but from element (div) itself.

So, I don't want to use the "query" below because I already have selected the element DIV [object HTMLDivElement]:

// I don't want to use this query
var children = document.querySelectorAll("div > div");

Just an example to achieve this (https://jsfiddle.net/t4gxt65k/):

// I already have selected DIV element 
var el = document.getElementById("test-div")
// OR var el = document.querySelectorAll("#test-div");

var children = el.querySelectorAll(":scope > div");

But because of browser incompatibility I don't want to use ":scope"

The real question is:

How can I get the children (only DIV elements) of [object HTMLDivElement] using pure JavaScript?

h2odev
  • 634
  • 9
  • 21
  • Please comment me if the question is not understandable :) – h2odev Feb 08 '17 at 23:13
  • Could you not then again go in and do: `var children = document.querySelectorAll("#test-div > div")` –  Feb 08 '17 at 23:14
  • This is OK for this example but in real application the DIV doesn't have an ID and I have only [object HTMLDivElement] – h2odev Feb 08 '17 at 23:16
  • Consider this: you have only the result from document.getElementById("test-div") – h2odev Feb 08 '17 at 23:17
  • Thats a good point. I just found out you can actually access you own direct element so what you could do is for example in the case of a select `var options = select.querySelectorAll("select > option");`. But in the case of multiple divs I'm not totally sure –  Feb 08 '17 at 23:20
  • That's my problem. It works with :scope as shown on example but don't like it. – h2odev Feb 08 '17 at 23:24
  • 1
    There's a [polyfill](http://stackoverflow.com/a/17989803/367865) for `:scope` in conjunction with `.querySelectorAll()`. – Ouroborus Feb 08 '17 at 23:51
  • Yeah, Marat also posted a similar example. Thanks – h2odev Feb 09 '17 at 00:00

3 Answers3

5

As an option, you could set a temporary unique attribute for your scope element, and then use querySelectorAll() for its parent with the attribute selector prepended to what you would place after the :scope selector:

// The `scope` variable stores a reference to the scope element.
var attrName = '_scope'  + Date.now();
scope.setAttribute(attrName, '');
var children = scope.parentNode.querySelector('[' + attrName + '] > DIV');

I’m not sure about how fast it is though.

Fwiw, specifically for getting child elements, there is the children DOM property:

var children = scope.children;
Marat Tanalin
  • 13,927
  • 1
  • 36
  • 52
3

To get direct children of an element use a combination of parentNode.children or parentNode.childNodes, and Array.prototype.reduce like this:

var children = Array.prototype.reduce.call(el.children, function(acc, e) {
    if(e.tagName == "DIV")
        acc.push(e);
    return acc;
}, []);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
2

Similar to @Ibrahims answer in selecting children but less complicated since it does not address prototype and reduce. Instead it uses Array.from, Array.filter and Element.matches. Element.matches makes it more versatile since it uses a normal selector string (as you would in querySelectorAll).

Array.from(rootElement.children)
  .filter(elm => elm.matches('div'))

const rootElement = document.getElementById('test-div')

Array.from(rootElement.children)
  .filter(elm=>elm.matches('div'))
  .forEach(elm=>elm.classList.add('matched'))
div {
  padding: 1rem;
  box-shadow: 0 0 0 1px gray inset;
}
.matched {
  box-shadow: 0 0 0 1px red inset;
}
<div id='test-div'>
    <div class='random-class-1'>
        <div class='useless-element-1'></div>
        <div class='useless-element-2'></div>
        <p>Just a paragraph, and useless</p>
    </div>
    <div class='random-class-2'>
        <div class='useless-element-3'></div>
        <div class='useless-element-4'></div>
        <div class='useless-element-5'></div>
    </div>
</div>
Sjeiti
  • 2,468
  • 1
  • 31
  • 33