dojo.NodeList

Available:since V 0.9

NodeLists are standard Arrays, decorated with many helpful functions which act on each DOM Node in the list.

Introduction

dojo.query returns instances of dojo.NodeList:

1
2
3
4
5
6
var nl = dojo.query(".selectable");
// NodeLists have length like all other arrays
console.log( nl.length );

// hide each element
nl.style("display","none");

You can also create NodeLists manually and since NodeLists are "just an Array" all of the Array methods you already know Just Work (TM):

1
2
3
4
5
6
7
// create an instance of a NodeList
var nl = new dojo.NodeList();
nl.push(dojo.byId("someId"));
nl.push(dojo.byId("someOtherId"));

// hide both
nl.style("display", "none");

The helper functions attached to the NodeList typically return the same instance of the NodeList, allowing you to call several methods in a row:

1
2
3
4
5
6
7
8
9
// get all "li" elements
dojo.query("ul > li").
  // make them visible but, slightly transparent
  style({ opacity: 0.5, visibility: "visible" }).
  // and set a handler to make a clicked item fully opaque
  onclick(function(e){
    // a node to dojo.query() is a fast way to get a list
    dojo.query(e.target).style({ opacity:1 }).toggleClass("clicked");
  });

Common NodeList Functions

The entire NodeList API is extensive, so lets just focus on some of the most frequently used methods.

forEach - runs a function for each element in a NodeList. If you want the option to break out of the loop, use every or some instead.

1
2
3
4
dojo.query("div > h2").forEach(function(node, index, array){
    // append content to each h2 as a direct child of a <div>
    node.innerHTML += " - found";
});

The syntax is the same as dojo.forEach except that the first parameter (the array) is implicitly provided. This pattern is repeated throught the dojo.NodeList API.

For instance, dojo.style() styles a single Node around a defined API. That API is mapped into NodeList, dropping the node parameter and calling dojo.style on each node in the list:

1
2
3
4
5
// all elements with class="hidden"
dojo.query(".hidden").
  style({ opacity:0, visibility:"visible" }).
  removeClass("hidden").
  addClass("readyToFade");

As is the case for removeClass(), addClass(), place(), and most other DOM-related functions in NodeList. All return the same NodeList, which allows for chaining. An exception is NodeList.coords, which returns an array of the coordinate values of the matched nodes when called as a getter.

1
2
3
4
5
var nl = dojo.query(".foo"); // an array of nodes, NodeList
var coords = nl.coords(); // an array of objects { w, h, t, l }
nl.forEach(function(n, i){
   console.log(n, "has", coords[i].w, "width");
});

Events with NodeLists

NodeList.connect() is provided as a way to add event handlers to all DOM Nodes in the list, matching the dojo.connect API, assuming again the node to connect to is the current item in the list:

1
2
3
4
dojo.query(".readyToFade").
  connect("onclick", function(evt){
    dojo.fadeIn({ node: evt.target }).play();
  });

You can pass any event you would to dojo.connect, and expect the same results. As a convenience, many DOM events are exposed on NodeList directly as functions, so the above example could be written out as:

1
2
3
4
 dojo.query(".readyToFade").
   onclick(function(evt){
     dojo.fadeIn({ node: evt.target }).play();
   });

Supported are onclick, onmouseenter, onmouseleave, onmouseover, omouseout, ondblclick, all the normal dom events you'd expect, and as of 1.2, onsubmit, onload, and onerror.

1
2
3
4
5
6
7
8
9
 // setup some basic hovering behavior:
 dojo.query(".foo.bar")
     .onmouseenter(function(e){
         dojo.style(e.target, "opacity", 1);
     })
     .onmouseleave(function(e){
         dojo.style(e.target, "opacity", 0.5);
     })
 ;

The Event object is the same as Dojo's normalized event when using dojo.connect.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// make an existing form use Ajax/xhrPost
dojo.query("#myForm").onsubmit(function(e){
  // note that the event is always passed and has methods not regularly
  // supported on IE
  e.preventDefault();

  dojo.xhrPost({
    form:"myForm",
    load: function(data){
      console.log('server said: ', data);
    }
  });

});

This example prevents the form from submitting and instead uses Ajax to send the data to the form's action="" url in an unobtrusive manner.

An event delegation API is provided in dojox.NodeList.delegate

Extending NodeList

Or, "Writing Your Own Plugins": Adding your own code to the dojo.NodeList class makes them available to dojo.query calls. Simply use dojo.extend to mix new functionality into the prototype of the NodeList class:

1
2
3
4
5
6
7
8
dojo.extend(dojo.NodeList, {
  makeRed: function(){
    this.style({ color:"red" });
    return this;
  }
});

dojo.query(".greenText").makeRed();

The import part being 'return this', ensuring any following chains will work.

