-
What’s All This Then?
I'm Alex Russell, a web developer working on Chrome, Chrome for Android, Chrome Frame, and the Web Platform Team at Google London. I'm guilty of many JavaScript transgressions.
As part of the Chrome team I serve on ECMA TC39 (the standards body for JavaScript).
My aim is to make the web a better platform and to the extent that I can keep politics and economics from creeping in, that's what this blog is about, as in my public speaking.
Other facets available upon HTTP request: twitter, facebook, flickr, linkedin, and quora. Expect much less self-restraint there.
-
Recent Comments
- The Pastry Box Project | 1 February 2013, baked by Anne van Kesteren on Reforming the W3C TAG
- Jack Bouba on Bits and Remainders
- c69 on Reforming the W3C TAG
- TAG, You’re “It” | Brendan Eich on Reforming the W3C TAG
- Chris Keene on Reforming the W3C TAG
- DigDug2k on Reforming the W3C TAG
- Chris Dent on Reforming the W3C TAG
- Sam Tobin-Hochstadt on Reforming the W3C TAG
- Changing the TAG – An Unexpected Opportunity | Peter Linss on Reforming the W3C TAG
- alex on Reforming the W3C TAG
Extending dojo.query()
As you probably know, Dojo is layered, extensible, and our philosophy of “build with, not on” means that we give you all of the same tools and extension points that we use in our code for use by your app.
Dojo’s got 2 “sides”, namely the bits that make working with the DOM better and the bits that make writing idiomatic JavaScript faster and easier. Where the package and language utilities enable you to extend and modularize your JavaScript work, the widget, behavior, and query systems make working with the DOM similarly extensible. Writing widgets and behaviors is well-understood in the Dojo community, but extending the results of a dojo.query()
call haven’t seen as much attention. To rectify that, here’s the two-minute version of how to write your own dojo.query()
extension.
Step 1: grok dojo.NodeList
dojo.NodeList
is the Array subclass which all dojo.query()
calls return an instance of. Therefore, to extend the results of a dojo.query()
, we really want to extend the dojo.NodeList
class. Both dojo.query()
and dojo.NodeList
are available as soon as dojo.js
is included in your page.
Step 2: extend NodeList the old-skool way
Instances of dojo.NodeList
pick up properties from the prototype object of the dojo.NodeList
class. Lets add an inspect()
method which logs out the innerHTML of the nodes in the list to the Firebug console:
dojo.NodeList.prototype.inspect = function(){
this.forEach("console.debug(item.innerHTML);");
return this;
}
// now we can call it:
dojo.query("#container > p").inspect();
// or via a direct instance:
var nl = new dojo.NodeList(dojo.byId("container"), document.body);
nl.inspect();
A couple of small things to note:
this
points to thedojo.NodeList
instance inside the extension method- Our extension returns the current
NodeList
in order to enable chaining (e.g.dojo.query("*").inspect().connect(...)
) - Dojo’s
forEach
method supports a small extension to the Mozilla spec to allow you to specify a string to be used as the body of the iteration function instead of having to repeatfunction(){ ...
everywhere. 3 “magic” variables,item
,index
, andarray
point to the things you’d expect. In every other way, ourforEach
conforms strictly to the Mozilla behavior on all browsers.
Step 3: modernize and package it up
We want to be able to use dojo.require()
to manage this module, so we’ll assume that our Acme module lives in the acme/
directly which is a peer of the dojo/
and dijit/
directories from the Dojo distribution.
Lets add a provide()
so that we can require()
our module and use a bit of Dojo’s language tools to extend dojo.NodeList
more tersely:
// this file located in:
// acme/ext-dojo/NodeList.js
dojo.provide("acme.ext-dojo.NodeList");
// require() statements go here
dojo.extend(dojo.NodeList, {
inspect: function(){
this.forEach("console.debug(item.innerHTML);");
return this;
},
...
});
We can now include this module at runtime via dojo.require("acme.ext-dojo.NodeList")
and use it as a part of a build which will significantly improve the performance of the application which needs the file. Dojo’s infrastructure makes doing what’s easy pay off in the long run for your application.
Note that the file name is acme/ext-dojo/NodeList.js
, which might seem a bit odd at first glance, but the intermediate “ext-dojo” directory makes it blindingly obvious to anyone who sees the require()
statement what’s going on. You can’t dot-access a variable named “ext-dojo”, so we know that this isn’t a “normal” module. Instead, it’s an extension, which extends the dojo.NodeList
class. Subclassing is often more trouble than it’s worth, and discouraging people from extending the Dojo core objects seems lame. Instead, we use this convention to make it easy to understand what’s happening when you look at any given Dojo project.
And that’s it! Writing powerful extensions for query results is easy, and because your project is using Dojo, you can structure your extension as a module and gain the benefits of optimization for deployment via the Dojo build system and the ease of use that comes from not having to worry about what order you’re including your files in. It’s good to be using a tool that you can build with, not just on.
4 Comments
Alex, what’s very cool about this article, is that on face value it’s about how you can extend dojo.query, which is cool. But then when you see dojo.query as a metaphor for “everything in the Dojo toolkit”, you realize what the potential is here.
I’m intreeged but this phylosophy โbuild with, not onโ. What would be the example of “build on” here?
CpILL:
building on would be creating a function external to query() which handles the inspect task and then returning the NodeList back out. By keeping the NodeList class open and giving you clean injection points to this and many other parts of Dojo, you can pull it apart and customize it as you need to. We also try to name and structure things in ways that allow extensions like these to live peacefully with one another. The goal of Dojo in this respect isn’t just to give you useful APIs to use, but rather to give you building blocks which you can mix, match, and even replace as your application demands.
Regards
So “extending” classes directly instead of inheriting from them. Does this run into the problem of messing with a namespace you don’t have direct control over, the same way that Dojo tries not to mess with the base Javascript name space (i.e. as Prototype does)?
2 Trackbacks
[...] composed of a layer of modules that can easily be utilized and extended on their own, following the Dojo philosophy of extensibility. First, JsonRestStore is an extension of the ServiceStore data store and is designed for [...]
[...] the Dojo philosophy of “build with, not on”, dojo.dnd provides a terrific API for getting the right behaviour for your app, with plenty of [...]