Dive Into Dijit Forms

By on August 11, 2010 7:30 am
Notice: There is a newer version of this post available

As was illustrated with our Dive Into Dijit post, the Dijit library provides an extremely powerful, flexible set of Dojo-based widgets with which you may easily enhance the look and functionality of your web application.  These widgets include drop down / popup menus, dialogs, page layouts, trees, progress bars, and form elements.  When looking at these elements, it’s easy to see that Dijit enhances their presentation but this post will focus on enhancing functionality;  specifically, enhancing a basic form with usability improvements and validation.

Quick Dijit Implementation Review

The first step in introducing Dijit to any page is including Dojo:

<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js.uncompressed.js" djConfig="isDebug:true,parseOnLoad:true"></script>

The next step is requesting the Dijit theme stylesheet:

<style type="text/css">
@import "http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/resources/dojo.css";
@import dojox/"http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css";
</style>

The last step is adding the theme name as a class for the BODY element:

<body class="claro">

Enhancing Basic Form Elements

Note: this tutorial will use the declarative method of widget creation. You may create any Dijit widget programatically using dojo.behavior as described in Dive Into Dijit.

The first step in enhancing our static form is enhancing the form elements themselves.  Dijit provides a corresponding widget (sometimes two or three) for the different types of form elements. Using the declarative method of Dijit widget creation and the dojoType attribute, we’ll quickly widget-ize every piece of our static form:

<form action="process.php" method="get">
<!-- text inputs:  dijit.form.TextBox -->
<strong>First Name: </strong>
<input type="text" name="firstName" placeholder="Your Name" id="firstName" dojoType="dijit.form.TextBox" />

<strong>Website:  </strong>
<input type="text" name="website" placeholder="Your Website" id="website" dojoType="dijit.form.TextBox" />

<!-- radio buttons:  dijit.form.FilteringSelect -->
<strong>Favorite Color: </strong>
<select name="color" id="color" dojoType="dijit.form.FilteringSelect">
	<option value="">Select a Color</option>
	<option value="Red">Red</option>
	<option value="Green">Green</option>
	<option value="Blue">Blue</option>
</select>

<!-- radio buttons:  dijit.form.CheckBox -->
<strong>Send Emails? </strong>
<input type="checkbox" id="checkbox" checked="checked" dojoType="dijit.form.CheckBox" />

<!-- radio buttons:  dijit.form.RadioButton -->
<strong>Email Format: </strong>
<input type="radio" id="radio1" name="format" checked="checked" dojoType="dijit.form.RadioButton" /> 
<label for="radio1">HTML</label>
   
<input type="radio" id="radio2" name="format" dojoType="dijit.form.RadioButton" />
<label for="radio2">Text</label>

<!-- submit button:  dijit.form.Button -->
<input type="submit" value="Submit Form" label="Submit Form" id="submitButton" dojoType="dijit.form.Button" />
</form>

Boom: our static, boring form elements have been themed and extended with extra functionality. A few notes with regard to widgets we created above:

  • The FilteringSelect widget duplicates the functionality of a native SELECT element by:
    • Setting an initial value based on one of its options having a selected attribute.
    • Enforcing a fixed set of possible results based upon the values and text of each OPTION element.
    • Providing keyboard accessibility
  • The FilteringSelect widget adds the following functionality to the basic SELECT element:

    • You may type values into the FilteringSelect; autocomplete is employed.
    • If an invalid value is provided, an error message is provided to the user.
    • You get more control over the display when the widget is disabled.
  • Dojo 1.5 introduces strategies for employing placeholder text within INPUT elements to save you time in adding focus/blur events to accomplish the same functionality.

Now that the basic form has been widget-ized and themed, we can add basic validation functionality.

Form Validation with Dojo

As with just about every client-side problem, Dojo’s got a great solution for form validation. Luckily there are only a few key components required for basic form validation.

dijit.form.ValidationTextBox

A precursor to the overall validation of a form is deciding which elements are required. Say we want to require the first field; the dojoType of that will will change from dijit.form.TextBox to dijit.form.ValidationTextBox:

<input dojoType="dijit.form.ValidationTextBox" required="true" placeholder="Your Name" missingMessage="Ooops!  You forgot your first name!" name="firstName" id="firstName" type="text" />

Since required="true" has been added to the widget, an error icon and tooltip (with error message) will display if the user fails to place text into the box. A custom error message can be placed within the missingMessage attribute, otherwise a generic message will display.

What if the field requires special validation of the pattern of input? That’s where the regExp attribute comes in:

<input dojoType="dijit.form.ValidationTextBox" required="true" regExp="(https?|ftp)://[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/\.=]+" name="website" placeholder="Your Website" id="website" type="text" />

Not only is the website field now required but the value of the field must pass the regular expression test provided by the regExp attribute.

