Posts in the ‘Dojo’ Category

Object Capability Model and Facets in Perstore/Pintura

Monday, March 8th, 2010
This entry is part 6 of 6 in the series Server-Side JavaScript, Pintura, and Persevere 2.0

The object capability model is an approach to security that utilizes object references as the primary means of controlling access and providing authority. Capability-based security follows the principle of using unforgeable capabilities to provide access to resources. Object capability builds on capability-based security by leveraging object references as the primary representation of capabilities, which are naturally unforgeable in memory safe languages. Object capability based security is an elegant approach to security because the goals of object-oriented principles of encapsulation and information hiding are realized in virtually the same exact manner as the principle of least authority that is at the heart of object capability security. This type of security is extremely flexible and customizable since it is based on object-oriented design. Plus, writing good code naturally leads to secure code, security can be designed with object encapsulation hand-in-hand.

(more…)

Learning Dojo

Friday, March 5th, 2010

There is so much existing information about the Dojo Toolkit that it can be challenging to know where to begin. The following is a Dojo curriculum (I use this term loosely) highlighting community resources and a logical path for self-learning the foundational parts of Dojo.  If you understand the purpose of a variable and function, or you are new to Dojo, then this is for you.

(more…)

General Interface – Dojo Integration and Runtime Metadata

Wednesday, March 3rd, 2010

General Interface (GI) recently joined the Dojo Foundation as part of a transition to a true comprehensive 100-point open source project. TIBCO open sourced GI a number of years ago, but now GI can enjoy the benefits of running under the Dojo Foundation and being integrated with the infrastructure for open SVN, bug tracking, and more. Not only is GI is part of the foundation, but GI now includes significant integration with the Dojo Toolkit. The powerful GI builder, a web-based visual IDE for building client side web applications, now is capable of utilizing Dojo widgets as well as the GI set of widgets.

gi-dojo.png

(more…)

Efficient Lazy Loading of a Tree

Wednesday, January 27th, 2010

Dojo 1.4 sports a fantastic tree widget, complete with ARIA compliance, keyboard accessibility, and internationalization (including right-to-left layout for appropriate countries and languages). For large tree data sets, we want to be able to only load the necessary data for the visible nodes of the tree. As a user expands a node, we then want to load the children of that node. Ideally, we only want to make one HTTP request per expansion for optimal performance. Historically, effective lazy loading has been a challenge, but some recent additions will make it much easier to utilize efficient lazy loading mechanisms in the tree.

(more…)

Managing Widget Templates in Dojo 1.4

Wednesday, January 20th, 2010

This article introduces dojo.cache and presents a technique for externalizing your widget templates in swappable configuration files, where they can be referenced by a custom templateKey widget property.

Introducing dojo.cache

Dojo 1.4 adds a new core utility called dojo.cache. To appreciate it we first have to review how Dijit’s templatePath works. When you define a _Templated widget with a templatePath property, the content from that URL is fetched the first time you instantiate the widget, and made available as a string. All subsequent instances get the cached string. Furthermore, when you run a build, your templatePaths get replaced with templateStrings and their content is inlined into the output from the build. This improves performance considerably by removing those synchronous XHR requests, while remaining transparent to the developer.

dojo.cache generalizes this pattern, making the same functionality available from Dojo Core—synchronous, cached content retrieval that gets inlined during the build. dojo.cache usage is much like dojo.moduleUrl:

dojo.require("dojo.cache");
my.stringResource = dojo.cache("module.path", "relative.path.html" );

(more…)

Dojo 1.4 Released!

Thursday, December 10th, 2009

Dojo 1.4 is hot off the presses, with more than seven months of significant improvements to performance, stability, and features.

Of particular interest:

  • IO Pipeline topics
  • dojo.cache
  • dojo.contentHandlers
  • dojo.hash with native HTML5 onhashchange event support where available
  • Traversal and manipulation for NodeLists (the return value for dojo.query)
  • dojo.ready (easier to type than dojo.addOnLoad)
  • Hundreds of refinements to the Dijit API and collection of Dijits, and a few new widgets in DojoX
  • DataChart widget and other improvements to charting
  • dojox.drawing lands!
  • Editor improvements and new plug-ins in both Dijit and DojoX
  • Grid is faster, and the EnhancedGrid lands!
  • ForestStoreModel for the TreeGrid
  • GFX improvements
  • dojox.jq, a very experimental module aimed at trying to match the jQuery API as close as possible, but using Dojo underneath
  • Dojo build system optionally supports the Google Closure Tools compiler
  • Significant speed improvements, especially in IE

