Friday, November 21, 2008

Discovering Dojo for Domino: Part 4 - Event Handlers, the DOM and Data Stores

Work and family have been pretty busy, so this next post has taken a little longer than I expected

OK, so dijits are pretty and all web 2.0-ish, and the date picker is nice, but there is more to dojo than that. The whole point of a javascript framework is to simplify common tasks and allow you to extend your application.

Basic event handling

Firstly, a common task on a web form: the user clicks a radio button and some of the fields are hidden or shown, depending on the choice. No too difficult, but tedious if you want to change the properties on multiple items. With the dojo.query method, this becomes alot simpler:

Step 1  Set the event handler for dojo. Your field HTML Attributes become:
"dojoType='dijit.form.RadioButton' onclick='clickRadioButton' "
Notice that I have assigned a text string to the onclick event, not called a function directly. This is because dojo provides event handlers which can override and extend the default event handlers. This is the function which will be called when the event fires.

Step 2  Load the dijit code in your JS Header

Step 3  Add a function to your script library to handle the onClick event. For example:
function clickRadioButton(  ){
if( this.getValue == 'Hide' ) {
dojo.query('.myClass').style('display', 'none' );
} else {
dojo.query('.myClass').style('display' , '' );
this within the function is the dijit object, and has access to all the dijit functions, including getValue. This useful function gives you pretty much a value you can test as you would in Notes, so this.getValue will give you the following:

TextBoxonChangeText within the field
DateTextBoxonChangea Javascript date/time object
TimeTextBoxonChangea Javascript date/time object
CheckBoxonClickCheckbox label if being selected, false if being unselected
RadioButtononClickthe label of the selected radio button
FilteringSelectonChangethe alias of the selected option

Accessing the DOM

The dojo.query function takes any valid CSS3 selector (e.g. '.myClass', '#myDiv' , 'TD' etc) and returns an array of node elements. You can chain queries to get items nested within others. Dojo has functions which modify element properties and these can modify all node elements in a collection without the need to iterate over each item in turn. So
dojo.query('#myDiv').query('.myClass2').style('display' , 'none' );
would get all elements with the class 'myClass' inside the div 'myDiv' and set they display property to 'none'.

There are a range of functions for getting and setting various node attributes which can be used in this way.

Filtering Selects and Data Stores

A Filtering select is a dojo dijit like a combo box. As discussed in my previous post, there are problems with using a filtering select with a Domino dialog lists because they generate incomplete HTML.

What dojo actually does is parse the DOM and load your select options into an internal data store and point the dijit to that data store. Examining the dijit object using Firebug, I found that the options are loaded, but they contain a trailing end of line character (\n), which breaks the select in firefox but appends a trailing space in IE. Neither is pretty. I wrote the following function to 'fix' the data in the data store:

function fixSelect( dijitID ){
// get the data store used by the select
var thisStore = dijit.byId( dijitID ).store;

// function to update store items
var itemUpdate = function(listItem){
if([0].indexOf( "\n" ) > 0 ){[0] =[0].split( "\n" )[0] ;
// function to handle errors
var gotError = function() {
// your error handling goes here ;

// now call the fetch.
var items = thisStore.fetch( {
onItem: itemUpdate,
onError: gotError

This looks a little complicated, because the fetch method is asyncronous. This means we cannot simply call store.fetch, assign the results to a variable, then iterate over the results. Instead we pass fetch(() the function to call as each item is returned (there are also ways to work on the complete item set). The first parameter passed to the function is the returned item, which our function can then do something with.

The other alternative is to use a text field, define it as a FilteringSelect dijit in the HTML Attributes and point it to a data store you have created yourself. This is what you will need to do to use AJAX to replace your list choices.

Data stores are a powerful construct with what seems like a whole api of their own and I have only just skimmed the surface so far. I intend to post more when I get my dynamic picklists working (by this I mean AJAX updates of the select choices depending on a choice in another field).

Some more on using DateTextBox

The date format used by dojo is yyyy-mm-dd, and dates are stored in the text field (and returned to Domino) are in that format. You can change the display format or let dojo detect your users locale and use the appropriate format, but you can't change the format in which the data is submitted.

If you want to pre-populate your field with a date (such as @Today) you actually need to split the date and re-format it into the appropriate string first


Robert Ibsen Voith said...

Michelle, I have been trying to play around with your Dojo calendar fix (which you posted info about in the comments of Vikto Krantz's Dojo Calendar blog). Have you been able to get your calendar widget to work on IE7? I have a Domino 8.5 server (and thus Dojo 1.1.1). The test-calendar works fine on Firefox 3 and Opera 9.6. IE7 complains about; failed loading /domjs/dojo-1.1.1/dojo/../mywidgets/widget/Calendar.js with error: [object Error]
Could not load 'mywidgets.widget.Calendar'; last tried '../mywidgets/widget/Calendar.js'caltest.html (line 21)

Anonymous said...

I got the same error... Do you have an idea?