Real World Dojo, part One (Basic Validation)
The Scenario:
I’ve kind of been nibbling around the edges of Dojo for a while, but
I’m at a place in this project where I really need to buckle down and
learn it. Since I’m having so much trouble finding real-life examples of
the basics, I figured I’d share what I’m coming across.
I have a very simple proof-of-concept form that shows the basics of the one
that forced me to buckle down. It looks like this:
<head>
<title>Validation Test (raw HTML)</title>
</head>
<body>
<form action="/beta/test/client_validated" method="POST">
Name: lt;input type="textbox" name="Name" /><br />
URL: <input type="textbox" name="Url" /><br />
File: <input type="file" name="File" /><br />
<input type="Submit" value="OK" />
</form>
</body>
</html>
(For now, the server action just verifies that the Name and URL fields have
values).
In the real-world example, there’s a required field that’s very
easy to forget. And it’s easy to forget that the database is picky about
URL’s.
If this were an ASP.NET application, I’d just toss in a couple of
validators and move on. That isn’t an option for the platform
we’re using, so here we go.
Switch to Dojo Fields
My first stab was just blindly following the tutorials I could find, adding
in the Dojo infrastructure and marking a couple of fields as required:
<html>
<head>
<title>Validation Test (switch to Dojo)</title>
<link id="themeStyles" rel="stylesheet"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/tundra/tundra.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js"
djConfig="parseOnLoad: true, isDebug: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.ValidationTextBox");
</script>
</head>
<body>
<form action="/beta/test/client_validated" method="POST">
Name: <input dojoType="dijit.form.TextBox" type="textbox" name="Name"
required="true" trim="true" intermediateChanges="true" /><br />
URL: <input dojoType="dijit.form.ValidationTextBox" type="textbox"
dojo.regExpGen="dojox.regexp.url" required="true" name="Url" /><br
/>
File: <input type="file" name="File" />
<input type="Submit" value="OK" />
</form>
</body>
</html>
Switch to Dojo Form
Sadly, it wasn’t that simple, so I took the next step and switched
everything except the file element to a Dojo widget (a.k.a. dijit):
<html>
<head>
<title>Validation Test</title>
<link id="themeStyles" rel="stylesheet"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/tundra/tundra.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js"
djConfig="parseOnLoad: true, isDebug: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Form");
dojo.require("dijit.form.Button");
</script>
</head>
<body class="tundra">
<form action="/beta/test/client_validated" method="POST"
id="TheTest" encType="multipart/form-data" dojoType="dijit.form.Form"
validate();" onReset="return false;">
Name: <input dojoType="dijit.form.ValidationTextBox" type="textbox"
name="Name" required="true" trim="true" intermediateChanges="true" /><br />
URL: <input dojoType="dijit.form.ValidationTextBox" type="textbox"
dojo.regExpGen="dojox.regexp.url" required="true" name="Url" /><br />
File: <input type="file" name="File" /><br />
<button dojoType="dijit.form.Button">OK
<script type="dojo/method" event="onClick">
console.dir(dijit.byId("TheTest").attr('value'));
</script>
<script type="dojo/method" event="startup">
var form = dijit.byId("TheTest");
// set initial state
this.attr("disabled", !form.isValid());
this.connect(form, "onValidStateChange", function(state){
this.attr("disabled", !state);
});
</script>
</button>
<button dojoType="dijit.form.Button" type="reset">Reset</button>
</form>
</body>
</html>
I snagged the actual validation pieces from Dojo’s online unit test
suite (non-automated). The important pieces were at Dojo
Test Form Validation State. That portion of their website is one of the
best resources I’ve found as far as seeing how to actually do something.
(If all else fails, read the source code...Dojo’s source code is
extremely well-written and -commented, but it’s lacking when it comes to
usage examples).
The URL regular expression validator isn’t working correctly
(it’s accepting anything I input), and the Reset button doesn’t do
anything. But it’s getting closer.
Change the Reset button’s declaration to:
<button dojoType="dijit.form.Button" type="reset">Reset
<script type="dojo/method" event="onClick">
dojo.byId("Name").value="";
dojo.byId("Url").value="";
dijit.byId("Submit").attr("disabled", true);
</script>
</button>
(I don’t know why that didn’t work automatically...I’m
probably declaring the button wrong) and the regular expression part of the URL
input to
[http|https|ftp]://[A-Za-z0-9-_]+\\.[A-Za-z0-9-_%&\?\/.=]+
(dojox.regexp.Url is in the development trunk, but it didn’t make it into
1.2.0 apparently), and we have something. (Yes, that regexp is pretty weak.
But it’s good enough for what I’m doing).
The final version looks like:
<html>
<head>
<title>Validation Test</title>
<link id="themeStyles" rel="stylesheet"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dijit/themes/tundra/tundra.css">
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/dojo/1.2.0/dojo/dojo.xd.js"
djConfig="parseOnLoad: true, isDebug: true"></script>
<script type="text/javascript">
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Form");
dojo.require("dijit.form.Button");
</script>
</head>
<body class="tundra">
<form action="/beta/test/client_validated" method="POST"
id="TheTest" encType="multipart/form-data" dojoType="dijit.form.Form"
validate();" onReset="return false;">
Name: <input dojoType="dijit.form.ValidationTextBox" type="textbox"
name="Name" id="Name" required="true" trim="true"
intermediateChanges="true" /><br />
URL: <input dojoType="dijit.form.ValidationTextBox" type="textbox"
regExp="(https?|ftp)://[A-Za-z0-9-_]+\.[A-Za-z0-9-_%&\?\/\.=]+"
required="true" name="Url" id="Url" /><br />
File: <input type="file" name="File" /><br />
<button id="Submit" dojoType="dijit.form.Button">OK
<script type="dojo/method" event="onClick">
console.dir(dijit.byId("TheTest").attr('value'));
</script>
<script type="dojo/method" event="startup">
var form = dijit.byId("TheTest");
// set initial state
this.attr("disabled", !form.isValid());
this.connect(form, "onValidStateChange", function(state){
this.attr("disabled", !state);
});
</script>
</button>
<button dojoType="dijit.form.Button" type="reset">Reset
<script type="dojo/method" event="onClick">
dojo.byId("Name").value="";
dojo.byId("Url").value="";
dijit.byId("Submit").attr("disabled", true);
</script>
</button>
</form>
</body>
</html>
I’m tempted to take out the intermediate steps, so this isn’t so
long. But I think they might be useful to anyone who was having the same
problems I did.
Of course, this form doesn’t actually do anything.
I’ll save that for next time...this bad boy’s too long as it
is.