Read the full Dojo 1.4 release notes for more details! And thanks to everyone in the Dojo community that helped make this release great!

Getting Help

Thursday, November 5th, 2009
This entry is part 9 of 9 in the series Dojo Quick Start Guide

In addition SitePen’s various commercial support options, there are a number of ways to find helpful information on your own. Dojo has a large community of developers and hobbyists all across the globe that are willing to assist with problems and offer guidance. Many tutorials and examples exist and are ready to be found, you just have to look.

Here are some vital community resources available to assist you in your Dojo-learning, and some hints to ensure success:

Dojo Search

Search first, ask later. A quick stop at the dojotoolkit.org search page usually turns up lots of commonly encountered problems. The new search engine has options to help you target specific resources in the Dojo community, like blogs, forums, or archived mailing lists.

Dojo Forums

If you are unable to find any discussion or book entry already, start a new topic in the Dojo forums.

It helps to provide examples contained within code tags, and to politely state your question. If you have tried other methods and failed, mention them as well. The more infomation you provide in your post, the more likely someone is going to quickly be able to assist you.

Also available on the Dojotoolkit website: a collection of Frequently Asked Questions.

#dojo

Join the #dojo chat room on the irc server irc.freenode.net. This room acts as a realtime development center for numbers of people ranging from beginner to expert. Often, many core Dojo developers are available for any level of discussion, at seemingly odd hours of the day. There is no experience requirement, just a desire to learn.

The conversations range from deeply technical to outlandishly silly. It is a very friendly room, and a great way to be in immediate contact with like minded people while developing or learning Dojo. The first rule in the channel topic “Don’t Ask to Ask, just Ask” means just that: Jump right in, and start talking. If help is available, you will likely get a response.

Mailing Lists

Though the forums have taken the place of the once-active mailing lists, this resource is still available, and the preference of some. Simply signup, and begin writing a thoughtful, well researched question, and you are typically going to receive a response. The more thought you put into your post, the more willing people will be to help you.

There are several thousand subscribers to dojo-interest, so civility is expected of everyone.

It is important to remember the Dojo community is entirely voluntary. People helping other people for the good of the Open Web, typically in their spare time. Civility is expected of everyone, and you are not guaranteed any speedy response, if at all. If you find things within the community to be lacking, you are always welcome to contribute. See the Getting Involved guide for more information about what you can do. The community grows daily, and your contributions are just as welcome as everybody elses.

Dijit: Prepackaged

Thursday, November 5th, 2009
This entry is part 8 of 9 in the series Dojo Quick Start Guide

Dojo’s widget system is called Dijit. Dijits are the official, accessible, themed components shipped with the Dojo Toolkit. It has its own namespace, and likewise its own collection of utility functions:

dijit.byId("firstWidget"); // is a reference to the actual widget.
dijit.byId("firstWidget").domNode; // is the domNode the widget uses
// as opposed to:
dojo.byId("testHeading"); // is a domNode in our page

Using dijits

There are two ways to make Dijits: via markup, or programatically. The markup route breaks W3C validation because Dojo conveniently uses customized attributes in the markup to configure the widget. If this concerns you, it can all be done with script. We’ll do both.

Start by making a new skeleton file, including a couple changes for dijit styling: the default theme tundra’s CSS, and setting to enable it:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>Dijit Test Page</title>    
   
        <link rel="stylesheet"
                        href="js/dojotoolkit/dijit/themes/tundra/tundra.css" />
   
        <!– load the dojo toolkit base –>
        <script type="text/javascript" src="js/dojotoolkit/dojo/dojo.js"
            djConfig="parseOnLoad:true, isDebug:true"></script>

        <script type="text/javascript"> 
        // our code, and dojo.requires()
        </script>
   
    </head>
    <body class="tundra"><!– this is a Typical WebPage starting point … –>
        <h1 id="testHeading">Dijit Skeleton Page</h1>

        <!– empty placeholder nodes –>
        <div id="sampleNode"></div>
        <div id="anotherNode"></div>

    </body>
</html>

Dijit uses Dojo’s package system to track dependencies via dojo.require. Simply call in the modules you need in a script tag. For instance, to use a dijit.Dialog and dijit.form.Button, you need the following calls:

<script type="text/javascript">
        dojo.require("dijit.Dialog");
        dojo.require("dijit.form.Button");
