Dojo is a very flexible toolkit. Most every aspect of its functionality is extensible by taking advantage of JavaScript’s dynamic nature. Today, I’m going to show you how you can write your own modular reusable code to create a generic component you can provide others (perhaps your development team, or designers?) to use in whichever way they desire … Just like the toolkit itself.
The problem we are about to solve is a common one: Ajax activity. When we submit a form, for instance, we’ll want a way to notify the user that background network activity is taking place, and to prevent the user from re-submitting by hastily clicking away.
Conceptually, this is a rather easy task. The long and short of it is: we’ll simply overlay the form with a semi-transparent div element, blocking the underlying content. To make it reusable and generic is a greater task, and the primary focus of this article.
To sneak a peak at what we’ll be working towards checkout the end result or a small cheeky sample before diving in.
Lets start by creating a class for a component to block the content. We’ll name it dojo._Blocker. The underscore preceding the class name, at least in Dojo, indicates a private class or method which users typically won’t need to instantiate on their own. We’ll address why we’re doing that in a minute, but for now let us focus on the actual blocking of a node:
duration: 400,
opacity: 0.6,
backgroundColor: "#fff",
zIndex: 999,
constructor: function(node, args){
// mixin the passed properties into this instance
dojo.mixin(this, args);
this.node = d.byId(node);
// create a node for our overlay.
this.overlay = dojo.doc.createElement(‘div’);
// do some chained magic nonsense
dojo.query(this.overlay)
.place(dojo.body(),"last")
.addClass("dojoBlockOverlay")
.style({
backgroundColor: this.backgroundColor,
position: "absolute",
zIndex: this.zIndex,
display: "none",
opacity: this.opacity
});
},
show: function(){
// summary: Show this overlay
},
hide: function(){
// summary: Hide this overlay
}
});
It might look like a lot, but it is really simple. dojo.declare declares a class. Here we’re defining a class called dojo._Blocker, mixing in the base class null, inheriting no other code. dojo.declare is part of Dojo Base, and provided by dojo.js. The third parameter is an object hash of properties and functions to mix in to our class, and consists of four configurable properties, and three functions. The most important function is named constructor, and is run when the class is instantiated using the JavaScript new function. The signature of the function accepts a node in the first position, and properties in the second position:
var thinger = new dojo._Blocker(node, { /* properties */ });
After that, we can call thinger.show() or any of the other class methods when appropriate. If you look at the constructor function more closely, a couple of interesting things are taking place. The first thing happening, we’re mixing the args param into this, allowing the user to override the default opacity, backgroundColor, z-index and duration we’ve supplied as ’sane defaults’. Most of Dojo works this way, and is very easy to customize.
On the next line, we’re assigning the passed node parameter to this.node, to store the reference in our instance. We could accept a node: parameter in the args position, but the API I’ve setup here calls for a node to be passed separately, and matches the common Dojo API. This is important later, so just take my word for it for now.
Next, we create a <div> element, and store the reference as this.overlay. The overlay is the important node, and the one we’ll be placing somewhere to block the page. Using dojo.query, we chain a few commands to manipulate our newly created node. First placing the overlay as the last child of the <body> tag, adding a distinct class name (for custom styling), and applying some basic styles. Setting position:absolute on a child of body will allow us to position the node freely, and setting display:none prevents the overlay from being shown. We’re also mixing in our user-defined (or default) backgroundColor and zIndex, all in one fell swoop.
Now that our constructor is setup, and our blocker div is created and styled, we have to activate it somehow. We’ve added two methods, show and hide, to show and hide the overlay, respectively. Our show method grabs the position of the node we intend to overlay, and sets those coordinates on our overlay div via dojo.marginBox. The node is still invisible at this point, so we make another call to dojo.style to set the opacity to 0 (which is visible, just really hard to see) and display:"", undoing the none value we set previously. Immediately after that, we fade in the node, using the defined duration. The hide method counteracts those actions, effectively making a toggle.
The show function:
// summary: Show this overlay
var pos = dojo.coords(this.node, true),
ov = this.overlay;
dojo.marginBox(ov, pos);
dojo.style(ov, { opacity:0, display:"block" });
dojo._fade({ node:ov, end: this.opacity, duration: this.duration }).play();
}
You’ll notice I used a private function _fade. This was for my own convenience, but the results can be achieved a number of different ways. _fade is simply the shortest to type, and I’m fairly certain the API won’t be changing any time soon (though it could, which is what the underscore indicates).
dojo.animateProperty({
node: ov,
properties: { opacity: this.opacity },
duration:this.duration
}).play();
// or with the (new in 1.1) dojo.anim:
dojo.anim(ov, { opacity: this.opacity }, this.duration)
The code for the hide function simply fades out the node, and sets the CSS property display to none after completion:
// summary: Hide this overlay
dojo.fadeOut({
node: this.overlay,
duration: this.duration,
// when the fadeout is done, set the overlay to display:none
onEnd: dojo.hitch(this, function(){
dojo.style(this.overlay, "display", "none");
})
}).play();
}
We can test this basic implementation by creating a simple test page. We have a simple styled div, with some basic content. Save the declaration code as Block.js and load it, and Dojo into a page. For now, we’ll use the Google CDN:
<head>
<title>basic dojo._Blocker</title>
<style type="text/css">
#blockme {
height:200px;
width:200px;
background:#ededed;
color:#000;
}
#blockme p {
padding:20px;
}
</style>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js"
></script>
<script type="text/javascript" src="Block.js"></script>
<script type="text/javascript">
// just for this test:
dojo.addOnLoad(function(){
var blocker = new dojo._Blocker("blockme");
dojo.query("#login").connect("onsubmit", function(e){
e.preventDefault(); // stop ‘real’ submission
blocker.show();
// wait 2 seconds, and hide it
setTimeout(dojo.hitch(blocker,"hide"), 2000);
});
});
</script>
</head>
<body>
<h1>Block it Test:</h1>
<div id="blockme">
<form id="login">
<p>Name:
<input type="text" id="user" name="user"></p>
<p><button id="startBlock" type="submit">Login</button></p>
</form>
</div>
</body>
</html>
So we know our single-use case works. We can create an instance of a _Blocker, and assign it to a node. We can do this over and over, as often as we like, but the process is a little cumbersome. With this structure in place, we can easily make an API to create and show the _Blocker, and be assured everything is “working”. We can wrap the _Blocker API with some simple functions: dojo.block() and dojo.unblock() …
Jumping right into optimization, and avoiding the possibility of future conflicts, we’ll wrap the code in a self-executing anonymous function, creating a closure:
var d = dojo;
d.declare("dojo._Blocker", null, {
// all that code
});
})();
We simply alias ‘d’ to the dojo namespace, and call d.declare. We can also assign any variables we want in this scope, and prevent them from polluting the global namespace. We are doing this for a reason, so let’s move on.
I don’t want to have to manually create a new dojo._Blocker every time I need to simply block a node after some action, so I am going to make a simple public API to do the magic for me. At first thought, you’d want to just wrap the existing code in a function, creating a new blocker every
time the function was called. Thinking forward, we want to create some kind of cache of blockers to
prevent duplicates from being created for a given node (in the case of repetitious failed logins, for instance). This is where the closure comes into play. First, we create a local object to store our blockers in:
var d = dojo;
d.declare("dojo._Blocker", null, {
// all that code
});
// cache of all blockers:
var blockers = {};
})();
Then, define a dojo.block function, which accepts the same API as dojo._Blocker: node, args. This way, we’ll be able to call dojo.block("someNode");, and the rest of the work will be done for us:
block: function(/* String|DomNode */node, /* dojo.block._blockArgs */args){
var n = d.byId(node);
var id = d.attr(n, "id");
if(!id){
id = _uniqueId();
d.attr(n, "id", id);
}
if(!blockers[id]){
blockers[id] = new d._Blocker(n, args);
}
blockers[id].show();
return blockers[id]; // dojo._Blocker
}
});
We’re still within this scope, so ‘d’ is still dojo, and the blockers variable is available to us. We’re doing a little extra work above, using the id attribute of a node and creating a unique id if one does not exists. You see the first thing we do is pass the node attribute through dojo.byId, which returns a DomNode from a passed string or existing domNode, a convention used nearly everywhere in Dojo, and Dijit.
The _uniqueId function is quite simple:
var id_count = 0;
var _uniqueId = function(){
var id_base = "dojo_blocked",
id;
do{
id = id_base + "_" + (++id_count);
}while(d.byId(id));
return id;
}
Simply create a function within this scope, and a counter to guarantee uniqueness. After that, we create a blocker if one does not already exist, call the .show() method, and return the instance.
We can either call .hide() on the returned instance, or create a second public API: dojo.unblock, which will accept a node or string. Adding this to our dojo.mixin call provides just that function:
block: function(node, args){
/* same as before */
},
unblock: function(node, args){
// summary: Unblock the passed node
var id = d.attr(node, "id");
if(id && blockers[id]){
blockers[id].hide();
}
}
});
Updating our basic HTML to use the new API is simple, and a lot shorter:
dojo.addOnLoad(function(){
dojo.query("#login").connect("onsubmit", function(e){
e.preventDefault(); // stop ‘real’ submission
dojo.block("blockme");
// wait 2 seconds, and hide it
setTimeout(dojo.hitch(dojo,"unblock","blockme"), 2000);
});
});
Now we can block and unblock any node we choose, with a really simple byId API. For example, onclick a button, send off an Ajax request, unblock after completion, and inject the response data:
dojo.query("#myButton").onclick(function(e){
dojo.block("someNode");
dojo.xhrPost({
url:"login.php",
handle:function(data){
dojo.byId("someNode").innerHTML = data;
dojo.unblock("someNode");
}
});
})
});
The last step in all of this is to wrap it into dojo.query, allowing us to make calls like:
.block()
.forEach(function(n){
n.innerHTML = "changed";
})
.unblock()
;
Writing the dojo.query plugin is the easiest part yet:
block: // d.NodeList._mapIn("block", true), // refs #7295
function(args){
return this.forEach(function(n){
d.block(n, args);
});
},
unblock: // d.NodeList._mapIn("unblock", true) // refs #7295
function(args){
return this.forEach(function(n){
d.unblock(n, args);
});
}
});
In my code you see a “refs #7295″. This refers to Dojo tracker ticket #7295, which exposes a private function in the core NodeList script to more easily wrap the block and unblock functions. This works because we have made the API similar to what Dojo expects internally. Until #7295 is fixed, we have to simply iterate over the NodeList, calling the block function and passing the individual node:
return this.forEach(function(n){ d.block(n, args); })
Our final example will include a small piece of server-side logic, mostly to simulate network latency, but also utilizing our newly created chain-able API:
dojo.addOnLoad(function(){
var $ = dojo.query;
$("#login").connect("onsubmit", function(e){
e.preventDefault(); // stop ‘real’ submission
var ub = $("#blockme").block()[0];
dojo.xhrPost({
form:"login",
handle:function(data){
ub.innerHTML = "<p>Server said:<br>"
+ data
+ "</p>";
$(ub).unblock();
}
});
;
});
});
And update the form to be a ‘real’ form, with an action:
<form id="login" action="hello.php" method="POST">
<p>Name:
<input type="text" id="user" name="user"></p>
<p><button id="startBlock" type="submit">Login</button>
</p>
</form>
</div>
The PHP is very small:
If you think the overlay is a little bland, the class we added initially allows you to style the overlay however you choose. Run over to AjaxLoad, and generate an icon. Then add a background property to nodes with the class dojoBlockOverlay
.dojoBlockOverlay {
background:#fff url(images/loading.gif) no-repeat center center;
}
</style>
As an added bonus, we can put this file somewhere in the Dojo source tree, and take advantage of the Dojo build and package system. Simply dojo.provide the component as the first line of code:
(function(d){
/* all above code */
})(dojo);
And save the file as dojo/Block.js … Then, when you want to use the Blocker API, simply issue a dojo.require call:
In doing this, our module (with heavy comments and readable variable names) will be optimized automatically by the build system, resulting in a simple, semi-obfuscated file, with a resultant size of 1.3KB before gzip.
Dojo really can be whatever you like it to be, and can easily bend to your preferred coding style. It also provides you all the tools you need to package, optimize, and modularize these kinds of plugins, without worry of conflicts with Dojo, or any other library.

