Monday, May 19, 2008

SnTT : Dojo. It's not just eye candy

If you thought that Dojo was all about fancy widgets and eye candy for you web apps, then you might have missed another advantage of using Dojo. In fact, it's not just Dojo. Most of the popular toolkits provide the features to make OO in JavaScript easier. I'm using Dojo, so my third post on Dojo is all about how I used OO in Dojo.

The challenge.

Let me explain the challenge. I needed to build  a few HTML forms (without resorting to the whole lotus workplace forms solution). The forms, while fairly short (the longest being 30 multiple choice questions), were complicated by the fact that a large majority needed to include the 'Other - please specify' additional to the simple radio and checkbox fields. In addition the users could also choose different paths through questions. As a user answers the questions the subsequent questions that they need to answer change.

I wanted to have the simplest user experience possible and in my opinion that means, if you can't fill in a field then it should be hidden away. In short, I wanted the field that captures the 'other' detail to be hidden until the 'other' choice is selected. Likewise, fields that are not available based on previously selected choices are also hidden. 

To make it even simpler for the user I wanted to maintain the hidden fields choices. If the user changed their mind a few times, they would not need to repeat answering questions. I would also need to remove all the hidden values before the form was submitted so that the data sent to the server represented exactly what was on screen.

It sounds like a lot of work, for something so simple as filling in a few multiple choice fields - but I don't think of it has extra programming. Think of it as an investment in reducing the number of support calls.

So why Dojo ?

Sure, you could do all of this in plain old JS. Functions for this and functions for that, but wouldn't it be nice to be able to just write some simple JavaScript. Something like...

if(fielda.mandatorySelected()==false) {
// then record or show errors
}

or 

fielda.visible(true);
fieldb.visible(false);

and maybe...

fielda.display();
fieldb.display();


Dojo.Declare.

Dojo gives you a great framework for OO using Dojo.declare for building JS classes. Its simple to implement, simple to reuse and easy to read. If you are reusing it then you're writing less lines of code. Which means less that the browser needs to download which in turn makes the pages load faster. 

How did I use Dojo Declare ?

In the Notes form, the HTML looks like the screen shot below. A div for the radio or checkbox field with a unique id 'q8' and a div for the other field with a unique id of 'q8-other'.  All pretty standard stuff.



I started by calling my class scius.AuditField. I won't reproduce all the functions as I've attached the JS file here.

dojo.declare("scius.AuditField", null, 
{ ... } );

then I added in some member variables and the constructor. The constructor allows me to initially specify the visibility, and if this field has the 'other' field.

_id:null,
_other:"other",
_hasOther : null,
_isVisible : null,
_otherIdSuffix : "-other",
_otherFieldSuffix  : "other",
constructor : function(id, isvisible, hasOther) {
this._id = id;
this._hasOther = hasOther;
this._isVisible = isvisible;
},

some setters and getters (or properties), which I can use to determine the visibility or set the visibility.

visible : function(isVisible) {
this._isVisible = isVisible;
},
isVisible : function() {
return this._isVisible;
},

The hiding and showing using CSS classes through hide() and show() which is called by the display() function. The display function also checks to see if it needs to display the 'other' field (see the source code attached).

hide : function(fieldid) {
dojo.removeClass(fieldid,'form-fields');
dojo.addClass(fieldid,'form-fields-hidden');
},
show : function(fieldid) {
dojo.removeClass(fieldid,'form-fields-hidden');
dojo.addClass(fieldid,'form-fields');
},


Next is the checking of mandatory fields function. Note I reused an existing function to determine the actual value of the radio button via the 'isRadioChecked(rbo)' line. I guess it should really be part of the class or a utility class of its own.....maybe one day it will !

mandatorySelected : function() {
var rbo= document.forms[0][this._id];
if(isRadioChecked(rbo)) {
if (this._hasOther && this.hasValue("other")) {
var oth = document.forms[0][this._id+this._otherFieldSuffix];
if (oth.value=="") {
return false;
} else {
return true;
}
} else {
return true;
}
} else {
return false;
}
},

So how did I use this class in the Form ?

As I had around 30 questions, I decided to store the questions in an array and initialize them in the Notes forms JSHeader object. Creation is fairly simple. 

The format is scius.AuditField(domid, visible, hasOther).

var qlist = new Array();
...
qlist[8] = new scius.AuditField("q8",false, false);
qlist[9] = new scius.AuditField("q9",false, true);
....

I have a checkConditionalQuestion() function that gets called from the onClick() of each field, which checks the visibility of dependent fields.


function checkConditionalQuestion(cond_question) {
...
} else if (cond_question=="7") {
if (qlist[7].hasValue("yes")) {
qlist[8].visible(true);
qlist[9].visible(false);
}else if (qlist[7].hasValue("no")) {
qlist[9].visible(true);
qlist[8].visible(false);
}
qlist[7].display();
qlist[8].display();
qlist[9].display();
} else if (cond_question=="9") {
qlist[9].display();
}

...
}

You've already seen the checking of mandatory field values and of course there is the emptying of the invisible fields. Called after validation and before the submit.

function emptyInvisible() {
for (var i = 1; i <= 30; i++) {
if (qlist[i].isVisible()==false) {
qlist[i].empty();
}
}
}

Summary.

Using the Dojo.declare to create classes is more readable than the JS prototype way. The format is closer to the way you would create Object in LotusScript and Java and so is familiar and easier to read. I only scratched the surface of what's possible and I can see areas for improvement. If you are interested, here it is in action.  

Next.

I think that a database containing the three articles as a download would be a useful starting place if you need to implement similar forms. I've already started pulling out the various components into a standalone application and I'd like to tidy up a few areas before releasing it. As soon as its ready I'll post it.  I can't say when - it all depends on the workload over the next few months. 

5 comments:

  1. Nice write up. I'm ding something very similar, "yes" "no" radio buttons where if you pick yes you must leave enter a text explanation. I've been using hidden divs to show or hide the explanation text area.

    I'm looking forward to looking at your code.

    Thanks,

    Jeff

    ReplyDelete
  2. Thanks for the comment.

    ReplyDelete
  3. Thanks for the writing. I guess these kinds of post helps us on the way. // Patrick

    ReplyDelete
  4. Thanks for this writing. I guess these kinds of posts helps us on our way! // Patrick

    ReplyDelete
  5. Hi,

    very good article.

    can't wait for the demo database.

    ReplyDelete