NodeList extensions

To keep the Base size to a minimum, some NodeList functionality is provided by external modules. For instance, dojo.NodeList-fx add all the required FX/Animation code to NodeList, dojox.fx.ext-dojo.NodeList provides the animation functionality from dojox.fx, and dojo.NodeList-html adds advanced HTML manipulation functions. The hyphen in the filename is meant to indicate the module being loaded modifies an existing Class, as you won't be able to call hyphenated functions directly. Simply require in the the necessary code:

1
2
3
4
5
dojo.require("dojo.NodeList-fx");

dojo.addOnLoad(function(){
  dojo.query(".readyToFade").fadeIn().play();
});

The NodeList animations do not return the NodeList instance. Instead, they return the created Animation object, which you have to explictly call .play() on.

Additional Extensions

API Details

Array Methods

at:Returns one (or more) elements from the list in a new NodeList based on integer index. This is a fast way to wrap elements in a NodeList, exposing all the manipulation and DOM conveniences easily (can be chained).
1
2
3
4
5
// we only want to style the first one
dojo.query("a").at(0).style("fontWeight", "bold");

// get the 3rd and 5th elements:
var ofInterest = dojo.query(".stories").at(2, 4);
1
2
// new in Dojo 1.5, .at() can accept negative indices
dojo.query("a").at(0, -1).onclick(fn);

Incidentally, you can .end() out of a NodeList returned from .at, providing you access to the original NodeList before filtering.

1
2
3
4
5
6
7
dojo.query("a")
    .at(0)
       .onclick(function(e){ ... })
    .end() // back to main <a> list
    .forEach(function(n){
          makePretty(n);
    });
forEach:like dojo.forEach but with current list as the first parameter. Has the same API as Array.forEach in browsers that support it. Returns the source NodeList (can be chained).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
dojo.query("a").
  forEach(function(node, idx, arr){
    console.debug(node);
  });

// alternately, use second param to provide the scope:
dojo.query("a").
  forEach(console.debug, console);

// or using the special shortened syntax from dojo.forEach:
dojo.query("a").forEach("console.debug(item);");
map:like dojo.map with the current list as the array or Array.map in browsers that support it. Returns a new dojo.NodeList with the mapped-in elements (can be chained).
1
2
3
4
5
6
7
var parents = dojo.query("a").
  map(function(node){
    return node.parentNode;
  });

// or using the string version:
var parents = dojo.query("a").some("return item.parentNode;");
slice:Used for grabbing only some of the elements in the list. Like Array.slice, returns a new dojo.NodeList from a subset of the current list (can be chained).
1
2
// style all but the first and last:
dojo.query("a").slice(1, -1).addClass("emphasis");
splice:Useful for changing a list in-place instead of making a new copy. Like Array.splice, returns a new dojo.NodeList containing the elements removed from the list (can be chained).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
var anchors = dojo.query("a");

// remove 3, starting with the second
var removed = anchors.splice(1, 3);

// ... and since we return a NodeList, style them:
removed.style("opacity", 0.5);

// bold the remaining anchors
anchors.style("fontWeight", "bold");
concat:Joins other lists to the current list. Like Array.concat, returns a new dojo.NodeList containing both the original elements and the new items (can be chained).
1
2
3
var anchors = dojo.query("a");
var bolds = dojo.query("b");
var boldsAndAnchors = anchors.concat(bolds);
push:Like Array.push, push adds items to the NodeList. Can be used to add multiple items at once. Returns the new list length (does not chain).
1
2
3
4
var anchors = dojo.query("a");
var a = dojo.doc.createElement("a");
// add "a" and 2 copies
anchors.push(a, a.cloneNode(), a.cloneNode());
pop:Like Array.pop, removes the last item from the NodeList (does not chain).
1
2
3
4
var anchors = dojo.query("a");
// remove the last item from the list
var a = anchors.pop();
dojo.style(a, "fontWeight", "bold");
shift:Like Array.shift. Works like pop, but instead pulls the first element from the list instead of the last (does not chain):
1
2
3
4
var anchors = dojo.query("a");
// remove the first item from the list
var a = anchors.shift();
dojo.style(a, "fontWeight", "bold");
unshift:Like Array.unshift. Similar to push, but instead puts elements at the front of the list. Returns the new length of the NodeList (does not chain):
1
2
3
var anchors = dojo.query("a");
var a = dojo.doc.createElement("a");
var howMany = anchors.unshift(a);
indexOf:Like Array.indexOf (where supported) or dojo.indexOf. Returns integer index if the tested element is found, -1 if not found (does not chain).
1
2
3
var anchors = dojo.query("a");
var tested = dojo.byId("tested");
console.debug("is it in the list?", ( anchors.indexOf(tested) != -1 ) );
lastIndexOf:Like Array.lastIndexOf (where supported) or dojo.lastIndexOf. Returns integer index of the tested element found closest to the end of the list, -1 if not found (does not chain).
some:like dojo.some and Array.some. Returns a boolean value indicating whether any of the items in the list match the filter function (does not chain).
1
2
3
4
5
6
7
var hasFoo = dojo.query("a").
  some(function(node){
    return node.innerHTML == "foo";
  });