Very well done. You gave me a solution to a current problem and taught me some dojo and Javascript at the same time. Thanks.
[...] is a horrible example, but we’ve only just implemented this function. Following the same pattern outlined in another similar article, we created dojo.show and dojo.hide functions, and wrapped them into into dojo.NodeList — anything [...]
why not create a submit button function to disable it after it has submitted the form or during a post request?
[...] functions, and added some other experimental plugins like a very simple block overlay based on an earlier article, and a cross-browser position:fixed implementation that is incomplete, but has potential. None of [...]
I’m having an issue with this code that I hope you can help me with. I’m doing some xhrPost calls that update select options dynamically. There is some latency which is why I want to use this code. The selects are contained inside a dojo tabcontainer.
The problem is that the dojo.block() “spinner” is not centering on the div I’m calling it with, but rather appears somewhere near the top of the page.
If the element which you want to block is located within a nested (border|tab)container structure the overlay is shown at the wrong place.
One solution is to make the overlay div as a child of this.node and use css to set the proper position with position:abolute top:0 left:0
Thank You for this great article!
Thanks for your reply. How do I go about setting the overlay div as a child of this.node? Do I have to modify blocker.js or can I do the mod outside of this file. Help is appreciated!
I have modified the blocker.js file as follows:
//.place(d.body(),”last”) becomes
.place(this.node,”last”)
and i added top:0, left 0 to the style.
This works.
@Sam – you would likely have to modify the blocker.js file directly. In the _Blocker constructor you can see the ‘this.overlay’ node being placed as a child of the body element ( .place(dojo.body()) ), so placing it appropriately would need to be done there.
There is an updated version of this code available in a mini-project I have called ‘plugd’
http://code.google.com/p/plugd/source/browse/trunk/block.js
It still places as child of the body, but I believe I adjusted the positioning code to accommodate tabs, margins and padding. My use case has never brought me to embedding this in complex layouts, and I try to avoid margins on target nodes to avoid excessive calculations.
Genius stuff Peter. Thanks for the link and this code! Works for me…
Amazing dojo tutorial, this is very much so under implemented!