JavaScript’s Selectors API

Dealing with the DOM can be a very tedious process.  Traversing the DOM can quickly clutter your code with nested loops.  For years, developers have wanted a better way to query the DOM for nodes matching specified criteria.  In HTML5 their wishes came true in the form of a new specification called the Selectors API.  If you have worked with CSS before, then the term “selector” probably sounds familiar.  If you are unfamiliar with CSS, selectors are pattern strings used to retrieve matching nodes from the DOM.  The Selectors API is the same concept translated to JavaScript.  In addition to removing excessive looping in your code, the Selectors API also runs faster because it executes natively in the browser.

One nice thing about the Selectors API is that it only introduces two new (extremely useful) methods.  The two new methods are ‘querySelector()’ and ‘querySelectorAll()’.  Both methods take a single parameter – a string specifying the DOM selector(s).  The ‘querySelector()’ method returns only the first element matched by the selector.  If there is no match it returns null.  If you need to select a list of all elements that match the selector string, then the ‘querySelectorAll()’ method is used.  If there are no matches, then an empty list is returned.  Both ‘querySelector()’ and ‘querySelectorAll()’ can be called on the ‘document’ object, as well as individual elements.

The following HTML tables show the employee rosters for two imaginary companies, ‘companyFoo’ and ‘companyBar’.  The rosters list each employee’s name and salary.  A ‘data-manager’ custom data attribute is used to designate whether an employee is a manager or not.  These tables will be used to illustrate example usages of the Selectors API.

<table id="companyFoo">
  <tbody>
    <tr>
      <td class="employee" data-manager="false">Jack</td>
      <td class="salary">$70,000</td>
    </tr>
    <tr>
      <td class="employee" data-manager="true">Jill</td>
      <td class="salary">$80,000</td>
    </tr>
  </tbody>
</table>

<table id="companyBar">
  <tbody>
    <tr>
      <td class="employee" data-manager="false">Pete</td>
      <td class="salary">$55,000</td>
    </tr>
    <tr>
      <td class="employee" data-manager="true">Pam</td>
      <td class="salary">$90,000</td>
    </tr>
  </tbody>
</table>

Selecting a Single Node

The following three statements will all return the ‘companyFoo’ table element.  The first statement uses the traditional ‘getElementById()’ method, while the second and third statements use the ‘querySelector()’ method.  Notice the use of the # character in the second statement.  If you are accustomed to using ‘getElementById()’ it can be easy to forget the #, which would cause the method to return null.  The third statement shows how ‘querySelector()’ is used to return only the first of the two table elements.

var node1 = document.getElementById("companyFoo");
var node2 = document.querySelector("#companyFoo");
var node3 = document.querySelector("table");

Selecting Node Lists

These next three statements all return node lists containing both of the table elements in the document.  The first statement uses the ‘getElementsByTagName()’ DOM method.  The second statement uses the ‘querySelectorAll()’ method to select all of the table elements in the document.  The third statement selects the same table elements individually using multiple selectors.

var nodes1 = document.getElementsByTagName("table");
var nodes2 = document.querySelectorAll("table");
var nodes3 = document.querySelectorAll("#companyFoo, #companyBar");

You must also be aware that ‘getElementsByTagName()’ returns a live node list, while ‘querySelectorAll()’ returns a non-live node list – also referred to as a static node list.  This means that after the list is created, it will not reflect any changes made to the DOM.  If the DOM is updated, the static node list could become out of date.  In that case another call to ‘querySelectorAll()’ is needed to refresh the list.

A Real Example

The previous examples don’t show the power of the Selectors API.  What if you wanted to highlight all of companyFoo’s managers’ names in red font?  What would the JavaScript look like?  First, you would need to isolate the table for companyFoo using ‘getElementById(“companyFoo”)’.  Next, ‘getElementsByClassName(“employee”)’, would be called to select all of the cells containing employee names.  Finally, you would have to check that the custom data-manager attribute value is present and set to true.  The resulting JavaScript would look something like this.

var table = document.getElementById("companyFoo");
var cells = table.getElementsByClassName("employee");

for (var i = 0; i < cells.length; i++) {
  var cell = cells[i];

  if (cell.dataset.manager === "true")
    cell.style.color = “#FF0000”;
}

The same code is rewritten in the following example using the Selectors API.  Here, all of companyFoo’s managers can be found using a single query.  Even for this simple example, the Selectors API proves to be more powerful than the older DOM access methods.  As a side note, this simple example could have been implemented using a CSS rule.

var cells = document.querySelectorAll("#companyFoo > tbody > tr > td[data-manager='true']");

for (var i = 0; i < cells.length; i++)
  cells[i].style.color = "#FF0000";

 


2 thoughts on “JavaScript’s Selectors API

  1. Thanks for this little tutorijal. Learning js and this is good tip for selectors. So there’s no need for jquery here?

    • Well jQuery can do much more than query the DOM, but if you only want to use CSS style selectors, then you can leave it out in favor of the Selectors API.