This section provides some hands-on usage for a pretty intuitive
dijit—the dijit.form.NumberSpinner
—to warm you up for the chapters that follow. First, we'll work
through creating the dijit in markup, and then we'll follow up with
programmatic creation.
As you learned from an earlier section on the parser, it's
pretty trivial to stick a dijit into the page. You require in the
resources, provide the dojoType
attribute in a tag, and have the parser go to work. For
completeness, Example 11-4
shows how we'd follow that very same pattern to instantiate a
NumberSpinner
dijit.
Example 11-4. Creating the NumberSpinner widget in markup
<html> <head> <title>Number Spinner Fun!</title> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" /> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" /> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js" djConfig="parseOnLoad: true" ></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.form.NumberSpinner"); </script> <head> <body class="tundra"> <form> <!-- some really awesome form --> <input dojoType="dijit.form.NumberSpinner" constraints="{min:0,max:10000}" value=1000> </input> </form> </body> </html>
While you'll often create dijits in markup, programmatic
creation is no less common and the process is the very same as
creating any other Function
Object
because that's exactly what a dijit is—a Function Object
. In general, the
constructor for a dijit accepts two parameters. The first is an
Object
that provides properties
that should be passed in, and these are the same properties that you
would be including in the tag if you were creating in markup. The
second parameter is a source node or the id
for a source node that identifies the
placeholder that the dijit should replace:
var d = new module.DijitName(/*Object*/props, /*DOMNode|String*/node)
Example 11-5
programmatically creates the NumberSpinner
and produces the very same
effect as Example 11-4.
Example 11-5. Programmatically creating the NumberSpinner widget
<html> <head> <title>Number Spinner Fun!</title> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" /> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" /> <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js" ></script> <script type="text/javascript"> dojo.require("dijit.form.NumberSpinner"); dojo.addOnLoad(function( ) { var ns = new dijit.form.NumberSpinner( //props { constraints : {min:0,max:10000}, value : 1000 }, "foo" //node id ); // do other stuff with ns here... }); </script> <head> <body class="tundra"> <form> <input id="foo"></input> </form> </body> </html>
This particular example displays a nice little text box with a
control that allows you to adjust the value from either the arrow
keys on the keyboard, by clicking the arrow controls on the dijit
itself, or though manual keyboard entry. In any case, the min
and max
and key/value pairs are part of the
constraints
attribute that can be customized to form the
upper and lower values for the spinner with the arrow keys or when
clicking on the controls; the value
attribute provides the default value
just like in ordinary HTML. Manually changing the value via manual
keyboard entry, however, still changes the value, which may trigger
a tooltip-style error message. Figure 11-3 illustrates what
happens.
Tip
Recall that Dojo attempts to supplement the existing fabric
for developing web applications—not override it. Thus, common
attributes for form elements such as the value
attribute in the previous code
listing's input
element still
work just like normal.
Figure 11-3. Left: a NumberSpinner dijit changing its value via keyboard or mouse control; right: the default display when manual keyboard entry enters a value that is out of bounds
Warning
While techniques from djConfig
showed key/value pairs
expressing objects constructed in markup without the surrounding
curly brackets like djConfig="parseOnLoad:true,isDebug:true"
,
it is more the exception than the rule. Dijit requires that Object
attributes in markup be expressed using braces like constraints="{min:0, max:100}"
.
You've probably already made the connection about the NumberSpinner
's keyboard entry and a11y,
but there are some other niceties that are worth trying out right
away. You've no doubt noticed the numeric formatting that is
automatically applied to separate every three digits of numbers
greater than 999. Note that if you were rendering the page for a
supported locale that used a different separator for the digits, it
would have happened automatically: locales like
en-us use commas to separate values, like
1,000, while Spain, the es-es
locale, for example, uses dots to separate the digits, like 1.000.
Figure 11-4 demonstrates.
Try it for yourself by modifying your default locale in djConfig
. For example, to set a default
locale of Spain, you could do the following:
djConfig="locale:'es-es'"
Warning
Remember that any values in djConfig
that are strings need to
contain additional quotes around them. The syntax for declaring an
associative array inline makes this easy to forget, and
unfortunately, the error messages that can result from forgetting
it are not always helpful to point you in the right direction. Any
djConfig
settings need to be
loading prior to Base bootstrapping.
Figure 11-4. Dijits handle special formatting for the supported locales right out of the box with no additional configuration required; the top NumberSpinner was configured with en-us while the bottom NumberSpinner was configured with es-es; the dijit internally took care of the formatting details
Another great out-of-the-box feature that Dijit supports is
the notion of controls being typematic—that is, they respond in
special ways to holding down a mouse button or keyboard key. If you
try holding down the mouse button on one of the controls for the
NumberSpinner
, you should notice
that it gradually increases for the first 10 or so numbers and then
eventually speeds up and moves rapidly. Not surprisingly, keyboard
navigation works the very same way. The Page Up and Page Down
buttons also work and adjust the values by multiples of 10 by
default.
In addition to being able to programmatically write ordinary
JavaScript to control and extend widgets, Dojo also provides the
ability to define the JavaScript directly in markup by including a
special type="dojo/method"
attribute in SCRIPT
tags. This
can be very convenient for designers as well as anyone who needs to
rapidly prototype a new idea. What's especially notable about
defining methods in markup is that the keyword this
refers to the containing widget, so
you have instant access to the context you'd expect.
Consider the following update to the example code listing that defines methods in markup:
<!-- snip --> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.form.NumberSpinner"); dojo.require("dijit.form.Button"); </script> </head> <body class="tundra"> <form> <div
dojoType="dijit.form.NumberSpinner"jsId="mySpinner
" constraints="{min:0,max:10000}" value=1000> <script type="dojo/method"> dojo.mixin(this, { reset : function( ) { this.setValue(1000); } }); </script> </div> </form> <button dojoType="dijit.form.Button" onClick="mySpinner.reset( )"> reset</button> </body> </html>
To sum up the effect of the changes, the jsId
attribute gave the NumberSpinner
a global variable name
mySpinner
, which was referenced
in a Button's onClick
method. The
actual body of the reset
method
was established by the special script
tag included inside of the dijit.
The script
tag providing
anonymous dojo/method
is executed
after its constructor
runs, so
that any values passed in via attributes included in markup would be
available.
Also, note that whereas the previous listing used an input
element to create the spinner, the
new listing uses a div
tag. The
reason why an input tag will not work with the updated listing is
that it does not allow innerHTML
.
The tag had to be switched to a type that does allow innerHTML
in order for it to work. If
you're wondering why a div
tag
wasn't used all along, it really comes back to one primary issue:
the ability to have a semantically correct page that works without
any JavaScript involved. In other words, the previous form using an
input
element is a semantically
correct input
control even if
JavaScript were disabled (for whatever reason), whereas the div
-based spinner is not. Most of the
time, this isn't an problem, but when designing a degradable page,
it is very important to know your basic HTML and be aware of these
issues.
Warning
The dojo/method
and
dojo/connect
script tags do not
work inside of marked up elements that do not allow innerHTML
. This isn't a Dojo thing; it's
in accordance with the HTML specification. Although not
demonstrated with this example, SCRIPT
tags containing a type="dojo/connect"
attribute allow you
to set up connections in markup using the same pattern.
While the additional reset button may make a great addition for a mouse-based control, note that pressing the Escape key on the keyboard would have reset the spinner to its original value without any additional work at all.
As an improvement that produces the very same effect but with
less code, consider the following change to the dojo/method script
tag:
<script type="dojo/method" event="reset"> this.setValue(1000); </script>
Instead of being executed automatically a single time after
the constructor, which is the case for anonymous dojo/method script
tags, this approach
performs the work of actually creating the reset method and
attaching it to the widget on your behalf. If there had been
arguments involved, an additional args
attribute could have been specified.
For example, args="foo,bar,baz"
would have allowed for passing in three named arguments to a method
defined in markup.
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.