Skip navigation

For a long time I have been trying to find the right JavaScript framework for serious AJAX development.  At this point there are a few choices.  However, they all have a long way to go.  It seems that Dojo is the most mature one around and it has a pretty good user base.  However the documentation and examples still are lacking.

Recently I picked up a small side project.  I didn’t want to spend a whole lot of time on it so using a JavaScript framework would really speed things up.  I chose Dojo and development has gone fairly smoothly.  The only issue is there are some real mysteries about the framework that I had a hard time solving.

The first issue is the ComboBox and FilteredSelect.  I had the hardest time finding an easy way to simply add items to them.  Dojo uses a data model that is similar to ASP.NET data binding.  The difference is in ASP.NET you can add individual items to all the controls instead of binding if you want to.  With Dojo you cannot (from what I can tell).  So, the easiest way to add items to a ComboBox or FilteredSelect is this way:

var options = new dojo.data.ItemFileWriteStore({data: {identifier: ‘value’, items:[]}});
for (var i = 0; i < collection.length; i++) {
options.newItem({name: collection[i].Name, value: collection[i].ID});
}
dropDownNode.store = options;

Take note of the identifier portion of the ItemFileWriteStore constructor.  It tells the drop down the property name of the item that corresponds to the value of the drop down item.  I had a really hard time finding this information, and when I did find it, it wasn’t in the official documentation.  This is a very simple concept that any UI developer needs to know when building UI.

The next issue I faced, and actually I had faced in the past, was using the Dojo grid.  I had no luck with the grid in the past and decided I wouldn’t waste my time trying again.  The reason it is so difficult is getting it to bind correctly with JSON is not very easy.  The JSON has to be formatted just right or the grid will not work, and I’ve never been able to get it formatted right apparently because the grid has never worked for me.

So I decided to build my own simple grid.  I didn’t need anything complicated, it just needs to display in a table format and allow the user to select a row (for editing, deleting etc.)  Below is the solution I came up with.

Here’s the template:

<table class=”dojoxGrid-row-table list” dojoAttachPoint=”containerNode”>
<thead dojoAttachPoint=”headerNode” class=”dojoxGrid-header”>

</thead>
<tbody dojoAttachPoint=”bodyNode”>
<tr>
<td><img src=”images/5-1.gif” /></td>
</tr>
</tbody>
</table>

And the widget:

dojo.provide(“hockey.widgets.list”);

dojo.declare(“hockey.widgets.list”,
[dijit._Widget, dijit._Templated],
{
templatePath: dojo.moduleUrl(“hockey”,”widgets/layout/list.htm”),
templateString: “”,
list: null,
columns: null,
selectedItem: null,
emptyListText: “”,

selectedId: function() {
if (this.selectedItem != null) {
var returnValue = this.list[this.selectedItem.itemRowIndex][“ID”];

if (!isNaN(returnValue))
return parseInt(returnValue);
}

return 0;
},

selectedIndex: function() {
if (this.selectedItem != null) {
return this.selectedItem.itemRowIndex;
}

return 0;
},

removeRow: function(index) {
if (this.bodyNode.childNodes.length > index) {
this.bodyNode.removeChild(this.bodyNode.childNodes[index]);
}
},

postCreate: function() {
this.inherited(“postCreate”, arguments);
},

clear: function() {
if (this.headerNode.hasChildNodes()) {
while (this.headerNode.childNodes.length > 0) {
this.headerNode.removeChild(this.headerNode.firstChild);
}
}

if (this.bodyNode.hasChildNodes()) {
while (this.bodyNode.childNodes.length > 0) {
this.bodyNode.removeChild(this.bodyNode.firstChild);
}
}
},

showLoading: function() {
this.clear();

var row = document.createElement(“row”);
var cell = document.createElement(“cell”);
var loading = document.createElement(“img”);

loading.src = “images/5-1.gif”;

cell.appendChild(loading);
row.appendChild(cell);

this.bodyNode.appendChild(row);
},

bind: function() {
var instance = this;

this.clear();

// generate columns
if (this.columns != null && this.columns.length > 0) {
for (var columnIndex = 0; columnIndex < this.columns.length; columnIndex++) {
var header = document.createElement(“th”);
header.innerHTML = this.columns[columnIndex].headerText;
header.className = “dojoxGrid-cell”;

this.headerNode.appendChild(header);
}
}

// generate rows
if (this.list != null && this.list.length > 0) {
for (var itemIndex = 0; itemIndex < this.list.length; itemIndex++) {
var row = document.createElement(“tr”);
row.className = “dojoxGrid-row”;
row.itemRowIndex = itemIndex;

// loop through each column
for (var columnIndex = 0; columnIndex < this.columns.length; columnIndex++) {
var cell = document.createElement(“td”);
var cellValue = “”;

if (this.columns[columnIndex].formatString)
cellValue = this.list[itemIndex][this.columns[columnIndex].dataField].format(this.columns[columnIndex].formatString);
else
cellValue = this.list[itemIndex][this.columns[columnIndex].dataField];

if (!cellValue)
cellValue = ” “;

cell.innerHTML = cellValue;

if (this.columns[columnIndex].bindCallback) {
this.columns[columnIndex].bindCallback(this.list[itemIndex], cell);
}

row.appendChild(cell);
row.onclick = function() {
instance.selectItem(this);
}
}

this.bodyNode.appendChild(row);
}
} else {
var row = document.createElement(“tr”);
var cell = document.createElement(“td”);

cell.innerHTML = this.emptyListText ? this.emptyListText : “Nothing to show”;

if (this.columns)
cell.setAttribute(“colspan”, this.columns.length);

row.appendChild(cell);
this.bodyNode.appendChild(row);
}

this.containerNode.style.display = “none”;
setTimeout(function() { instance.containerNode.style.display = “table”; }, 50);
},

selectItem: function(item) {
// unselect the last item
if (this.selectedItem != null) {
dojo.removeClass(this.selectedItem, “dojoxGrid-row-selected”);
}

// select the next item
if (item != null) {
dojo.addClass(item, “dojoxGrid-row-selected”);
this.selectedItem = item;
}

console.log(this.selectedItem);
}
});

It is a very simple grid, but it does exactly what I need it to.

The last issue I faced was uploading a file.  I wanted to be able to upload an image file using Dojo without having to use something like Adobe AIR (although it is really cool, I didn’t have time to learn it for this project).  After much searching around I found a few examples.  Most of the examples I found were for older versions of Dojo and did not work.  I finally pieced together exactly what I needed to do.  All that needs to be done is the upload input has to be wrapped in a form.  The form should be built just like it would if an actual postback were occurring.  Then, to upload the file use the following code:

// gather all parameters from a form
dojo.io.iframe.send({
form: “imageForm”,
hanldeAs: “text”,
load: function(data) {
// handle callback here
},
error: function(data) {
// handle errors here
}
});

The form property should be the id of the form you want to post.  Make sure the form’s enctype is multipart/form-data and the method is post.  On the page that the form is being posted to make sure to return something.  And for whatever reason, that something has to be wrapped in a textarea tag or Dojo will assume an error has occurred.

There you have it, things that I have learned about Dojo that do not seem to be common knowledge.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: