Jul 292008
 

Today's tutorial: Dojo Tag Cloud Widget using dojo.data store

So I though it was time to post another Dojo widget tutorial. This time I have written a widget for displaying a tag cloud. Even though you could use it for any kind of links, the most common use is obviously tags from your blog or other website. The TagCloud widget is using dojo.data and any kind of store to display the tags. Let’s jump into some code shall we. In the bottom of this tutorial you will find links for downloading all the code.

First we need to add our core Dojo and dependencies to our JavaScript in the head of our HTML page.

[code=”xhtml”]
[/code]

You can see that we added the ItemFileReadStore, after that we have the topic of the tutorial: mydojo.TagCloud and last we added the dojo.parser so that we can create our widgets by HTML markup. You can see that the name space for my widget is mydojo.TagCloud. That means that I’ve created a folder named mydojo in the same folder as the dojo, dijit and dojox folders.
Now we add the dojo.data store and the markup HTML for our Tag Cloud widget inside our body.

[code=”xhtml”]

[/code]

You can see what it looks like in example 1.

The link above will give you the default TagCloud widget. If you look at the code, through Firebug naturally, you’ll see that it is made up of a DIV element with an unordered list, UL, inside. The list has all the tags from our dojo store with different sizes. Larger for tags with more values.

Most people want a tag cloud to look like a tag cloud though :lol: For that we need to add some style to our code inside the head tag.

[code=”css”]

[/code]

See example 2.

As you can see in the style classes above we declared a font and width inside a class named “TagCloud”. That class is always added to the div tag that the widget creates. That default class name can be changed and you can also add other classes that I will explain later. We also declared that any UL tag inside “TagCloud” will not have any margin or padding. That is because the browser automatically adds some margin and padding to unordered lists and we don’t want that for our tag cloud. Last in our style sheet we add the definition of our list item, LI. We want it to display inline and not be in a list format.

Lets add some more style to our tag cloud before I explain what attributes we can pass in to our widget. We add some more attributes to our existing classes and add two more rules.

[code=”css”]

[/code]

View it in example 3.

Tag Cloud Widget Attributes

There are a number of attributes we can pass in to change behavior and/or functionality of our widget. If we open up our widget JavaScript file we will see a number of variables at the top. You can actually change all of those by just adding attributes to our widget HTML code. They are documented inline in the code but lets look at a few of them.

[code=”javascript”]//sizeDifference: Boolean
//If we should show larger font for more tags
sizeDifference: true,

//fontMaxSize: Integer
//The size of the largest tag in percent
fontMaxSize: 200,

//fontMinSize: Integer
//The size of the smallest tag in percent
fontMinSize: 100,[/code]

So we can choose not to have a difference in size on the tags. How would we add that? Let’s look at the example below.

[code=”xhtml”]

[/code]

See what it looks like in example 4.

We have just added the sizeDifference attribute with a value of false to our widget code. Other then that it is the same code as example 3 above.

We can also choose to have bigger difference in size on tags. As you can see I’ve added the fontMaxSize attribute to our widget DIV tag.

[code=”xhtml”]

[/code]

Really large fonts in example 5.

I mentioned earlier that you can also add more style sheet classes besides the default class “TagCloud” to your widget. By adding the normal “class” attribute to our DIV tag. Classes will be appended after the “TagCloud” class. The default class can also be changed by changing the “baseClass” attribute.

What happens when the user clicks the tag? Well, since I don’t know what should happen because it depends entirely on what your tags represent and also on what kind of server the code sit on. In this blog, based on WordPress, the tag when clicked would take you to a url that look like:

[code=”javascript”]/index.php/tag/the_tag[/code]

So how do we do that? Well, one of the variables/attributes in our TagCloud widget is “clickFunction” with a default value of “tagItemClicked”. So you can add JavaScript funtion named “tagItemClicked” or pass in a new value to “clickFunction”. I’m going to show you the first way. Let’s add the following code to our JavaScript in the head of our HTML page.

