Search code examples
javascriptthischildrenwai-ariaselectors-api

this.element.querySelectorAll('li') vs this.element.children where all children are LI


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>

Solution

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