This tutorial is for Dojo 1.6 and may be out of date.

Up to date tutorials are available.

Form Management with dojox.form.Manager

While there are elements within Dojo to allow for simple form validation, occasionally you may want a more powerful solution. The Dojo Toolkit offers a fantastic solution for detailed form management: dojox.form.Manager.

Getting Started

A recurring problem for any form-based application is an easy way of managing all of the elements in a form, including collecting values, validating values, and handling form resetting and submission. More often than not, this is done manually—which can often be time consuming and brittle. The Dojo Toolkit offers a comprehensive solution that works with both HTML-based forms and Dijit-based forms: dojox.form.Manager.

The Problem

Traditionally, form management has always been cumbersome. Two approaches are generally taken: either know all of the form elements (including identifiers) beforehand and write any handling code based on this knowledge, or write a system that will try to automatically detect all of the elements in a form and create a generic handling system for it. The first approach, while generally the most accurate, can become a maintenance nightmare (particularly in applications with a large number of forms); the second approach tends to be very brittle, and ends up becoming bloated (usually due to the slow but steady addition of business rules as time goes on).

dojox.form.Manager combines the best of both worlds—it allows you to simply wrap your form so that you don't have to know each individual element (if you don't want to), but gives you the flexibility to create custom methods to handle specific business rules. In addition, it will work with both regular HTML form elements as well as any Dijit-based ones!

Setting up the Manager

Setting up your form(s) to use the manager is easy: simply require the manager itself, and then set your form element to be of type dojox.form.Manager, like so:

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


<form data-dojo-type="dojox.form.Manager" id="myForm">
	...your form elements here...
</form>

That's all for the basic setup; now you're ready to start managing your form elements.

Unlike most Dijit-based widgets, dojox.form.Manager is not intended to be used/created programmatically; it's possible to do, but the design intention was to be able to apply the Manager to existing HTML forms. When using dojox.form.Manager, you should always use it declaratively, and make sure you have parseOnLoad: true as part of your data-dojo-config attribute of the script element that includes the Dojo base (i.e. dojo.js).

Adding in observer hooks to your form elements

The next step in setting up your form to be managed by dojox.form.Manager is to add a custom attribute to the form elements to be managed (both HTML-based and Dijit-based ones) called observer. This custom attribute tells the Manager what to execute, in the Manager itself, when a change is made in your form element.

The value in each observer attribute is a comma-delimited list of methods to execute when something changes on the form element. For example, if we have an HTML checkbox input and we wanted to run the methods showValues and logRadio when someone clicks on it, we'd set it up like so:

<input type="checkbox" name="foo" observer="showValues, logRadio" />
<input type="text" name="txt" observer="showValues" dojoType="dijit.form.TextBox" intermediateChanges="true">

This setup tells the Manager to execute both methods each time the state of the checkbox changes, and to call showValues when the value of the dijit.form.TextBox widget changes. If you only have one method observing changes, then just list the single method (no comma). The intermediateChanges property can be used to fire the change event on every change made to an input or delay the observer event until after the widget has lost focus.

Note that dojox.form.Manager is not set up to be completely HTML 5 data-attribute compliant; you'll be adding non-standard attributes to your form elements as we go. This means that if HTML validation is extremely important to you, using dojox.form.Manager will cause your document to fail validation.

Setting up your observer methods

Finally, you'll need to actually implement your observer methods. dojox.form.Manager handles this using the special declarative script technique available with the dojo.parser; inside of your main declarative object, you'll use script blocks to make your definitions. The net effect of adding these script blocks is to extend the instance of the Manager with functionality specific to your form's needs. Here's an example:

<input type="checkbox" name="foo" observer="showValues, logRadio" />
<script type="dojo/method" event="showValues" args="value,name">
	if(name){
		console.log("name = ", name, " value = ", value);
	}
</script>

Let's break this down.

The MIME type of the script block