[code=”javascript”]function tagItemClicked(sTag){
alert(“You clicked on ” + sTag);
}[/code]

See example 6.

If you click a tag it will alert the tag. Not very useful so let’s change it a little to make it work on my blog.
[code=”javascript”]function tagItemClicked(sTag){
location.href = ‘/index.php/tag/’ + sTag;
}[/code]

Updated to example 7.

Two other very important variables that we can change in our widget are the names of the item value names in our data.store. Default are “name”, “slug” and “count” and you can obviously keep those. Many times however you might not have the luxury over what your Ajax (XHR) call will return, or you just don’t like mine. :cry: In that case you can change them by adding the attributes “tagAttr”, “slugAttr” and “countAttr”.

Below is the JSON i’ve been calling with the ItemFileReadStore in all our examples so far.

[code=”javascript”]{items:[
{name:”ajax”, count:15},
{name:”beth”, count:2},
{name:”blog”, count:4},
{name:”calendar”, count:3},
{name:”calendar entries”, slug:”calendar-entries”, count:2},
{name:”Collaboration University”, slug:”collaboration-university”, count:14},
{name:”cu-2007″, count:11},
{name:”demo”, count:6},
{name:”dojo”, count:31},
{name:”domino”, count:20},
{name:”family”, count:9},
{name:”google”, count:2},
{name:”ibm”, count:5},
{name:”lotusphere”, count:11},
{name:”lotus quickr”, slug:”lotus-quickr”, count:27},
{name:”movies”, count:2},
{name:”podcast”, count:3},
{name:”snapps”, count:30},
{name:”templates”, count:17},
{name:”tutorial”, count:11},
{name:”widget”, count:4},
{name:”xhr”, count:3}
]}[/code]

As you can see it uses the default “name” and “count” attributes for each item. If however that would be changed to “word”, “special” and “number” everywhere…

[code=”javascript”]{items:[
{word:”ajax”, number:15},
{word:”beth”, number:2},
{word:”calendar entries”, special:”calendar-entries”, number:2},

{word:”xhr”, number:3}
]}[/code]

…we would change our HTML markup to:

[code=”xhtml”]

[/code]

What is the “slug” attribute you might ask. When a tag need a different call than it’s name you can add the slug attribute. If none is there it will just use the name attribute instead. In the example above the tag “calendar entries” has a slug of “calendar-entries” that way we can display one way but still link to the right URL.

Calling our widget with JavaScript

What if we wanted to do all this by JavaScript instead? Well Dojo widgets have this build in so all we have to do is code our HTML page a little different.

We can delete the reference to “dojo.parser” in our SCRIPT since we no longer are parsing HTML markup and we would add the following JavaScript.

[code=”javascript”]function createTagCloud() {
var oStore = new dojo.data.ItemFileReadStore({
url:”tagcloud.json”
});
var oCloudDiv = dojo.byId(‘tagCloudDiv’);
var oCloud = new mydojo.TagCloud({
store: oStore
},oCloudDiv);
}

dojo.addOnLoad(function(){
createTagCloud();
});[/code]

Then in our body we would add the following HTML.

[code=”xhtml”]

[/code]

JavaScript version example 8.

