dojo.query¶
dojo.query() returns a list of DOM nodes based on a CSS selector.
dojo/query is the AMD module containing the query function in 1.7.
Introduction¶
XHR is half of the AJAX story. Once you make a request for data and receive it via dojo.xhr, you must change the page - display the new data in a panel, turn an indicator from red to green, or whatever. Changing HTML is, in turn, dependent on locating nodes.
A bad solution: using the DOM API¶
To select HTML elements in JavaScript, you can use the browser’s native DOM API, but they’re verbose and hard to work with...not to mention slow. For example, retrieving all nodes with the class “progressIndicator” uses this code:
// list every node with the class "progressIndicator":
var list = [];
var nodes = document.getElementsByTagName("*");
// iterate over every node in the document....SLOOOW
for(var x = 0; x < nodes.length; x++){
// only nodes with the class "progressIndicator":
if(nodes[x].className == "progressIndicator"){
// add to array:
list.push(nodes[x]);
}
}
console.dir(list);
Oy! That’s a lot of code for what should be very simple. It’s also very slow.
Better and faster: dojo.query¶
dojo.query gives us a more compact way to do it, and it’s often faster, particularly as we ask for more sophisticated kinds of relationships. The following is exactly equivalent to our first example:
// list every node with the class "progressIndicator":
console.dir( dojo.query(".progressIndicator") );
Usage¶
Users of other libraries will find the syntax very familiar:
Dojo 1.7 (AMD)¶
require("dojo/query", function(query){ // Note, query or any other variable name can be used
// find and dump contents of every element in the page with the class "blueButton" assigned
query(".blueButton").forEach(function(node, index, arr){
console.debug(node.innerHTML);
});
});
Dojo < 1.7¶
dojo.ready(function(){
// every element in the page with the class "blueButton" assigned
dojo.query(".blueButton").forEach(function(node, index, arr){
console.debug(node.innerHTML);
});
});
The returned object of a dojo.query() call is an instance of dojo.NodeList, a subclass of Array with many convenience methods added for making DOM manipulation and event handling easier. Custom extensions of the dojo.NodeList class are supported and encouraged.
Examples¶
Simple Queries¶
// all <h3> elements
dojo.query('h3')
// all <h3> elements which are first-child of their parent node
dojo.query('h3:first-child')
// a node with id="main"
dojo.query('#main')
// all <h3> elements within a node with id="main"
dojo.query('#main h3')
// a <div> with an id="main"
dojo.query('div#main')
// all <h3> elements within a div with id="main"
dojo.query('div#main h3')
// all <h3> elements that are immediate children of a <div>, within node with id="main"
dojo.query('#main div > h3')
// all nodes with class="foo"
dojo.query('.foo')
// all nodes with classes "foo" and "bar"
dojo.query('.foo.bar')
// all <h3> elements that are immediate children of a node with id="main"
dojo.query('#main > h3')
Immediate Child Elements¶
dojo.query('#main > *')
dojo.query('.foo > *')
Queries rooted at a given element¶
dojo.query('> *', dojo.byId('container'))
dojo.query('> h3', 'main')
Multiple class attribute values¶
dojo.query('.foo.bar')
Using attribute selectors¶
Picking out elements with particular attributes/values
dojo.query('[foo]')
dojo.query('[foo$=\"thud\"]')
dojo.query('[foo$=thud]')
dojo.query('[foo$=\"thudish\"]')
dojo.query('#main [foo$=thud]')
dojo.query('#main [ title $= thud ]')
dojo.query('#main span[ title $= thud ]')
dojo.query('[foo|=\"bar\"]')
dojo.query('[foo|=\"bar-baz\"]')
dojo.query('[foo|=\"baz\"]')
dojo.query('.foo:nth-child(2)')
Descendant selectors¶
dojo.query('> *', 'container')
dojo.query('> [qux]', 'container')
Sibling selectors¶
dojo.query('.foo + span')
dojo.query('.foo ~ span')
dojo.query('#foo ~ *')
dojo.query('#foo ~')
Sub-selectors, using not()¶
dojo.query('#main span.foo:not(span:first-child)')
dojo.query('#main span.foo:not(:first-child)')
Nth-child¶
dojo.query('#main > h3:nth-child(odd)')
dojo.query('#main h3:nth-child(odd)')
dojo.query('#main h3:nth-child(2n+1)')
dojo.query('#main h3:nth-child(even)')
dojo.query('#main h3:nth-child(2n)')
dojo.query('#main h3:nth-child(2n+3)')
dojo.query('#main > *:nth-child(2n-5)')
Using pseudo-selectors¶
dojo.query('#main2 > :checked')
dojo.query('#main2 > input[type=checkbox]:checked')
dojo.query('#main2 > input[type=radio]:checked')
Count of checked checkboxes in a form with id myForm¶
dojo.query('input:checked', 'myForm').length
Standard CSS3 Selectors¶
Because dojo.query adopts the CSS3 standard for selecting nodes, you can use any CSS reference guide for help on choosing the right queries. Eric Meyer’s CSS: The Definitive Guide is a good resource. For convenience, here’s a chart of the standard CSS3 selectors, taken from the current working draft RFC.
Pattern | Meaning |
---|---|
* | any element |
E | an element of type E |
E[foo] | an E element with a “foo” attribute |
E[foo=”bar”] | an E element whose “foo” attribute value is exactly equal to “bar” |
E[foo~=”bar”] | an E element whose “foo” attribute value is a list of space-separated values, one of which is exactly equal to “bar” |
E[foo^=”bar”] | an E element whose “foo” attribute value begins exactly with the string “bar” |
E[foo$=”bar”] | an E element whose “foo” attribute value ends exactly with the string “bar” |
E[foo*=”bar”] | an E element whose “foo” attribute value contains the substring “bar” |
E[hreflang|=”en”] | an E element whose “hreflang” attribute has a hyphen-separated list of values beginning (from the left) with “en” |
E:root | an E element, root of the document |
E:nth-child(n) | an E element, the n-th child of its parent |
E:nth-last-child(n) | an E element, the n-th child of its parent, counting from the last one |
E:nth-of-type(n) | an E element, the n-th sibling of its type |
E:nth-last-of-type(n) | an E element, the n-th sibling of its type, counting from the last one |
E:first-child | an E element, first child of its parent |
E:last-child | an E element, last child of its parent |
E:first-of-type | an E element, first sibling of its type |
E:last-of-type | an E element, last sibling of its type |
E:only-child | an E element, only child of its parent |
E:only-of-type | an E element, only sibling of its type |
E:empty | an E element that has no children (including text nodes) |
E:link | |
E:visited | an E element being the source anchor of a hyperlink of which the target is not yet visited (:link) or already visited (:visited) |
E:active | |
E:hover | |
E:focus | an E element during certain user actions |
E:target | an E element being the target of the referring URI |
E:lang(fr) | an element of type E in language “fr” (the document language specifies how language is determined) |
E:enabled | |
E:disabled | a user interface element E which is enabled or disabled |
E:checked | a user interface element E which is checked (for instance a radio-button or checkbox) |
E::first-line | the first formatted line of an E element |
E::first-letter | the first formatted letter of an E element |
E::selection | the portion of an E element that is currently selected/highlighted by the user |
E::before | generated content before an E element |
E::after | generated content after an E element |
E.warning | an E element whose class is “warning” (the document language specifies how class is determined). |
E#myid | an E element with ID equal to “myid”. |
E:not(s) | an E element that does not match simple selector s |
E F | an F element descendant of an E element |
E > F | an F element child of an E element |
E + F | an F element immediately preceded by an E element |
E ~ F | an F element preceded by an E element |
dojo/query (1.7 only)¶
In Dojo 1.7, a dojo/query
module is also available to reference to the query functionality and choose alternate selector engines and needed levels of compliance.
The basic usage of the dojo/query
module is to simply use the module’s value as the query function:
define(["dojo/query"], function(query){
var nodeList = query(".foo.bar");
});
We can also specify alternate selector engines and compliance levels. By default, Dojo base will use the acme selector engine, which supports a large set of CSS3 selectors. However, not all applications need all of these selectors, and most queries can be performed with the native selector engines or with a simpler engine. Dojo 1.7 includes a new lite selector engine for situations where simpler queries are sufficient. The acme selector engine is about 14KB (minified, not gzipped), whereas the lite selector engine is about 2KB, which can be a big advantage for mobile applications.
Selector Engine Levels¶
There are several different levels of CSS compliance that can be selected:
- css2 (or lite) - This will always use the lite engine, which delegates to the native selector engine if available for anything but very simple queries (like id lookups). When a native selector engine is not available (IE7 and below), this supports simple, basic CSS2 level queries, consisting of elemental selectors: .class, #id, tag, and star, attribute selectors, and child (>), descendant (space), and union (,) combinators. With a native selector engine, the lite engine does not support pseudo classes.
- css2.1 - This will always use the lite engine when a native selector engine is available. When a native selector engine is not available (IE7 and below), this will load acme.
- css3 - This will always use the lite engine when a native selector engine with significant CSS3 support is available. When a CSS3 capable (supporting most features) native selector engine is not available (IE8 and below), this will load acme.
- acme - The acme selector engine with full CSS3 features will be used. This supports certain features that are not available in any native engine (albeit rarely used).
When you are not using Dojo base (running async without a dependency on base module “dojo”), the default selector engine level is “css3”. Again, if you are using Dojo base, the default is “acme”.
The summarize, the two alternate selector engines included with Dojo have the following features (which can be selected explicitly or by the module’s CSS level needs):
- acme - Designed to have full CSS3 support.
- lite - Basic CSS2 level queries, consisting of elemental selectors: .class, #id, tag, and star, attribute selectors, and child (>), descendant (space), and union (,) combinators. With a native selector engine, the lite engine does not support pseudo classes.
Specifying Selector Level¶
There are a couple of ways to set the selector engine. First, we can define the selector engine as part of the dojo configuration for the whole page:
<script data-dojo-config="selectorEngine='css2.1'" src="dojo/dojo.js">
</script>
You can also specify the selector engine level you are dependent on for each of your modules. This is done by indicating the CSS selector engine level after ! in the dojo/query module id. For example, if your module needed to do a CSS3 level query, you could write:
define(["dojo/query!css3"], function(query){
query(".someClass:last-child").style("color", "red");
});
If Dojo had started with the lite engine, this will ensure that CSS3 support is available, and will load Acme on older browsers. It is recommended that you use this syntax for modules that make more complex queries. If your module is using a simpler query, then "dojo/query"
or "dojo/query!css2.1"
should be used.
Alternate Selector Engines¶
We can also use other selector engine levels. Both Sizzle and Slick are excellent selector engines that work with dojo/query. AMD/Dojo compatible versions (just wrapped with AMD) are available here: https://github.com/kriszyp/sizzle and https://github.com/kriszyp/slick. Once installed, you can use the selector engine module id as specified selector engine level. We could set Sizzle as the query engine for our page:
<script data-dojo-config="selectorEngine='sizzle/sizzle'" src="dojo/dojo.js">
</script>
or set Slick as the engine for a particular module:
define(["dojo/query!slick/Source/slick"], function(query){
query(".someClass:custom-pseudo").style("color", "red");
});
Note for cross-domain legacy API usage¶
This use-case should be quite rare, but presents a wrinkle worth noting.
When loading dojo.js cross-domain and electing to use an alternate selector engine not included in
dojo.js
itself, legacy APIs will not immediately work, since Dojo base does not finish loading
until the selector engine is pulled in asynchronously. In this case, it will be necessary to use
require
. In a pinch, legacy code can simply be wrapped like so:
require(["dojo"], function(dojo){
dojo.require(/* ... */);
// etc...
});
Again, this issue only affects use of legacy APIs when a selector engine is used which is not
baked into dojo.js
.
Table of Contents
- dojo.query
- Introduction
- Usage
- Examples
- Simple Queries
- Immediate Child Elements
- Queries rooted at a given element
- Compound queries
- Multiple class attribute values
- Using attribute selectors
- Descendant selectors
- Sibling selectors
- Sub-selectors, using not()
- Nth-child
- Using pseudo-selectors
- Count of checked checkboxes in a form with id myForm
- Standard CSS3 Selectors
- dojo/query (1.7 only)