This is a way of telling the Dojo parser that the content that is contained within the block has special meaning. The Dojo parser recognizes two "special" types: dojo/method and dojo/connect. The first tells the Dojo parser that we are extending the underlying object with a new method definition; the second tells the Dojo parser to make a connection (via dojo.connect, the main event mechanism in the Dojo Toolkit) to an existing method.

Keep in mind that when you create a script block using type="dojo/method", you may be overriding any methods that already exist on the underlying object. Using the dojo/connect type ensures that you are not clobbering anything that already exists—but at the same time, you are not preventing the original method from executing when called.

The "event" attribute

This is the name of the method either being defined (in the case of dojo/method) or being connected to (in the case of dojo/connect).

When defining methods using the declarative technique, don't forget that the this keyword can be used, and will be a reference to the object you are defining the methods against.

The "args" attribute

This is an optional attribute; but if it exists, it is the list of the parameters that will be passed to the function, in order.

When using Dojo's declarative script techniques, the script is applied to the parent object—so make sure your script blocks are nested in the right place.

Our example from above, showValues, is a pretty typical observer with dojox.form.Manager. Notice the signature of the observer: value and name. The observer—when executed—will either be passed no arguments, a single value argument, or both. Because of this, you must account for all of these possibilities when implementing your observer methods.

Helper methods of the Form Manager

Now that we have the basics of setting up your form management, we can tap into some of the helper methods of the Manager itself to aid you. There are a few basic methods to be used:

  • gatherFormValues: can take an array of names, a dictionary of names, or nothing. If an array or dictionary is passed only those elements that match in the form will be returned, otherwise all of the values in the form is collected and returned.
  • setFormValues: takes a dictionary of name/value pairs, and will match the keys in the dictionary to the corresponding form elements in your form, and set the value.
  • isValid: ensures that any elements in a form with validation attached passes validation.
  • validate: force any validation to be run, and return a boolean indicating the validity of the form.

There are quite a few other useful methods in the Manager, such as enable/disable and addClass/removeClass, that can be used as well. Take a look at the API documentation for more details.

Inspecting the form

The Manager also has a set of inpection methods you can use on your form when you wish. The main one is inspect; this takes an inspector function, and optional state and defaultState objects. The optional state object can be a name/value dictionary or an array of names to inspect. The idea is that you create the inspector function (for example, if you need certain elements in your form to match certain business rules) and the Manager will take care of finding all elements in the form for you—including any Dijit-based form elements. Your inspector function should take three arguments:

  1. name: the name of the element being inspected;
  2. node: either a single node (or a widget's domNode), or an array of such nodes;
  3. value: a supplied value.

In addition, your inspector function should return a state; this state can be whatever you'd like it to be, but something should be returned regardless.

dojox.form.Manager can also deal with groupings of elements through special use of a dojoAttachPoint attribute. However, functionality based on attach points are somewhat limited. Take a look at the source of our demonstration to see how to define attach points in your form.

Events on your form

Finally, the Manager pre-defines two events for you to override: onReset and onSubmit. These are self-explanatory, but they will allow you to do any kind of special handling when either event occurs. For example, if you wish to prevent any form submission, you would add this to your markup:

<script type="dojo/method" event="onSubmit">
	//	prevent form submission
	return false;
</script>

If you want your form to be "ajaxy", you can use any of Dojo's xhr methods in your onSubmit handler; just remember to return false; in it to prevent the browser's normal actions.

Let's put it all together

Now that we have a good overview of dojox.form.Manager, let's put it all together!

View Demo

Conclusion

The dojox.form.Manager is a powerful tool for form management; it allows you to inspect your form easily (including validation), get and set values in your form quickly, deal with standard form events, and a lot more. It allows you to mix-and-match standard HTML form elements and Dijit-based form elements quickly and easily; in addition, it allows you to easily implement custom methods so that you can work with your standard business rules in a clean, modular fashion.

Happy form management!