0

When all of the children are 'li' elements, why doesn't this.el.children work when this.el.querySelectorAll('li'); does?

For example:

function RadioGroup(id) {
this.el = document.querySelector(id);
this.buttons = slice(this.el.querySelectorAll('.radio'));
this.focusedIdx = 0;
this.focusedButton = this.buttons[this.focusedIdx];

this.el.addEventListener('keydown', this.handleKeyDown.bind(this));
this.el.addEventListener('click', this.handleClick.bind(this));

this.el.setAttribute('role', 'radiogroup');

// This works
this.el.querySelectorAll('li').forEach(function (item){
  item.setAttribute('role', 'radio');
});

// But this doesn't
this.el.children.forEach(function (item){
  item.setAttribute('role', 'radio');
});
}

Where this is the HTML:

  <ul id="group1" class="radiogroup">
    <li class="radio">Water</li>
    <li class="radio">Tea</li>
    <li class="radio">Coffee</li>
    <li class="radio">Cola</li>
    <li class="radio">Ginger Ale</li>
  </ul>
  • Because `HTMLCollection`s don’t have a `forEach` method. Use the [browser console (dev tools)](https://webmasters.stackexchange.com/q/8525) (hit `F12`) and read any errors. – Sebastian Simon Jul 25 '18 at 20:04
  • Possible duplicate of [Why is forEach not working for children?](https://stackoverflow.com/questions/15094886/why-is-foreach-not-working-for-children) – Sebastian Simon Jul 25 '18 at 20:04
  • We could probably also say that any time someone is learning the difference betw a nodelist and an HTMLCollection, it is a duplicate of that question. Thanks though! – anthonyCarton Jul 25 '18 at 21:25

2 Answers2

1

Element.querySelectorAll returns a NodeList which does contain the forEach method, where as Node.children is an HTMLCollection and does not contain forEach.

[1] https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
[2] https://developer.mozilla.org/en-US/docs/Web/API/NodeList

[3] https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/children
[4] https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection

Meghan
  • 1,215
  • 11
  • 17
1

With ES6's spread operator, you can make both to work in the same way.

function RadioGroup(id) {
this.el = document.querySelector(id);
this.buttons = slice(this.el.querySelectorAll('.radio'));
this.focusedIdx = 0;
this.focusedButton = this.buttons[this.focusedIdx];

this.el.addEventListener('keydown', this.handleKeyDown.bind(this));
this.el.addEventListener('click', this.handleClick.bind(this));

this.el.setAttribute('role', 'radiogroup');

// This works
[...this.el.querySelectorAll('li')].forEach(function (item){
  item.setAttribute('role', 'radio');
});

// And this too ;-)
[...this.el.children].forEach(function (item){
  item.setAttribute('role', 'radio');
});
}
Kamalakannan J
  • 2,818
  • 3
  • 23
  • 51