Dijit provides drop-in, degradable replacements for standard
push buttons and checkboxes, yet it also gives you a lot of
sophisticated options, such as the kinds of buttons that you normally
find in toolbars. Let's start out with an ordinary Button
and work our way up through more
sophisticated options.
Figure 13-4 shows a button, and Table 13-12 gives the rundown on the most basic
kind of button dijit, a Button
,
which inherits _FormWidget
.
Table 13-12. Button properties
Name | Comment |
---|---|
| Used to provide the label for the button in markup or via programmatic creation. |
| A Boolean value
designating whether to display the text label in the
|
| A class specifying an image that can make a button appear like an icon. |
| An extension point that is called in response to a click. This is a very common method to override. |
| A method accepting an
HTML string that can change a |
Tip
Unlike TextBox
and its
descendants, the Button
widgets
require you to use the setAttribute('value', /*...*/)
function,
inherited from _FormWidget
, to
set value because Buttons don't have a widget
value so much as they have a form value that is relayed
to the server.
Let's dust off the code from Example 13-4 and provide some
final polish by replacing those ugly buttons, as shown in Example 13-8. Remembering to add an obligatory
dojo.require("dojo.form.Button")
to the head of the page, the replacement is straightforward. Note
how convenient providing the onClick
handler in markup is for this
situation.
Example 13-8. Typical Button usage
<button dojoTye="dijit.form.Button" type="submit">Sign Up! <script type="dojo/method" event="onClick" args="evt"> alert("You just messed up...but it's too late now! Mwahahaha"); </script> </button> <button dojoTye="dijit.form.Button" type="reset">Reset</button>
The Button
's iconClass
is especially snazzy in that it
doesn't just replace the entire button with an icon. Instead, it
embeds the icon into the button alongside an optional label if one
is specified and showLabel
is
true
. For example, if you had a
small 20 × 20px thumbnail image of some spam that you wanted to
embed into the "Sign Up!" button, you could do it by including
iconClass="spamIcon"
in the
button tag and ensuring that the following class appeared in your
page:
.spamIcon { background-image:url('spam.gif'); background-repeat:no-repeat; height:20px; width:20px; }
Of course, you can provide any customized styles you'd like for buttons to make them look any way that you'd like by applying an inline style or a custom class.
Because form dijits leverage inheritance so heavily, they
often have common ancestors that provide common functionality for
descendant classes. ToggleButton
is one such class; it inherits from Button
and adds in functionality for a
button that has an on/off state, like a RadioButton
or a CheckBox
. The only notable attribute it
adds is checked
, which can be
toggled with setAttribute
.
Although you would probably use a more conventional control
like CheckBox
to designate on/off
states, you could choose to use ToggleButton
directly, or subclass it and
implement your own custom ToggleButton
. The onChange
extension point (common to all
form dijits) is one particularly useful feature:
<button dojoType="dijit.form.ToggleButton"> <script type="dojo/method" event="onChange" args="newValue"> console.log(newValue); </script> </button>
Most of the buttons that appear in a toolbar such formatting a
text with italics, bold, underline, etc., use the ToggleButton
. The Menu
and MenuItem
dijits are introduced in Chapter 15.
Warning
Several button dijits are not included in their own
designated resource file. In particular, you should dojo.require("dijit.form.Button")
for
Button
, ToggleButton
, DropDownButton
, and ComboButton
. While it may seem odd to
require one thing when you actually want another, the rationale is
that the (inheritance-driven) implementations for the various
buttons are so similar that they are included in the same physical
file to minimize overhead in acquiring resources from the server.
Additionally, recall that the mapping between classes simulated
via dojo.declare
and resource
files is not designed to be a one-to-one mapping (although
traditional object-oriented programming philosophy often deems it
so).
This technique remains a source of consternation amongst Dojo circles, as the overhead from a synchronous request to the server would be a moot point in a production setting that uses the facilities from Util to optimize layers for each page of an application.
These kinds of nuances result from so many (well-intentioned) competing interests in the Dojo community.
CheckBox
descends directly
from ToggleButton
and is a
standard drop-in replacement for an ordinary <input type="checkbox">
element.
Using it is as simple as requiring it into the page and then using
the dojoType
tag. We might
introduce it into Example 13-4 page by disabling
the "Sign Up!" button until after user click the CheckBox
to confirm that they're aware of
our covert intentions to spam them:
<div
name="confirmation" dojoType="dijit.form.CheckBox"> <script type="dojo/method" event="onClick" args="evt"> if (this.checked) dijit.byId("signup").setAttribute('disabled', false); else dijit.byId("signup").setAttribute('disabled', true); </script> </div
> I understand that you intend to spam me.<br> <button id="signup" disabled dojoType="dijit.form.Button" type="submit"> Sign Up! </button>
Figure 13-5 shows a series
of CheckBox
dijits.
Warning
The reason that DIV
tags
are being used instead of INPUT
tags is because you cannot embed SCRIPT
tags inside of INPUT
tags, and if you try, it is almost
a certainty that the browser will strip them out. Thus, if you
want to use SCRIPT
markup
inside of dijits, you should be especially cognizant that you
can't use INPUT
tags. If
degradability is so important that this isn't acceptable for your
application, simply write the methods in pure JavaScript instead
of markup.
Thus, to programmatically check the CheckBox
, you might use the setValue(true)
method, which would check
the box as well as set its checked
attribute to true
and its value attribute to true
.
Tip
If it is really important to ensure every page is as
degradable as possible, you can go the extra mile to explicitly
include ordinary HTML attributes in tags. For example, instead of
just specifying <input
dojoType="dijit.form.CheckBox"/>
, you could also
include the extra type
attribute, resulting in <input
dojoType="dijit.form.CheckBox
type="checkbox"/>
.
Like ordinary HTML checkbox
elements, however, there is a difference in the
state of the checkbox versus the
value of the checkbox. The state of the
checkbox is either that it is or is not checked, and you can detect
the state via the standard checked
attribute. The value
attribute, however, may take on
non-Boolean values to pass special values to the server if the box
is checked when the form is submitted. For example, a tag like
<input name="pleaseSpamMe"
value="yes"/>
would append pleaseSpamMe=yes
to the query string if
the form was submitted via GET
.
(The default for value
is
"on"
.)
The confusion comes in, however, when you find out that the
getValue
method and the value
attribute do not always return the
same thing. The way it works is that getValue
returns whether the box is
checked regardless of what the actual value
attribute happens to be. The
rationale for this design is that the most common use case for a
getValue
function would be to
determine a visible on/off state—not getting the actual value, which
may not reflect the on/off state.
Because it is possible to get yourself tangled up in the
differences between some of the different possibilities, consider
some of the common cases for a CheckBox
dijit:
<input id="foo" dojoType="dijit.form.CheckBox"></input>
Example 13-9 shows a series of calls to manipulate the dijit along with extensive commenting to show the effects.
Example 13-9. Typical CheckBox usage
/* Check the initial state */ dijit.byId("foo").checked // false dijit.byId("foo").getValue( ) // "on" /* Use setValue with true */ dijit.byId("foo").setValue(true) // check the box and set the value to true dijit.byId("foo").checked // true dijit.byId("foo").getValue( ) // true /* Use setValue with false */ dijit.byId("foo").setValue(false) //uncheck the box and set the value to false dijit.byId("foo").checked // false dijit.byId("foo").getValue( ) // false /* Use setValue with a String */ dijit.byId("foo").setValue("bar") //check the box and set the value to "bar" dijit.byId("foo").checked //true dijit.byId("foo").getValue( ) // "bar"
These most common use cases for the CheckBox
are using getValue
and setValue
with Boolean values as
parameters, so the chances are reasonably good that you won't need
to wade through the potentially esoteric effects that can arise when
you start mixing state and values.
Warning
Here's one particularly unintuitive combination that accentuates some of the issues involved in mixing state and value that you should be especially aware of:
dijit.byId("foo").setAttribute("value", "foo") // changes the value attribute but does not check the box dijit.byId("foo").value // "foo" dijit.byId("foo").getValue( ) //false, because the box is not checked
The unintuitive part is that after setting a value you
wouldn't expect a call to getValue(
)
to return false
because common idioms in JavaScript involve the ability to test a
string value, and if it's not ""
, null
, or undefined
, then it evaluates as true
. However, the thing to remember is
that getValue( )
consistently
returns whether the box is checked or not—regardless of what is
actual value
attribute is set
to be. In this case, the box is not checked, so getValue( )
returns false
.
Likewise, the dijit's onChange
event will not fire for a
dijit.byId("foo").setAttribute("value",
"foo")
method call since the checked state of the box
did not visibly change.
A RadioButton
is a drop-in
replacement for the ordinary HTML equivalent descending from
CheckBox
, and like its HTML
equivalent, is conceptually a group of checkboxes in which only one
can be selected at any given time. Recall that each button in a
radio group has the same value for name
but distinct values for value
. Figure 13-6 shows a RadioButton
group.
We might even further refine our working example (Example 13-4) by asking users
how many times a day they'd like us to bother them. We could use
radio buttons as shown in Example 13-10 to achieve this purpose quite
easily, having first required dijit.form.CheckBox
in the
page.
Warning
Although you'd think that last sentence was a typo, it's
not. Recalling that you dojo.require
resources, not individual
widgets, it turns out that the dijit.form.CheckBox
resource provides
dijit.formCheckBox
and dijit.form.RadioButton
.
This warning is along the same lines as the previous warning
about how the dijit.form.Button
resource provides multiple dijit implementations.
Example 13-10. Typical RadioButton usage
<input name="spamFrequency" value="1 per day" dojoType="dijit.form.RadioButton"> 1 per day<br> <input name="spamFrequency" value="2 per day" dojoType="dijit.form.RadioButton"> 2 per day<br> <input name="spamFrequency" value="3+ per day" dojoType="dijit.form.RadioButton"> 3+ per day<br>
A DropDownButton
is simply
a descendant of Button
that when
clicked produces a drop-down menu with options you can select—just
like you're used to seeing in a toolbar. DropDownButton
and dijit.Menu
are closely related, in that a
Menu
is one of the most common
vehicles for supplying a drop-down list; TooltipDialog
is another common option.
Figure 13-7 shows the DropDownButton
dijit.
More complete coverage is given to Menu
(and the individual MenuItem
s it contains) in Chapter 15. Example 13-11, however, demonstrates a
DropDownButton
in action and
should get the point across. Note that the first child of the parent
DropDownButton
node is a label
that appears on the button.
Example 13-11. Typical DropDownButton usage
<button dojoType="dijit.form.DropDownButton"> <span>Save...</span> <div dojoType="dijit.Menu"> <div dojoType="dijit.MenuItem" label="Save"> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> <div dojoType="dijit.MenuItem" label="Save as..."> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> <div dojoType="dijit.MenuItem" label="Save to FTP..."> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> </div> </button>
If you want to use a DropDownButton
as part of a form
submission, you could do so by creating a hidden INPUT
element and programmatically setting
its value via the constituent MenuItem
's onClick
method. The most common uses for
DropDownButton
, however, normally
involve an application-level behavior, such as saving a
document.
Tip
In general, form fields that are submitted to a server via a
form submission should be visible to the user at the time of
submission. In that regard, DropDownButton
may seem a bit misplaced
with its inclusion into dijit.form
because it isn't
that kind of form control. The reason it
appears in this section is that it is a descendant of Button
, and it would make even less
sense to try to have a Button
ancestor living in another namespace.
A ComboButton
inherits from
DropDownButton
, but with a twist:
it provides a reserved area that produces a drop-down when it is
clicked, whereas if you click on the "other" part of the button that
is initially visible, it invokes a default action. For example, you
might have a "Save" button that triggers an ordinary save action
when clicked, while clicking the drop-down portion of the button
produces a menu with options such as "Save", "Save as . . . ", "Save
to FTP site", and so on. Figure 13-8 shows a
ComboButton
before and after
clicking on the expander.
Figure 13-8. Left: a ComboButton before clicking on the expander; right: the ComboButton after clicking on the expander
Example 13-12 illustrates using
a ComboButton
.
Example 13-12. Typical ComboButton usage
<button dojoType="dijit.form.ComboButton"> <span>Save</span> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked the button itself"); </script> <div name="foo" dojoType="dijit.Menu"> <div dojoType="dijit.MenuItem" label="Save"> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> <div dojoType="dijit.MenuItem" label="Save As..."> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> <div dojoType="dijit.MenuItem" label="Save to FTP..."> <script type="dojo/method" event="onClick" args="evt"> console.log("you clicked", this.label); </script> </div> </div> </button>
Notice that the label for the ComboButton
is still provided via the
first child element, <span>Save</span>
in this
case, and the options that are provided via the drop-down are just
the same as with a DropDownButton
.
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.