</script>
The dijit.Dialog is a modal dialog box. It takes the node’s content, and displays it front-and-center on the viewport, awaiting user interaction. It can also act as a form element. To explore beyond this guide, visit the dijit.Dialog API Pages, or the Book overview.

From markup

You can specify all the attributes needed to setup your widget directly in markup, the most important being the dojoType. The parser finds the dojoType attribute, and turns the node into a Dijit with the matching classname. title is a common attrbute used by many widgets with headings:

<div dojoType="dijit.Dialog" id="sampleNode" title="The First Widget">
        <p>I am the Content inside the dialog.</p>
</div>
<button dojoType="dijit.form.Button" id="myButtom"
    onClick="console.log(’clicked’)">
    And Button
</button>

If parseOnLoad is true, the widgets will be created, then addOnLoad code will be executed. If you want to execute code before widgets are parsed, set parseOnLoad:false, and put your code inside an addOnLoad function as before. Issuing the command dojo.parser.parse(); will create the widgets when you are ready.

If parseOnLoad is true, the parser is loaded automatically. Otherwise, you must issue a dojo.require("dojo.parser"); call to include the required functions. All dijits use the parser, so it is included automatically.

From JavaScript

The same results can be achieved using valid HTML and JavaScript. Our markup is simple, valid HTML:

<div id="sampleNode">
        <p>I am the Content inside the dialog.</p>
</div>
<button id="myButton">
        Show Button
</button>

And our script is standard dojo code. We pass all the attributes as an object into our constructor, and tell it to use the node “sampleNode” for it’s content. All Dijits (or declared classes) can be created using the JavaScript new function.

dojo.require("dijit.Dialog");
dojo.require("dijit.form.Button");
dojo.addOnLoad(function(){
    // make the button
    var theButton = new dijit.form.Button({
                onClick:function(){
                    console.log("clicked");
                }
    },"myButton");

    // make our Dialog
    var theDijit = new dijit.Dialog({
                title:"The First Widget"
    },"sampleNode");
    // make sure its started. parser does this if using markup
    theDijit.startup();
});

When the button is clicked, you should see the word “clicked” in your Firebug (or Firebug Lite) console.

Manipulating The Widget

With our dialog successfully loaded and parsed (no errors were thrown, and the content of the Dialog is hidden), we need to explore some of the ways to manipulate the widgets. The function dijit.byId gives us a reference to our widget. The dijit.Dialog has an id of sampleNode.

To make the button the button control the dialog, modify the button’s onClick attribute to do more than print text:

<div dojoType="dijit.Dialog" id="sampleNode" title="The First Widget">
        <p>I am the Content inside the dialog.</p>
</div>
<button dojoType="dijit.form.Button" id="myButton"
        onClick="dijit.byId(’sampleNode’).show()">
        Show Dialog
</button>

If using the programmatic method, modify the lines that create the button:

// make the button
var theButton = new dijit.form.Button({
        onClick:function(){
            dijit.byId("sampleNode").show();
        }
},"myButton");

The dijit.Dialog inherits from a dijit.layout.ContentPane which provides a few content-handling methods, including setHref. Add a new button outside the dialog with a new onClick function:

<div dojoType="dijit.Dialog" id="sampleNode" title="The First Widget">
        <p>I am the Content inside the dialog.</p>
</div>
<button dojoType="dijit.form.Button" id="myButton"
    onClick="dijit.byId(’sampleNode’).show()">
    Show Dialog
</button>
<button dojoType="dijit.form.Button" id="otherButton"
    onClick="dijit.byId(’sampleNode’).setHref(’sample.txt’)">
    Change Content
</button>

Or programatically by adding another button to our HTML:

<div id="sampleNode">
        <p>I am the Content inside the dialog.</p>
</div>
<button id="myButton">
        Show Button
</button>
<button id="otherButton">
        Change Dialog
</button>

And an additional new call:

// make the button
var theButton = new dijit.form.Button({
        onClick:function(){
            dijit.byId("sampleNode").show();
        }
},"myButton");
var theButton = new dijit.form.Button({
        onClick:function(){
                dijit.byId("sampleNode").setHref("sample.txt");
        }
},"otherButton")

Adding an id attribute to the paragraph inside the Dialog is an easy way to demonstrate another useful Dijit tool, dojo.getEnclosingWidget, to find which widget contains a passed domNode:

// show the dialog onLoad, without knowing it’s id
dojo.addOnLoad(function(){
        // add <p id="myPara"> to the dialog content
        var p = dojo.byId("myPara");
        var theDijit = dijit.getEnclosingWidget(p);
        theDijit.show();
});

Ajax: Simple Transports

Tuesday, November 3rd, 2009
This entry is part 7 of 9 in the series Dojo Quick Start Guide

Ajax is an acronym for “Asynchronous JavaScript and XML”, a technology employed to send and receive data on the fly. It can be used to update sections of a website from any number of remote sources, send data to the server and pass responses back and forth, all without ever refreshing the webpage.

Having been versed on some essential Dojo methods, we’ll move on the the bread and butter of Ajax: XmlHttpRequest (or XHR for short). Dojo has several XHR methods available using common HTTP verbs: POST, GET, PUT, and DELETE.

To prepare, we need to create a file with some text to load in. Create a file named sample.txt in your js/ folder with sample text:

I am a remote file.
We used Ajax to put this text
in our page.

And modify the skeleton.html to have some basic markup and style:

<style type="text/css">
    #container {
        border:1px dotted #b7b7b7;
        background:#ededed;
        width:75px;
        height:55px;
    }
</style>
<div id="container" class="box">
    <div id="content">
    I am some Inner Content.
    I am going to be replaced
    </div>
</div>
The XHR methods use dojo.Deferred behind the scenes to handle callbacks. This is beyond the scope of a QuickStart, but extremely useful in practice. If you would like to learn more about callbacks and the various way to set them up, visit the Dojo book or the dojo.Deferred API pages.

Getting data

The first stepping stone is dojo.xhrGet, which will return the contents of a GET call on a URL. The XHR methods share a lot of common parameters. Most important are the url: (our destination) and handleAs: (how we handle what is coming back). When the data arrives, it will be passed the the load: function we define:

var init = function(){
        var contentNode = dojo.byId("content");
        dojo.xhrGet({
            url: "js/sample.txt",
            handleAs: "text",
            load: function(data,args){
                // fade out the node we’re modifying
                dojo.fadeOut({
                    node: contentNode,
                    onEnd: function(){
                        // set the data, fade it back in
                        contentNode.innerHTML = data;
                        dojo.fadeIn({ node: contentNode }).play();    
                    }
                }).play();
            },
            // if any error occurs, it goes here:
            error: function(error,args){
                console.warn("error!",error);
            }
        });
};
dojo.addOnLoad(init);

You will notice we’ve combined techniques above. The content will fade out, be replaced by the received data, and fade back in using methods we’ve learned to this point. It was almost too easy.

A single handle argument can be used instead of load and error, handling both success and failure cases in a common function:

var init = function(){
     dojo.xhrGet({
         url: "js/sample.txt",
         handleAs: "text",
         handle: function(data,args){
        if(typeof data == "error"){
            console.warn("error!");
            console.log(args);
        }else{
            // the fade can be plugged in here, too
            dojo.byId("content").innerHTML = data;
        }
         }
     });
};
dojo.addOnLoad(init);