I hope you enjoyed this tutorial and I would love to read your comments. Here you can download the [download#1]. Happy coding.  :roll:

Mar 282008
 

Dojo Toolkit 1.1 was released today with huge improvements. I’ve been testing the beta of 1.1 for some time now and it’s really great.

You can read more details in the Change Log, Release Notes and Porting Guides.
Here are some of the improvements.

  • An easy to use and significantly improved Dojo API Viewer with some seriously great features, including the ability to easily find the original definition of a method that is “mixed-in”
  • A growing collection of demos, tutorials, and articles
  • A new BorderContainer Dijit, which is a much better way to handle layout-based widgets than SplitContainer and LayoutContainer
  • Significant performance improvements to dojo.query and dojo.fx
  • Support for Adobe AIR and Jaxer, and updated dojox.flash and dojox.offline APIs
  • Major improvements to Dijit infrastructure and widgets
  • All around Dijit theme improvements including the CSS structure for themes, refinements to the Tundra theme, re-introduction of the Soria theme, and the newly added Nihilo theme
  • DTL, the Django Template Language, is now available for use in widgets with dojox.dtl
  • Vector graphics animations
  • Additions to DojoX including an analytics package
  • Improvements to Dojo Data and RPC, and support for JSONPath
  • Many improvements to the build system including CSS optimization, multiple-versions of the Dojo Toolkit co-existing in the same document, and other great tools for optimizing performance

On top of these there are over 800 improvements, bug fixes and enhancements. Way to go and a big congratulations to the Dojo Toolkit team. Head over to the site and download now.

Jan 252008
 

Troy Reimer at SNAPPS has created LotusScript classes for parsing and creating JSON text. These classes are contained within five script libraries. There is a JSONReader and a JSONWriter class together with some wrapper classes including JSONArray and JSONObject. The JSONWriter class is really cool. You can pass it basically anything Notes data related and let it create the JSON for you. This is really handy for passing a NotesDocumentCollection to the class and let it return perfect JSON to the browser or whatever called it.

This class provides two ways of outputing JSON text. The first is to pass an array, list, NotesDocument, NotesDocumentCollection, NotesView, NotesViewEntryCollection, or NotesViewEntry to the ToJSON method. This will render the object as JSON. If the object is a type of view object, the output will be taken from the column values. The output data is basically the same as the properties/values of NotesViewEntry. If the object is a document, its output follows the NotesDocument properties/values.

Troy has wrapped the code in a Notes database and the download can be found here. UPDATE! The link to this download is now available at JSON.org and at OpenNTF.org

Sep 282007
 

Troy & Viktor at g33k in Stockholm, SwedenTroy Reimer and I spoke for a couple of hours in front of 30 or so geeks Tuesday night in Stockholm, Sweden. Ekakan sponsored the event and Troy and I had a great time. We spoke about the Lotus Quickr Templates, you can download them here, and about workflow lotusscript, JSON and the Dojo Toolkit. It was great to see some familiar faces from past years when I was working in Sweden but also several from Lotusphere.

Viktor and Troy at Icebar, StockholmBefore the event they took us to Icebar Stockholm. They made an entire bar in ice from the northern part of Sweden. That’s right, they ship the ice down and build the walls, bar and seats out of pure ice.

The pictures are taken by Joachim Dagerot who also together with Niklas Waller has blogged about the event.

Jun 292007
 

In today’s three part tutorial I’m first going to show you how to create a sign in form directly on a Domino page. Secondly, I’m going to show how you can embed a Domino form, with security, directly into a floating pane and submit it using Ajax. Last I’m showing you some code how to display a Domino view on the page using JSON and give you some of the code we at SNAPPS used for the Lotus Quickr templates we developed, free for you to download.

I have also created a short Flash preview of what I’m going to show today. It’s a good idea to view that first to get an idea of what I’m trying to explain.

Prerequisites

To get this to work there are a few things that are required and you need a basic to medium skill-set of how JavaScript works inside Domino.

The Domino server has to be version 7.0.2 or later. This is because we are getting JSON from the view and this was introduced on that version of the Domino server.

We need to have the Dojo Toolkit library downloaded to our Domino server. Unfortunately, Domino on Windows has a problem. The file name Shadow.js cannot be used. The file just does not show up through the web server. I have created a Dojo version where Shadow.js is renamed to Shadow2.js and everywhere it’s being referenced is changed. This is the version of Dojo that IBM is using inside Lotus Quickr 8. You can download it here: [download#5#nohits]. Remember to put the “dojo” folder inside the “html” directory on your Domino server. If you have a Lotus Quickr 8 server, you don’t have to do this step, but you need to modify the “src=” of the JavaScript to “/qphtml/html/dojo/dojo.js”.

We also must have session based authentication on our Domino server for the Sign In form to work. If you don’t you can still use the other code in this tutorial.

You need to download the database with all the code in it, [download#6#nohits]. You don’t want to type it all yourself do you?

Embedded Sign In FormSign In Form on a Domino Page or Form

What I’m doing here is a sign in form that we can put directly on a Domino Page or Form to let the user sign in without leaving the page to go to the Domino log-in form that redirects us back to where we came from. There is not much code to it. Let’s start.

We start by looking at the “HTML Head Content” of the “Dojo Forms Submission” Page.

"<script type="text/javascript" src="/dojo/dojo.js"></script>" + @NewLine +
"<script>" + @NewLine +
"var dbURL = '/" + @WebDbName + "';" + @NewLine +
"</script>" + @NewLine +
"<style>" + @NewLine +
"body, td {
color:#333333;
font-family:Helvetica,Geneva,Arial,Verdana,Sans-Serif;
font-size: 0.9em;
}" + @NewLine +
"</style>" + @NewLine

All we are doing here is calling the Dojo JavaScript file, adding a variable for the database URL and adding some style to our page. Next we look at the “JS Header”. Inside here we have 239 lines of JavaScript code. Don’t worry, we are only going to use 14 of them for this first part of the tutorial. The function we are using for the sign in is “directLogin()”.

function directLogin(){
var poststring = "username=" + dojo.byId("Username").value + "&password=" + dojo.byId("Password").value;
var kw = {
url: "/names.nsf?Login",
postContent: poststring,
load: function(t, txt, e) {
location.href = location.href;
},
error: function(t, e) {
alert(e.message);
}
};
dojo.io.bind(kw);
}

As you can see we are constructing a string variable “poststring”, by adding the values of the “Username” and the “Password” fields to it. We are setting the “url” to “names.nsf?Login” and the “postContent” to our “poststring” variable. The “load” is what what we want to do after the Domino server returns that it was successful. All I do here is reload the page. We don’t have to that, we are actually signed in, but for the Hide-When formulas to take effect we need to in this case. More on this later. Dojo takes care of the rest by calling the “dojo.io.bind” and passing in the “kw” object.

Let’s look at the HTML part of our Domino Page. At the top of the Domino Page I have added some text to show who you are signed as and what access level you have. In a normal application, you would obviously not have those there.

<fieldset id="loginFieldset" style="padding-left:5px; padding-right:5px; padding-bottom:5px; width:200px;">
<legend style="font-weight:bold;"> Sign In </legend>
Name<br />
<input name="Username" id="Username" value="" maxlength=256 style="width:100%;" /><br />
Password</br>
<input name="Password" id="Password" value="" type=password maxlength=256 style="width:100%;" /><br /><br />
<input type="button" value="Sign In" onclick="directLogin()" />
</fieldset>

We make the form pretty by adding the “fieldset” and “label” HTML tags. The important parts of the HTML code are the two fields and the button. There is nothing special with the fields other than they need to be there and the only thing I added the call to our function. I have also added a Domino Hide-When formula to this text.

@TextToNumber(@UserAccess(@DbName ; [AccessLevel])) > 2

All that the above @Formula does is hide the HTML if we have a user access greater than 2. Which is Reader access. This is the Anonymous access to the database. Default is Author. That’s it, not to hard was it?

Embed Domino forms and submit them using Ajax

Now lets embed a Domino form inside a floating pane on our page. This is not done by any IFrames or pop-up windows. This is the actual HTML code of the form in question embedded onto our page. We will also submit this form using Dojo’s Ajax way.

The form we are going to embed is called “Favorites”. It is a very basic form with three Text fields, a Checkbox field and a Readers field together with two buttons.

I also created a view called “Favorites View” that contains the documents using the form. More on that later in the next part of the tutorial.

First we add some HTML to our Domino Page so that we can open up the form in the floating pane.

<a href="<Computed Value>">Sign Out</a> | <a href="javascript:createNewDocument();">New Document</a>

The first link is the “Sign Out” link. It’s only there so that we can sign out. (It really belongs to the previous section.) The second link is our link to create a new “Favorite” document. As you can see it calls the function “createNewDocument()”. Let’s take a look at that code inside the “JS Header” on our Domino Page.

function createNewDocument(){
if(!dojo.byId("ff-newdocument")){
var oDiv = document.createElement("div");
oDiv.innerHTML = "Loading...";
document.body.appendChild(oDiv);

var floatingPaneAttr = {
position: "absolute",
top: "100px",
left: "100px",
width: "300px",
height: "255px"
};

for(var s in floatingPaneAttr){
oDiv.style[s] = floatingPaneAttr[s];
}

var floatingPaneArgs = {
widgetId: "ff-newdocument",
title: "New Document",
href: dbURL + "/Favorites?OpenForm",
displayCloseAction: true,
toggle: "fade",
windowState: "normal",
cacheContent: false,
refreshOnShow: true,
hasShadow: true,
executeScripts: true
};

g_FloatingPane = dojo.widget.createWidget("FloatingPane", floatingPaneArgs, oDiv);
}else{
dojo.widget.byId("ff-newdocument").show();
}
}

First we check that we don’t already have an object named “ff-newdocument”. If we don’t we create a new Div element and append it to the document body. Then we add some style attributes to the Div. Here you see an example of how to use JSON directly in your JavaScript code. Then we create the “floatingPaneArgs” object. This is again Dojo and we are using a Dojo widget called “FloatingPane”.

The interesting part of the object is the “href” value. As you can see we are using the “dbURL” variable that we declared in the “HTML Head Content” area of our Page. If you recall, it was using an @Formula; @WebDbName. We then add the name of our form and the ?OpenForm to the string. What the other name-value pairs are I’m not going to go over here.

The last thing we do is to create our FloatingPane widget. We also have to declare to Dojo that we are going to use the FloatingPane widget, so we add this code to the top of our JavaScript.

dojo.require("dojo.widget.FloatingPane");

That’s all there is to it. You can see an example of what it looks like when we open the pane to the right.

As you can see, I have also added a Set Reader Access check-box on the form. If checked, only authenticated users can see the document.

If you open the “Favorites” form and examine the two buttons you’ll see that they both contain JavaScript calls. The Cancel button calls “cancelFavoritesForm();” and the Submit button calls “submitFavoritesForm();”.

These two JavaScript functions do not exist on the Domino Form. They are both in the “JS Header” on our Page. Another proof that we are not doing this by an IFrame or a pop-up window. These two functions looks like this:

function cancelFavoritesForm(){
if(dojo.widget.byId("ff-newdocument")){
dojo.widget.byId("ff-newdocument").closeWindow();
}
}

function submitFavoritesForm(){
var formObject = document.forms["_Favorites"];
var kw = {
formNode: formObject,
load: function(t, txt, e) {
dojo.widget.byId("ff-newdocument").closeWindow();
//Reload view
getDocumentViewJSON();
},
error: function(t, e) {
alert(e.message);
}
};
dojo.io.bind(kw);
}

The first function, “cancelFavoritesForm” is not to exciting, it just closes our Floating Pane. The same result as if you click the X at the top of the Pane. The “submitFavoritesForm” is much more interesting. In Domino all forms you open from the web gets a form tag with the name of the form with an _ (underscore) before it. So we create an object “formObject” by calling document.forms[“_Favorites”]. Now the fun begins. In dojo.io.bind we can declare a “formNode” value with the form object as it’s value. Dojo recognize that you are passing in a form and submits it using Ajax in the background. You can even have WebQuerySave agents run on the form and it will work. Really super cool.

Just as in our Sign-In JavaScript function, the “load” event is where we declare what will happen after the server returns that it was successfully loaded. Here we call “closeWindow” to close the Pane. We also call a function “getDocumentViewJSON()”. That is for the last part of this tutorial. You can see an example of much more complex Domino Form embedded into a web page by clicking the image on the left. This is from one of the Lotus Quickr templates that we have created, QContacts. It has a WebQuerySave agent, multiple tabs, attachment control and much more. There is also a function called “openDocument” where we just open documents after they have been saved. It looks a lot like the “createNewDocument” function I described earlier. We call this function inside our JSON function. Let’s jump to that.

Displaying a Domino View with JSON

The last part of today’s tutorial is all about Domino views, getting JSON from them and displaying the items on our Domino Page. First on our Page, we add a empty table to the HTML.

<table border=0 cellpadding=0 cellspacing=0 width="500">
<thead id="documentHead"></thead>
<tbody id="documentBody"></tbody>
</table>

This is where the documents show up when the JavaScript call is done. We also need to add some more functions to the “JS Header”. Don’t worry, it looks worse then it is.

function getDocumentViewJSON(){
var sURL = dbURL + '/favoritesview?ReadViewEntries&Outputformat=JSON';
sURL += '&Start=' + g_NumOfStartDoc;
sURL += '&Count=' + g_NumOfDocs;
dojoGetJSON(sURL, 'printDocumentTable');
}

dojo.addOnLoad(function(){
g_DocumentHead = dojo.byId("documentHead");
g_DocumentBody = dojo.byId("documentBody");
getDocumentViewJSON();
});

The bottom JavaScript, “dojo.addOnLoad” is a really handy way of not calling anything until we are sure that everything on our page has loaded in the browser window. All we do here is to assign two global variables for the table header and the table body and call the function above, “getDocumentViewJSON()”. That is also the function we called from within our submit function in the previous section. In that function, we create a URL string that we pass to the “dojoGetJSON” function. We also pass in a string “printDocumentTable” to that function. That is the name of the function that we want to call when the server has passed back the JSON to the”dojoGetJSON” function. The two functions “dojoGetJSON” and “returnJSONValue” I’m not going to examine in this tutorial, it would be to long. All I can say is that “dojoGetJSON” get JSON back from a server and “returnJSONValue” returns specific column values from a Domino View. Examine them and try them out. We at SNAPPS use them daily in our code. Let’s look at the “printDocumentTable” function instead.

function printDocumentTable(oJSON){
try{
var oRow, oCell;
if(oJSON["@toplevelentries"] && oJSON["@toplevelentries"] > 0){
var viewentries = oJSON.viewentry;
var n_viewentries = viewentries.length;
var unidAttr, entrydata, sTitle;

//Delete all rows in the table
var iRows = g_DocumentBody.rows.length;
for (var i = 0; i < iRows; i++){
g_DocumentBody.deleteRow(0);
}

if(n_viewentries > 0 && g_DocumentHead.rows.length < 1){
oRow = g_DocumentHead.insertRow(-1);

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Name";

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Pet";

oCell = oRow.insertCell(-1);
oCell.style.fontWeight = "bold";
oCell.innerHTML = "Color";
}

for (var i = 0; i < n_viewentries; i++){
unidAttr = viewentries[i]["@unid"];
entrydata = viewentries[i].entrydata;

oRow = g_DocumentBody.insertRow(-1);
oCell = oRow.insertCell(-1);
sTitle = returnJSONValue(entrydata[0]).items[0];
oCell.innerHTML = '<a href="javascript:openDocument('' + unidAttr + '', '' + sTitle + '');">' + sTitle + '</a>';

oCell = oRow.insertCell(-1);
oCell.innerHTML = returnJSONValue(entrydata[1]).items[0];
oCell = oRow.insertCell(-1);
oCell.innerHTML = returnJSONValue(entrydata[2]).items[0];
}
}
}catch(e){}
}

All I’m doing here is to create rows and cells with values for every document I get back from the call to the view. It might look like a lot of code but it is mostly repeated steps from creating rows and cells and adding values to them.

I will explain a few things though. “unidAttr” is just the UNID of the document. “entrydata” in the for loop represent all the column values that a document have. Calling returnJSONValue(entrydata[0]) returns an object with column type and an items array, even if there was only one value in the column for that document. Remember that a column can have multiple values for each document, a field with multiple values for instance. The function also returns the type of column the items come from, so that we can know what to do with the items. If for instance the column contains date strings we can parse them in the correct format for the application using JavaScript.

That’s if for this tutorial. I hope you have found it useful and maybe even learned something. As always please submit comments on the code and how I can do it better. Until next time. UPDATE! I have corrected some spelling errors. Why can’t everybody just learn Swedish?

Jun 062007
 

There are many articles out there explaining what JSON is and where to use it, including a very good article written by Scott Good titled JSON and Domino.

What I’m going to try to explain in this tutorial is why associative arrays are our best friend when coding with JSON and Ajax. We have all seen how JSON is starting to dominate the Ajax calls. Face it, XML is so 2006. But let’s jump to the code shall we?

Normal Arrays

We made an Ajax call to our table, or view if we live in the Lotus Domino world, using our favorite way (mine is using the Dojo toolkit) and we now have an array of objects that we need to iterate through. Let’s see an example of what the array might look like.

var aArray = [
{unid: "111AAABBBCCCDDD111", first: "Rob", last: "Novak", phone: "(555) 111-1111", zipcode: "11111"},
{unid: "222AAABBBCCCDDD222", first: "Troy", last: "Reimer", phone: "(555) 222-2222", zipcode: "22222"},
{unid: "333AAABBBCCCDDD333", first: "Jerald", last: "Mahurin", phone: "(555) 333-3333", zipcode: "33333"}
];

If all we want to do is write the array out to the browser this is fine, we just use a normal for loop.

var sHTML = '<table border=1>';
for (var i = 0; i < aArray.length; i++){
sHTML += '<tr>';
sHTML += '<td>' + aArray[i].unid + '</td>';
sHTML += '<td>' + aArray[i].first + '</td>';
sHTML += '<td>' + aArray[i].last + '</td>';
sHTML += '<td>' + aArray[i].phone + '</td>';
sHTML += '<td>' + aArray[i].zipcode + '</td>';
sHTML += '</tr>';
}
sHTML += '</table>';
document.write(sHTML);

Output:

111AAABBBCCCDDD111 Rob Novak (555) 111-1111 11111
222AAABBBCCCDDD222 Troy Reimer (555) 222-2222 22222
333AAABBBCCCDDD333 Jerald Mahurin (555) 333-3333 33333

But what if we have a little bit more complex example. (Stay with me.) What if we had a way of updating user meta data from this document or form and later call code on the server to actually update the record or document in the back-end.

So we have created JavaScript that when a row is clicked, fields are populated with data from the array so the user can update them. The end user clicks a button and our array should be updated with the new meta data. We also want to add a property of “updated” with a value of true (boolean) if it is changed so that we later only pass in those documents that have changed to our back-end code (agent if Lotus Domino).

So in our scenario we have updated one of the records and call a function to update the array. With a normal array this would be done like this.

function updateUserMetaData(sUnid, sFirst, sLast, sPhone, sZip){
for (var i = 0; i < aArray.length; i++){
if(aArray[i].unid == sUnid){
aArray[i].first = sFirst;
aArray[i].last = sLast;
aArray[i].phone = sPhone;
aArray[i].zipcode = sZip;
aArray[i].updated = true;
break;
}
}
}

This works but if we have hundreds or thousands of records in the array it can take a long time. We have to iterate over all the values in our array to find the one with the right “unid”. Even though we are using a break statement when we have found our record it can still take a long time. Associative arrays to the rescue.

Associative Arrays

In JavaScript we have something called objects. They are a mapping from property names to values. Objects are an associative array with one caveat: since property names are strings, only string keys are allowed. That doesn’t matter to us.

We write an object literal as { property1: value1, property2: value2, ... }

Let’s rewrite our code to create an object instead of the array above.

var oObject = {
"111AAABBBCCCDDD111": {first: "Rob", last: "Novak", phone: "(555) 111-1111", zipcode: "11111"},
"222AAABBBCCCDDD222": {first: "Troy", last: "Reimer", phone: "(555) 222-2222", zipcode: "22222"},
"333AAABBBCCCDDD333": {first: "Jerald", last: "Mahurin", phone: "(555) 333-3333", zipcode: "33333"}
};

Can you see the difference? Not much difference in the text but a huge difference in what we can do.

First we can’t use a normal for loop to write our table any more. We need to use a for(in) loop.

var sHTML = '<table border=1>';
for (var unid in oObject){
sHTML += '<tr>';
sHTML += '<td>' + unid + '</td>';
sHTML += '<td>' + oObject[unid].first + '</td>';
sHTML += '<td>' + oObject[unid].last + '</td>';
sHTML += '<td>' + oObject[unid].phone + '</td>';
sHTML += '<td>' + oObject[unid].zipcode + '</td>';
sHTML += '</tr>';
}
sHTML += '</table>';
document.write(sHTML);

The output is exactly the same as above so we haven’t gained any value there. The big difference is in our function to update our meta data.

function updateUserMetaData(sUnid, sFirst, sLast, sPhone, sZip){
oObject[sUnid].first = sFirst;
oObject[sUnid].last = sLast;
oObject[sUnid].phone = sPhone;
oObject[sUnid].zipcode = sZip;
oObject[sUnid].updated = true;
}

As you can see we no longer need to iterate through an array to find our record. Since it is an object we can just update the property values directly.

Conclusion

In search for fast JavaScript code, associative arrays will help many times. It may seem a little difficult to code to begin with but after a while it actually makes much more sense. Object oriented programmers will find it easier.

Exactly one year ago from today, June 6th 2006, James Mc Parlane declared JavaScript Array and Object.prototype Awareness Day. Read that article. It will help you code better associative arrays (objects) in JavaScript.

May 212007
 

Many of you have requested that I publish the sample database I used for the Faster Ajax with Domino and JSON speed test. I posted the article back in March and I should have done this a long time ago.

All documents/notes has been deleted from the Domino database to save some space and bandwidth on my server. If you want to run the tests yourself on your server you need Firebug so it can calculate the time it took for the XHR (XMLHttpRequest) to run. If you just want to check out the code, feel free to do so.

All code are in two Domino Pages: TestJSON and TestXML

  • Download [download#4#nohits] and put it on your server.
  • Open it up in Notes.
  • Create a few dummy documents by selecting Create/TestForm.
  • Copy & Paste the dummy documents many times so that you have a lot of them.
  • Browse to: your_server_and_directory/XML_JSON.nsf/TestXML?OpenPage for the XML version.
  • Browse to: your_server_and_directory/XML_JSON.nsf/TestJSON?OpenPage for the JSON version.

Enjoy

Mar 022007
 

As several bloggers have posted, there is a new way of getting data out of Domino views using JSON. This feature was planned for Domino 8 but “slipped” into the 7.0.2 release of Domino.

I wanted to know if it would be faster to parse the data with JSON out of a huge view, with over a 1000 documents, and print the result back to the browser. So I needed a way of telling how fast it really was. Thanks to a great plug-in for Firefox called Firebug I could do just that. Get Firebug now. Serious web developers can’t live without it.

Continue reading »

Mar 012007
 

UPDATE: (Nov. 19, 2009) This widget only works for Dojo 0.4x.

At times I have had the urge to update the code and add extra features, but I just don’t have the time right now.

About this tutorial

After using Dojo for some time and looking for a calendar widget I gave up and started coding one myself. I had several goals with this widget: Using any back-end database for the entries, time zone changes, localized (internationalization i18n) and being able to drag entries to other dates.

This tutorial gives you all the code and files to get this calendar up and running on your server.

Continue reading »