Validation Utilities with dojox.validate

The dojox.validate library includes numerous utility functions and regular expressions for validating form element values. These utility functions can validate email addresses, URLs, phone numbers, zip codes, and much more. An example usage of dojox.validate with a ValidationTextBox would look like:

<script type="text/javascript">
dojo.require("dojox.validate");
dojo.require("dojox.validate.web");
</script>

<strong>Email:</strong>
<input type="text" required="true" name="email" id="email" dojoType="dijit.form.ValidationTextBox" validator="dojox.validate.isEmailAddress" />

The validator attribute is a link to the validation function for emails. dojox.validate is especially helpful if you don’t feel comfortable with regular expressions. There are also locale-specific packages within dojox.validate. The API docs provide a complete listing of dojox.validate helpers.

dijit.form.Form with the onSubmit Event

Now that our required fields are in place, we’ll enhance the wrapping form element with a dijit.form.Form dojoType:

<form dojoType="dijit.form.Form" action="process.php" method="get">
<script type="dojo/method" event="onSubmit">
<!--
if (this.validate()) {
	alert('Form is valid, submitting!');
} else {
	alert('Form contains invalid.  Please complete all required fields.');
	return false;
}
return true;
-->
</script>
<!-- form fields here -->
</form>

Accompanying the dijit.form.Form is a special script element. Within this Dojo-specific script is a this.validate() test, acting on the dijit.form.Form instance, which validates the entire form based on require="true" inputs. You could also add your own custom validation within the code block as well.

The dijit.form Collection

I’ve only touched the most-used Dijit widgets within my example above. There are several more outstanding form widgets within Dijit; let’s take a look at a few other helpful widgets!

DateTextBox

Asking the user to format a date properly can be a nightmare, especially if other form fields within the page rely on the contents of a given date field. Dijit provides a dijit.form.DateTextBox class which displays a user-friendly calendar widget for users to select a date on.

<!-- when the user focuses on this element, the calendar appears -->
<input dojoType="dijit.form.DateTextBox" required="true" invalidMessage="Please provide a valid date." type="text" name="date" id="date" />

CurrencyTextBox

The dijit.form.CurrencyTextBox class helps the user to properly format and validate currency per a given locale.

<!-- {fractional:true} means you must provide cents -->
<input dojoType="dijit.form.CurrencyTextBox" required="true" constraints="{fractional:true}" currency="USD" invalidMessage="Please provide both dollars and cents." type="text" name="weekly_wages" id="weekly_wages" value="2000" />

Textarea

The dojox.form.Textarea class enhances a given TEXTAREA element so that the element grows in height as the user types.

<textarea dojoType="dijit.form.Textarea" name="comments"></textarea>

Enhancing Basic Dijit Widgets with DojoX Alternatives

As nice as many of the Dijit widgets are, DojoX hosts numerous enhanced widgets that solve problems that many basic widgets cannot. The following are a few notable DojoX form widgets.

BusyButton

dijit.form.Button works great but what if I want to disable the button (to avoid double submissions) and provide a feedback message (i.e. “Sending form….”) when clicked? We could use dojox.form.BusyButton to do just that:

<!-- assuming dojox.form.BusyButton has been required... -->
<button dojoType="dojox.form.BusyButton" busyLabel="Sending Data...">
    Send Data
</button>

CheckedMultiSelect

What if our SELECT element allows for multiple selections? That’s the perfect opportunity to use the dojox.form.CheckedMultiSelect widget:

<!-- assuming dojox.form.CheckedMultiSelect has been required... -->
<select multiple="true" name="rockers" dojoType="dojox.form.CheckedMultiSelect">
	<option value="Oasis">Oasis</option>
	<option value="Rod Stewart" selected="selected">Rod Stewart</option>
	<option value="Coldplay" selected="selected">Coldplay</option>
	<option value="Kings of Leon">Kings of Leon</option>
</select>

PasswordValidator

What if our website features a form that allows updating/changing of passwords? The dojox.form.PasswordValidator provides all the functionality you need to quickly implement that system:

<!-- assuming dojox.form.PasswordValidator has been required... -->
<!-- pwValidate is the name of your function that verifies the current password is correct -->	
<div dojoType="dojox.form.PasswordValidator" name="pwValidate">
	<!-- pwType=old is where the user must place their current password -->
	<input type="password" pwType="old" />
	<!-- pwType=new is where the proposed new password must be placed -->
	<input type="password" pwType="new" />
	<!-- pwType=new is where the user verifies their new pass -->
	<input type="password" pwType="verify" />
</div>

Reminder: JavaScript validation is not a substitute for server-side validation; JavaScript simply enhances the user experience by providing instant feedback to the user.

FileUploader

File uploading without enhancement is probably the worst form control available. The dojox.form.FileUploader provides a great solution for making the process more streamlined:

<!-- assuming dojox.form.FileUploader has been required... -->
<div class="uploadBtn" dojoType="dojox.form.FileUploader" hoverClass="uploadHover" pressClas="uploadPress" activeClass="uploadBtn" disabledClass="uploadDisable" uploadUrl="/upload-files.php">Select Files</div>

The dojox.form Collection

The dojox.form namespace hosts a huge host of widget enhancements, including:

  • BusyButton – button with special disable/busy label states
  • CheckedMultiSelect – turns your SELECT element with the “multiple” attribute into a series of checkboxes for usability
  • DropDownStack – disable/enable form elements based upon a selection
  • RangeSlider – allows values to be chosen via a sliding scale
  • Rating – easily creates UI for ratings (star ratings)
  • …and much more!™

Great Dijit & Dojox Resources

The Dijit library is much more than just gloss on your elements — it’s a hugely functional set of classes to make life easier for both you, the developer, and your users.

Comments

  • It’s super easy to set Dojo up for validation.

    The only problem that I’ve encountered is that it is not possible to validate a textarea.

    Although I haven’t checked out version 1.5 yet so maybe that is covered now

  • Brock Heinz

    Great post, but I’m hoping you can clarify something. I’m hoping you can expand upon what you mentioned in the following,

    “Reminder: JavaScript validation is not a substitute for server-side validation; JavaScript simply enhances the user experience by providing instant feedback to the user.”

    How can server and client side validation be harmonized? For example, let’s assume that I have a unique constraint in my database on email address. I can obviously setup an instance where I make an AJAX call to validate that email address during the user data entry. But what happens if the validation passes initially, but in a concurrent case, another form submission is executed, and the email wanted to be used by first user is committed to the database by the second user. So, now I’m validating the input at the server, and I’ve obviously got a problem, and I have to render the input form once again. Is there a simple way I can leverage the dijit API to show the user exactly where the error occurred following dijit notation, error styles, etc?

    I’m thinking there’s gotta be something better than following this: http://docs.dojocampus.org/dijit/form/ValidationTextBox-tricks

    Any help you can offer here will be greatly appreciated!

  • @Brock Heinz: It depends on your setup. What I meant by my reminder can be thought of with the following workflow:

    1. User arrives at form.
    2. User inputs their email address, widget checks server via AJAX to see if the email address is unique.
    3. User leaves email field, inputs information into other fields.
    4. User submits form.
    5. Server side language (PHP, etc.) duplicates any JS checks (valid phone number format, all required fields have been completed, email is unique, etc.).
    6. If everything is valid, commit. If errors are detected, return the user to the form page and notify them of errors.

    You always want to duplicate JS validation with server-side validations in one form or another. You could configure your processing server-side script to use the same snippet of PHP to run as AJAX and during form submission. If you don’t have a server-side validation on the processing page, you’re bound for trouble as the user may not be working in a JS-enabled environment.

  • Brock Heinz

    @David Walsh

    Thanks for the prompt response! You and I are on the same page, but here’s what I’m missing.

    Let’s assume #6 (from your list above) proves that the data is no longer valid. A different user has nabbed that email address (for whatever reason). Now, my server side code must re-render the form, and tell the user the problem. As that form loads, I’m going to need to find a way to duplicate the error handling built into dijit: change the color of the email component, show the error icon, maybe set focus there, etc.

    Now grant it, the likelihood of this happening isn’t great, but I’d like to figure out how to handle this scenario. Any thoughts? I’ve come across the following, and it leads me to believe that once I get deeper into the API, I can do this.


    this.editor11._editor.state = “Error”;
    this.editor11._editor._setStateClass();
    dijit.setWaiState(this.editor11._editor.focusNode, “invalid”, “true”);
    this.editor11._editor.displayMessage(inData.message.toString());

    http://dev.wavemaker.com/forums/?q=node/2632

    Lemme know what you think!

    Thanks again,
    Brock

  • Great question Brock! The solution provided there is great. Using my demo form (click on the image at the top of the post), the following will do exactly what you’re looking to do:


    var emailDijit = dijit.byId('email');
    emailDijit.state = 'Error';
    emailDijit._setStateClass();
    dijit.setWaiState(emailDijit,'invalid','true');
    emailDijit._maskValidSubsetError = true;
    emailDijit.displayMessage(emailDijit.getErrorMessage('The email address you provided is taken'));

    Unfortunately I don’t see a more elegant solution at this time. Possibly a good enhancement for future dijit.form.ValidationTextBox!

  • Brock Heinz

    @David

    Thanks for the confirmation on this :)

    On a related topic, the Dojo docs say “There is one small catch here: this validator will be called onType, meaning it will be sending requests to the backend on every key stroke. If you do not want that to happen, you may want to add another check in the beginning so that it always returns true if the validation text box is on focus.”

    http://docs.dojocampus.org/dijit/form/ValidationTextBox-tricks

    So… what’s the best way to check for focus? I am doing something like the following:

    dojo.addOnLoad(function() {
    dijit.byId(“email”).validator = function (value, constraints) {
    var ret = dojox.validate.isText(value);
    if (ret && !this._focused) {
    //do AJAX, set ‘ret’ based on text returned from ajax
    }
    return ret;
    }
    });

    In using myDigit._focused (referenced using ‘this’ above), I’m still seeing that I’m hitting the server twice when I leave the ’email’ component. Is there a better way to check for focus? Perhaps doing something with myDigit.focusNode?

    Thanks again, David!

    Brock

  • Brock Heinz

    Is there a bug in the select example you provide here:

    https://user.sitepen.com/~dwalsh/dijit-forms.html
    ?

    Based on what I see as options in the select, I would anticipate that if you choose the ‘Select a Color’ option from the list, and then change focus, an error would occur. Is that assumption wrong?

    Thanks,
    Brock

  • Good question Heinz — that dropdown isn’t required/validated so no error will occur.

    David

  • @David

    In your example, if you set ‘required=true’, and then select the ‘Select a Color” option, Dojo won’t treat that as an error, and I think it should. In your case, the option’s value is an empty string… to me, this just seems wrong. Thoughts?

    Brock

  • Seems like a hack to me, but adding a ‘value=”null”‘ attribute to the select tag does the trick to solve the issue described above. Here’s my source:

    http://o.dojotoolkit.org/forum/dijit-dijit-0-9/dijit-support/how-ensure-nothing-selected-default-required-filteringselect-fie#comment-19881

    Brock

  • (Here’s a bit more: to get the desired effect, you have to remove the ’emtpy’ option, and then set an attribute on the select box of value=”” or value=”null” :)

  • iDVB

    Great article! Thanks.

    How would you go about programmatically creating a dijit.form.Form form that same form example you have above and still ensure the various html form attributes are passed into the dijit.form.Form that will replace it?

    Eg. I have a form with action=”myForm.php” but once it gets programmatically changed to dijit.form.Form the action is not imported as well. Do I have to manually test and pass in existing attributes? ParseOnLoad does it for you… so why can’t Programmatically it do it too?

  • Bradley

    @Brock… re: email check

    When you submit your original email address check, store the email in a database table of temp emails (temp_emails) and everytime you validate the email, validate both the actual table and the temp_emails table.

    When a user submits, remove the email from the temp table (And any other emails they tried). Run a CRON job every 5 minutes that clears out all emails in the temp_email table where it was added 20 minutes ago or more.

    Also works for usernames.

  • Dusko

    Great tools!

    Is there a way to avoid the -thing in a form to make a nice grid similar to jsf’s ?

    Nice would be:

    Thanks, Dusko

  • Dusko

    Does not like tags. Here again…

    Is there a way to avoid the table-thing in a form to make a nice grid similar to jsf’s h:panelGrid ?

    Nice would be:
    form dojoType=”dijit.form.Form” columns=”2″

    Thanks, Dusko

  • Dan

    Why doesn’t anyone ever explain how to nest _multiple_ widgets inside of each other _programmatically_? Like multiple form input widget inside of a form widget?

    I know there (sometimes) is a “content” attribute which you can pass a widget reference to. But that sill leaves out the _multiple_ part.

  • sudhiendra

    for dojox.form.checkedmultiselect , it is converting each element to input type of checkbox but with no name and value. so when we submit the form the values does not to the server. what can be the solution?

  • Geert

    Please check this post. the text is good readable, but the examples and code snippets are not. Get a number of errors on this post. (see below)

    – Uncaught Error: Could not load class ‘dijit.form.TextBox dojo.js:14
    – Failed to load resource: the server responded with a status of 403 (Forbidden) http://www.google-analytics.com/ga.js
    – EXPERIMENTAL: dojox.validate — APIs subject to change without notice. /js/release/dojo/dojo/_firebug/firebug.js:8
    – Failed to load resource: the server responded with a status of 404 (Not Found) https://user.sitepen.com/~dwalsh/Form1.png
    – Failed to load resource: the server responded with a status of 404 (Not Found) https://user.sitepen.com/~dwalsh/Form3.png
    – Failed to load resource: the server responded with a status of 404 (Not Found) https://user.sitepen.com/~dwalsh/Form4.png
    – Failed to load resource: the server responded with a status of 404 (Not Found) https://user.sitepen.com/~dwalsh/Form5.png
    – Failed to load resource: the server responded with a status of 404 (Not Found) https://user.sitepen.com/~dwalsh/Form2.png

  • Dylan Schiemann

    @Geert, thanks for pointing this out, we have fixed this regression.