XHR has limitations. The big one being that url is not cross-domain. You can’t submit the request outside of the current host (eg: to url:”http://google.com”). It is a known limitation and a common mistake when getting excited about Ajax. Dojo provides alternatives like dojo.io.iframe and dojo.io.script for more advanced usage.

You also may experience problems with the Ajax samples if you are using Internet Explorer without a web server (from the local filesystem). It is a know security limitation of XHR and IE. While most of these examples do work from the filesystem, it is recommended you have a web server accessible to host the Dojo source, and your tests.

A full list of XHR parameters is available at the API page, or in the Dojo Book. We are only going to skim the surface here.

Sending Data

All Dojo XHR methods are bi-directional. The only difference is the method. Using dojo.xhrPost, we use the POST method, embedding the data in the request (as opposed to the query string as with dojo.xhrGet). The data can be set directly as an object passed to the content parameter:

dojo.addOnLoad(function(){
     dojo.xhrPost({
         url:"submit.html",
         content: {
        "key":"value",
        "foo":42,
        "bar": {
            "baz" :"value"    
        }
         },
         load: function(data,ioargs){
        console.log(data);
         }
     });
});

Or more commonly, conveniently converted from a form parameter. First, make a simple unobtrusive form in the skeleton.html:

<form id="mainForm" action="ajax-submit.php" method="post">
        <label for="firstName">Name: </label>
        <input type="text" name="firstName" value="Enter Name" />
</form>

Then, add in some JavaScript to submit the form by using dojo.connect to listen to the onSubmit event, and post the contents of the form to an alternate URL:

// submit the form
var formSubmit = function(e){
        // prevent the form from actually submitting
        e.preventDefault();
        // submit the form in the background   
        dojo.xhrPost({
            url: "alternate-submit.php",
            form: "mainForm",
            handleAs: "text",
            handle: function(data,args){
                        if(typeof data == "error"){
                            console.warn("error!",args);
                        }else{
                            // show our response
                            console.log(data);
                        }
            }
        });
};
dojo.addOnLoad(function(){
        var theForm = dojo.byId("mainForm");
        // another dojo.connect syntax: call a function directly       
        dojo.connect(theForm,"onsubmit","formSubmit"); 
});
Notice e.preventDefault() being used again. The default nature of a form being submitted to to visit a new page, and we want to prevent that from happening.

An example alternate-submit.php would look like:

<?php
        print "DATA RECEIVED:";
        print "<ul>";
        foreach($_REQUEST as $key => $var){
                print "<li>".$key." = ".$var."</li>";
        }
        print "</ul>";
?>

Object Data

Getting text back from the server is nice, but the really great stuff comes when you start passing JavaScript objects around. Using a different handleAs: attribute, we can alter how Dojo handles the response data. Make a new file named simple-object.json to load:

{
        foo: "bar",
        name: "SitePen",
        aFunction: function(){
                alert("internal function run");     
        },
        nested: {
            sub: "element",
            another: "subelement"
        }
}

We’ll target our xhrPost url: to the new file, and supply a handleAs: "json" parameter to convert the response data to an actual object we can use:

var postData = function(){
        dojo.xhrPost({
            url: "js/simple-object.json",
            handleAs: "json",
            load: function(data,ioargs){
                        // success: set heading, run function
                        dojo.byId("testHeading").innerHTML += " by: "+data.name;
                        if(data.aFunction && data.aFunction()){
                            // we just ran data.aFunction(). should alert() …
                        }
            }
        });
};
dojo.addOnLoad(postData);
A message will be thrown wanting you to use “json-comment-filtered” as a handleAs: value. You can either use the alternate value, or set your djConfig’s usePlainJson: true to deprecate this warning.

This allows us to send literally any kind of data back and forth across the wire, without ever interrupting the user experience.

Some Gloss: Dojo Animations

Tuesday, November 3rd, 2009
This entry is part 6 of 9 in the series Dojo Quick Start Guide

Dojo has a powerful animation system with several pre-made animations for a lot of common use cases. Adding some visual flair to you projects has never been easier, and typically makes the users experience a lot more interesting.

All animations use a single “magic object” as it’s only parameter. The most important being the node: attribute, the domNode on which to apply our animation. Some parameters are optional, and some are for advanced usage. A common setup would look something similar to:

dojo.addOnLoad(function(){
     var animArgs = {
          node: "testHeading",
          duration: 1000, // ms to run animation
          delay: 250 // ms to stall before playing
     };
     dojo.fadeOut(animArgs).play();
});

Base Animations:

Animations included in base dojo.js are: fadeIn, fadeOut, and animateProperty. dojo.animateProperty is very powerful, and is the foundation for most advanced animations, and other animations in Dojo Core.

dojo.addOnLoad(function(){
     dojo.style("testHeading","opacity","0"); // hide it
     var anim1 = dojo.fadeOut({ node: "testHeading", duration:700 });
     var anim2 = dojo.animateProperty({
       node: "testHeading", delay: 1000,
       properties:{
          // fade back in and make text bigger
          opacity: { end: 1 }, fontSize: { end:19, unit:"pt"}
       }
     });
     anim1.play();
     anim2.play();     
});

As seen, dojo.animateProperty will fade the element back in via it’s opacity property, and simultaneously make the text larger. You can animate most any CSS property this way.

In JavaScript, when modifying multi-word properties such as font-size and border-top, you must use a mixed cased version, as hypens are illegal as keys. Use fontSize and lineHeight, instead of font-size or line-height for example.

Additional FX

A lot can be done visually with the base animations, animateProperty especially. To keep the size of the base dojo.js down, all the additional animations and tools have been packaged into a single module: dojo.fx to be optionally called in via dojo.require. Adding the module to your code provides several additional animation methods: dojo.fx.combine, dojo.fx.chain, dojo.fx.wipeIn, dojo.fx.wipeOut and dojo.fx.slideTo.

dojo.require("dojo.fx");
dojo.addOnLoad(function(){
     // slide the node to 75,75
     dojo.fx.slideTo({
       node:"testHeading",
       top:75, left:75
     }).play(); // and play it
});

dojo.fx.chain and dojo.fx.combine are very useful, too. They run animations in parallel or in sequence, returning a single instance of dojo._Animation to use:

dojo.require("dojo.fx");
     dojo.addOnLoad(function(){
       var anim = dojo.fadeOut({ node: "testHeading" });
       var anim2 = dojo.fadeIn({ node: "testHeading" });
       dojo.fx.chain([anim,anim2]).play();
});

Combining an animation to fade in and out wouldn’t make sense, so lets fade it out and slide the node simultaneously using dojo.fx.combine:

dojo.require("dojo.fx");
     dojo.addOnLoad(function(){
       var anim = dojo.fadeOut({ node: "testHeading" });
       var anim2 = dojo.fx.slideTo({ node: "testHeading", top:75, left:75 });
       var result = dojo.fx.combine([anim,anim2]);
       result.play();
});

Animation Events

Each dojo._Animation has a series of “events” to tie into for more advanced usage. Going back to the one-stop-event-shop dojo.connect, we can connect to specific actions of the animation, and do other things. The most common are onEnd and beforeBegin:

dojo.addOnLoad(function(){
     var anim = dojo.fadeOut({ node: "testHeading" });
     dojo.connect(anim,"onEnd",function(){
       console.log(" the animation is done ");
     });
     dojo.connect(anim,"beforeBegin",function(){
       console.log(" the animation is about to start ");
     });
     anim.play();
});

These events are especially helpful when you want to do things like change some content out while a node is hidden and then fade it back in:

dojo.addOnLoad(function(){
     var anim = dojo.fadeOut({ node: "testHeading" });
     dojo.connect(anim,"onEnd",function(){
        dojo.byId("testHeading").innerHTML = "replaced after fade!";
        dojo.fadeIn({ node:"testHeading" }).play();
     });
     anim.play();
});

Conveniently, you can pass the event functions as properties to the animation. Using dojo.connect to setup the functions gives us a lot more power, and are typically safer for advanced uses, but sometimes it’s easier to wrap it all in:

dojo.addOnLoad(function(){
     var anim = dojo.fadeOut({
        node: "testHeading",
        onEnd: function(){
           dojo.byId("testHeading").innerHTML = "replaced … ";
           dojo.fadeIn({ node: "testHeading" }).play();
        }
     }).play();
});

The full explanation of events is available at the dojo._Animation API pages.

animateProperty

Probably the most powerful of the base animations, dojo.animateProperty allows us to easily animate multiple css properties simultaneously.

Since animateProperty is a dojo._Animation, it uses the same arguments as other animations. With an additional object, properties we can define any style property of a node. From start to end, and optionally using a unit attribute.

Manipulating our header element to use a new font color, size, and overall opacity is as easy as:

dojo.addOnLoad(function(){
     var anim = dojo.animateProperty({
        node:"testHeading",
        duration:700,
        properties: {
          // javascript css names are camelCase
          // (not hyphenated)
          fontSize: { start:12, end:22, unit:"pt" },
          opacity: { start:1, end:0.5 },
          color: { start: "#000", end:"#FFE" }
        },
        delay:100 // Note! trailing commas break IE.
     });
     anim.play();
});

dojo.query Animations

Dojo provides another convenient module: dojo.NodeList-fx, which adds additional methods to dojo.query for the available dojox.fx animations. To enable these methods, simply add in the required module:

dojo.require("dojo.NodeList-fx");
     dojo.addOnLoad(function(){
       dojo.query("#testHeading").fadeOut().play();
});

The above gives us the same effect as calling dojo.fadeOut directly, but dojo.query here makes an animation for each of of the NodeList elements, and combines them into a single dojo._Animation. This can be useful when you have groups of like nodes you want to easily affect (in this case, all the nodes with class=”fadeNode”):

dojo.require("dojo.NodeList-fx");
var fadeThem = function(){
     dojo.query(".fadeNode").fadeOut().play();
}
dojo.addOnLoad(function(){
     dojo.connect(dojo.byId("testHeading"),"onclick","fadeThem");
});
Unlike other dojo.query() chains, the NodeList-fx methods return an instance of dojo._Animation, preventing further chaining.