// or using the string version (item is the node):
var hasFoo = dojo.query("a").some("return item.innerHTML == 'foo';");
every:like dojo.every and Array.every. Returns a boolean value indicating whether every item in the list matches the filter function (does not chain).
1
2
3
4
5
6
7
8
// dojo.require("dojo.NodeList-traverse"); must be added in your code to use dojo.query().children() (new in 1.4)
var areOnlyChildren = dojo.query("a").
  every(function(node){
     return dojo.query(node.parentNode).children().length == 1
  });

// or using the string version (item is the node):
var areOnlyChildren = dojo.query("a").every("return dojo.query(item.parentNode).children().length == 1;");
filter:Like dojo.filter and Array.filter. A new form of filter is added to support testing against simple CSS class matches. Returns a subset of the items in the list that pass the test (can be chained).
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// a list of anchors that are only children, same as dojo.query("a:only-child")
// dojo.require("dojo.NodeList-traverse"); must be added in your code to use dojo.query().children() (new in 1.4)
var onlyChildren = dojo.query("a").
  filter(function(node){
    return dojo.query(node.parentNode).children().length == 1;
  });

// anchors that also have the class ``foo`` and an attribute ``bar``:
var fooBarAnchors = dojo.query("a").filter(".foo[bar]");

dojo.query("*").filter(function(item){
  // highlight every paragraph
  return (item.nodeName == "p");
}).style("backgroundColor", "yellow");

// the same filtering using a CSS selector
dojo.query("*").filter("p").styles("backgroundColor", "yellow");
query:Searches under all of the nodes in this list for nodes that match the passed query. Returns a flattened NodeList of all matching elements (can be chained).
1
2
// search for all anchor tags under several nodes:
var anchors = dojo.query("#foo, #bar").query("a");

DOM Methods

Click on a method name to see a documentation page for it.

:attr:
Attribute getter/setter for this list of nodes. Mimics dojo.attr, excluding the node passed.
:removeAttr:
New in 1.4 - Forcefully remove the passed attribute from a node. Mimics dojo.removeAttr.
style:Get or set styles to the nodes in this list. For more information see dojo.style
addClass:Add the passed class to the nodes in this list. For more information see dojo.addClass
removeClass:Remove the passed class to the nodes in this list. For more information see dojo.removeClass
toggleClass:Add the passed class to the nodes in this list, if the class is not present, otherwise removes it. For more information see dojo.toggleClass
place:TODOC
orphan:TODOC
adopt:TODOC
addContent:TODOC
empty:Empties the content of the nodes in this list, leaving the nodes in place. see dojo.empty
coords:Partially "deprecated", using NodeList.position is recommended in Dojo 1.4 and higher. Returns the coordinate values of all the nodes in this list.
position:Returns the coordinate values of all the nodes in this list.

Event Methods

connect:Connect to an event of all the nodes in this list. Follows the pattern of dojo.connect, though assumes each node in the list to be the target to connect to.
1
2
3
4
5
dojo.query("a.external").connect("onclick", function(e){
  // `this` here refers to the node, as we've not explicitly set the context to something
});

dojo.query("form").connect("onsubmit", function(){});

As a convenience, several common events are mapped as direct function calls. For example, the two following query() calls have identical results:

1
2
3
var fn = function(e){ console.warn(e.target); }
dojo.query("a").onclick(fn);
dojo.query("a").connect("onclick", fn);

The full list of methods that are mapped in this way are: onblur, onfocus, onchange, onclick, onerror, onkeydown, onkeypress, onkeyup, onload, onmousedown, onmouseenter, onmouseleave, onmousemove, onmouseout, onmouseover, onmouseup, and onsubmit.

It is also possible to manipulate the scope of the callback, just as dojo.connect would:

1
2
3
// both call obj.method(e) in context of obj onclick:
dojo.query("a").onclick(obj, "method");
dojo.query("a").onclick(obj, obj.method);

Animation

Adding animation to lists of nodes requires including the module dojo.NodeList-fx which adds the required methods to instances of dojo.NodeList. They are:

anim:TODOC
fadeIn:TODOC
fadeOut:TODOC
slideTo:TODOC
wipeIn:TODOC
wipeOut:TODOC
animateProperty:
 TODOC
Error in the documentation? Can’t find what you are looking for? Let us know!