Apr 182008
 

I ran across Twubble today. If you like/can’t live without Twitter this is a great tool/website to find your Twitter friends’ friends. It’s written by Bob Lee that works at Google.

If you use Twitter, Twubble can look at your existing friends’ friends and recommend new people for you to follow. It’s a stupid simple idea, but I think the execution and fun factor have won people over.

I wrote Twubble in a couple nights of hacking in bed after the kid went to sleep. I used the latest Google Web Toolkit milestone which supports Java 5 (flawlessly from my experience). I was writing Javascript code (server and client side) for years before I ever got into Java, but I have to say, you’d be crazy to write AJAX apps any other way than GWT nowadays.

Try it out. It’s amazing how many friends you can find by having this tool examining your friends.

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 302008
 

This is the third posting going more in depth of the code I showed at my Lotusphere session BP212: The Great Code Giveaway: “Beyond Cool”. If you haven’t read the first and second article yet I recommend doing so. You find them by clicking the links. You can download the instructions, code and databases here.

What is a Grid

The Book of Dojo explains it well.

Grids are familiar in the client/server development world. Basically a grid is a kind of mini spreadsheet, commonly used to display details on master-detail forms. From HTML terms, a grid is a “super-table” with its own scrollable viewport.

The domino.view.grid that I showed in my session contains two classes. The domino.view.grid class that extends dojox.grid.Grid and the domino.view.model class that extends the dojox.grid.data.DojoData class. It also uses domino.data.ViewStore for doing the XMLHttpRequest (XHR). I wrote about the domino.data.ViewStore in the previous postings.

Instead of going through 630+ lines of code, I’m going to show how to add it to your pages or forms. First the easy one and we’ll gradually move to more complex examples.
All the examples I’m going to show require you to add a couple of lines of code to your page/form.

In the HTML Head Content you have to add a style sheet, tundraGrid.css, and the dojo.js JavaScript. The tundraGrid.css file contains all the classes needed for the Grid to display properly.

"<style type="text/css">" + @NewLine +
"@import "/dojo102/dojox/grid/_grid/tundraGrid.css";" + @NewLine +
"</style>" + @NewLine +
"<script type="text/javascript" src="/dojo102/dojo/dojo.js" djConfig="parseOnLoad: true, usePlainJson: true"></script>"

In the HTML Body Attributes we add a class of tundra.

"class="tundra""

In the JS Header we add the required JavaScript files for the domino.view.grid and the dojo.parser. This is done the very specific Dojo way. It looks like Java but is really JavaScript. Dojo does this really smart by checking if the external JS file is already loaded and available to the browser. If it is not it gets/loads it.

dojo.require("domino.view.grid");
dojo.require("dojo.parser");

All those have to be added in all my examples here. In some of the examples in the download I have added more CSS classes and more JavaScript. In the very basic example this is all we need.

Now let’s add the HTML code to our page/form.

<div dojoType="domino.view.grid" url="sessiongrid1" style="height:600px;"></div>

As you can see (click on thumbnail for larger view) this is a very basic example that just displays a 600 pixel high grid from a view called “sessiongrid1” in the same database as the page/form. If you would look at the “sessiongrid1” view you would see that these columns are in the same order and widths. If you have specified that a column is not Resizable than you can’t resize it in the Grid either.

In the next example we add an attribute of handleViewDesign=true. That will also read in font families, sizes, colors, style and justification of both column headers and bodies. It will also read in colors for Alternate rows in the view property. You also see in this example that when Display values as icons is selected on the column, it displays in the Grid. Both numbered and shared Resources work.

<div dojoType="domino.view.grid" url="sessiongrid2" handleViewDesign="true" style="height:600px;"></div>

Structure

A really neat feature of Dojo’s Grid is that you can have multi row headers. That gives us a way of displaying more data in less space, especially when we have columns with a lot of text. Again the Book of Dojo explains it for us.

In standard spreadsheet and table terminology, a cell is the basic unit of displayed data. A row is a horizontally aligned contiguous group of cells, and a column is a vertically aligned contiguous group of cells. (Wow, that makes a simple concept sound complex!)

In grid-land, there’s a distinction between rows and subrows. A subrow is what people normally think of as a row – it’s exactly one cell tall. In Grid, a row may be more than one subrow – but it is selectable as a unit.

A View is a group of contiguous logical rows with the same inner and outer “shape”… You specify this in JavaScript with an array of arrays. Each array element is an object literal. The most important property of the object is “name”, which names the column. The column name always appear as the top logical row of the grid, and unlike other rows, it doesn’t scroll up or down.

<div dojoType="domino.view.grid" url="sessiongrid3" structure="myStructure" style="height:600px;"></div>

As you can see we are using a view called “sessiongrid3”. You can find that view in the “Sessions.nsf” database in the download. In that view we have added a column with the SessionAbstract field. This field contains a lot of text and if we displayed it in the same way as the previous examples we would see only two/three documents and we would have to scroll the grid a lot. But as you can see we have added a new attribute to the div, structure="myStructure". That tells the domino.view.grid class NOT to read in the design of the view and creating the structure dynamically, but instead that we are supplying it to the grid. Below you see the code example from the page “Grid 4” inside “Sessions.nsf”.

var myViewDesign = {
cells: [
[
{
name:'Session ID',
field:"SessionID",
width:'68px',
sortAsc:true,
sortDesc:true
},
{
name:'Location',
field:"SessLocs",
width:'113px',
sortAsc:true,
sortDesc:true
},
{
name:'Begin',
field:"BeginTime",
width:"96px",
sortAsc:true,
sortDesc:true
},
{
name:'End',
field:"EndTime",
width:"96px",
sortAsc:true,
sortDesc:true
},
{
name:'Session Abstract',
field:"SessionAbstract",
width:'auto',
rowSpan: 2
}
],
[
{
name:'Title',
field:"TITLE",
colSpan: 2
},
{
name:'Speaker',
field:"Speaker",
sortAsc:true,
sortDesc:true,
formatter: withLineBreaks,
colSpan: 2
}
]
]
};
var myStructure = [ myViewDesign ];

Let’s take a look at this code. First we create an object called myViewDesign and in that object we have a property of cells which is an array containing two arrays. Each array represents it’s own row. The first array contains five column objects and the last array two column objects.

Let’s look at the first column object: Session ID. As you can see we have a few properties to this object. The first two are required. The name property is what we want it to say in the column header. The field property is the Programmatic Name of that column specified in the view column with Domino Designer. Width is the default width of the column when first displayed. sortAsc and sortDesc set to true is if we have selected that the column can be sorted ascending, descending or both.

If you look at the Session Abstract column object, you’ll see that we have a width of auto and that we added a property of rowSpan: 2. This column is going to span over 2 rows but also extend to the width of the grid.

The last two column objects are in their own array. As you can see both have a colSpan property with a value of 2. Just as you can do in a HTML table these two columns will span over two columns each, leaving only the Session Abstract column by itself. It however spans over two rows as mentioned earlier. The last thing we do is to create an array, myStructure (named so as to match the structure attribute on the div HTML tag representing the grid), and set it to our object myViewDesign. You can see the result to the right.

In this posting I have only scratched the surface of what you can do with Grids. If you download the demo databases you will see many more examples including how to open documents by clicking cells or rows. You also see examples of how to use several Grids in conjunction with each other, i.e. click on a user document in the first Grid and display his/hers sessions in the second.

If you read up on Dojo Grids on the Dojo Toolkit website you’ll see that there are many more things we can do with Grids. One is to update document data inline right there in the Grid. This doesn’t work in the domino.view.grid class yet but I’m working on it. We also need an Agent for that to work. This Grid class does not work with categorized views as of yet, but I’m working on that as well. Check back here on my blog for updates.

I hope you enjoyed this demo/tutorial and as always if you have any comments or questions please post them here.

Jan 292008
 

Today we explore two extended form widgets I used in my Lotusphere session BP212: The Great Code Giveaway: “Beyond Cool”. The first article in this series can be found here. You can download the instructions, code and databases here.

domino.form.ComboBox & domino.form.FilteringSelect

These widgets are extended from dijit.form.ComboBox and dijit.form.FilteringSelect to accommodate for the URL syntax that a Domino view requires when doing a view search. They are modern and Ajax based. You can open both by clicking the down arrow but you can also type in the field to narrow down the choices. The important part of these widgets is in the _startSearch function.

if(key != ""){
var sLetters = "abcdefghijklmnopqrstuvwxyz**";
var lastChar = key.substring(key.length-1,key.length);
var sUntilKey = "";
if(isNaN(lastChar)){
var iCharNum = sLetters.indexOf(lastChar);
sUntilKey = key.substring(0,key.length-1) + sLetters.substring(iCharNum+1,iCharNum+2);
}else{
sUntilKey = key.substring(0,key.length-1) + (parseInt(lastChar)+1);
}
query["StartKey"] = key;
query["UntilKey"] = sUntilKey;
}else{
query["StartKey"] = null;
query["UntilKey"] = null;
}

What we do here is creating the URL syntax for a Domino view search that requires the &StartKey= and &UntilKey= arguments to find the document(s) the user is searching for.

From Domino Designer 8 Help:

StartKey=string
Where string is a key to a document in sorted view. The view displays at that document. In cases where there is no match for the StartKey, the next document is returned. So, for example, if the StartKey is “A” and there are no documents that begin with “A”, StartKey returns the first document that begins with “B.”

UntilKey=string
UntilKey is only valid when used with StartKey. It allows you to display the range of view entries beginning with the document specified by StartKey until the document specified by UntilKey. For example, &StartKey=A&UntilKey=B would give you all the entries that start with A. Use the &Count keyword to further limit the number of entries returned within any given range.

How to add to them to your form

Both these widgets are very easy to add to your forms. Both require the domino.data.ViewStore discussed in the previous article so you start by adding that.

<div dojoType="domino.data.ViewStore" jsId="DominoStore" url="../sessions.nsf/sessionlookup"></div>

Here we add a div tag with dojoType of domino.data.ViewStore, we give it a jsId of DominoStore and the url is pointing to a database and view. In this case a database called sessions.nsf parallel to the current database and a view named sessionlookup.

We add a Notes field to our form and make it type Dialog list. In the HTML Attributes of the field we add the following:

"dojoType="domino.form.ComboBox" store="DominoStore" searchAttr="IDTitle" pageSize="10" autoComplete="false""

The store attribute is the same as the jsId attribute of our domino.data.ViewStore above. The pageSize attribute is the number of documents we get/show at a time and the autoComplete attribute is for making the top search value auto complete the field. Try if for yourself by setting it to true.

I left the searchAttr attribute for last because it need some explaining. As you know we are using a store to get the values for the field.

If we open up the view sessionlookup in the database sessions.nsf in Domino Designer we see that the view has two columns. If you look at the Programmatic Name for the first column you’ll see that it is IDTitle. This column is what we want values from so we set the searchAttr to IDTitle. The value saved by a domino.form.ComboBox is the same as what you see.

The difference between a domino.form.ComboBox field and a domino.form.FilteringSelect field is that the latter has an onChange attribute and that the value of the field is always the identifier of the store it is using. What is an identifier you ask? Well, all data stores has a unique identifier. In some cases that is just an incrementing number starting at zero, but in the domino.data.ViewStore I created I used the NoteID. Why not the UNID? Because a document can actually exist several times in the same view.

So in a domino.form.FilteringSelect field representing all speakers I have the following attributes.

"dojoType="domino.form.FilteringSelect" store="SpeakerStore" searchAttr="Name" pageSize="10" autoComplete="false" onChange="setMentor(arguments);""

You can see this field in the “Mentor Selection” form in the “Mentors.nsf” database. It is part of the download. We now need the setMentor function.

function setMentor(arguments){
var identityRequest = {
identity: arguments[0],
onItem: function(item){
var sEmail = SpeakerStore.getValue(item, "Email");
alert(sEmail);
},
onError: function(){
console.error("Fetch failed.");
}
};
SpeakerStore.fetchItemByIdentity(identityRequest);
}

A version of this function can be found in the “index” page inside the “Registration.nsf” database. In this function we first create an object, identityRequest, and set the property identity to the first value in the passed in arguments array by setting identity: arguments[0]. We also have an onItem property. This is the function we call when we have retrieved a value. onError is being called if an error occurs. In the bottom of the function we do the call to the store and pass in our identityRequest object. SpeakerStore.fetchItemByIdentity(identityRequest); In this case we only alert the email address of the user we selected but if you look at the same function in the “index” page mentioned above you’ll see that we call another function to go get the profile from greenhouse.lotus.com for that email.

If you want to dig deeper in all possible attributes that a ComboBox and a FilteringSelect can change see the dijit.form.ComboBox and the dijit.form.FilteringSelect JavaScript files. Remember that in Dojo the name space is done by the periods you see in the names above. So in the folder dijit you find a folder called form where you’ll find the files ComboBox.js and FilteringSelect.js.

I hope this tutorial together with my code examples will clarify these two widgets for you. If not please comment below and I will try to explain further.

Jan 282008
 

At Lotusphere in my session BP212: The Great Code Giveaway: “Beyond Cool” I showed a couple of widgets and a Grid based on the Dojo Toolkit. I’m going to show you how I did those in a couple of articles the next few days. Instead of going through the code line for line I’m just going to highlight some of the changed variables and code. All the code for these examples and demos can be found here.

Extending Dojo code

One of the really powerful things you can do with a large toolkit like Dojo is that you can extend a widget/class instead of having to change the underlying code in the toolkit itself. Instead of having to write all the code for your class you just extend an existing class and change the functions/variables you need to. You can also add your own variables and functions. Extending Dojo code is really easy. You create your own JavaScript file and “require” the existing class/widget.

dojo.provide("my.new.Widget");
dojo.require("dijit.widgetToExtend");
dojo.declare("my.new.Widget", dijit.widgetToExtend, {
variablesToChange: "myNewValue",
functionToChange1: function(arg1){
//New code
},
functionToChange2: function(arg1, arg2){
//New code
}
}

In the example above we have extended a widget class called “dijit.widgetToExtend”. You would copy this JavaScript in a file named Widget.js inside a folder structure of “/my/new/” located parallel to the dijit, dojo and dojox folders. There are other places you can put your code but this is the simplest.

Using dojo.data

What is dojo.data?
Dojo.data is a uniform data access layer that removes the concepts of database drivers and unique data formats. All data is represented as an item or as an attribute of an item. With such a representation, data can be accessed in a standard fashion.

Ultimately, the goal of dojo.data is to provide a flexible set of APIs as interfaces that datastores can be written to conform to. Stores that conform to the standard interfaces should then be able to be used in a wide variety of applications, widgets, and so on interchangeably. In essence, the API hides the specific structure of the data, be it in JSON, XML, CSV, or some other data format, and provides one way to access items and attributes of items consistently.

The great thing about dojo.data stores are that they use a predefined way of getting/setting/updating code in the store. Whoever writes code for widgets that use stores does not have care about where the underlying data is located. It could come from a MySQL database, a XML file on the file system or now a Domino view.

domino.data.ViewStore

I’ve added three variables to this class. You see them below with their default value.

parseTypes: false,
dateFormatLength: "short",
handleAsJSON: true,

parseTypes: Parses all view data into it’s correct format. Numbers become floats, dates become locale dates. Locale dates are dates that show up in the format that the current browser language want to show them.
dateFormatLength: If parseType is true, then show the date in this “length”. Can be long, short, medium or full.
handleAsJSON: Default is that all data from the Domino view is returned with JSON using the “&OutputFormat=JSON”. If you set this to false all data is retrieved using XML instead. JSON was not implemented on the Domino server until version 7.0.2 so if you use a server prior to this you need to set this variable to false.

There are five functions I want to mention briefly.

_filterResponse: Used for parsing view data in JSON format to the required format for a store.
_filterXMLResponse: Used for parsing view data in XML format to the required format for a store.
_returnColumnValue: Helper function to get the value for a specific object. Used from _filterResponse.
_returnEntryValue: Helper function to get the value for a specific XML node. Used from _filterXMLResponse.
_returnDateTime: Helper function to format the Domino date string to a dojo.date.locale.

That’s it for this time. Next time we’ll look at domino.form.ComboBox and domino.form.FilteringSelect that both use the domino.data.ViewStore. Happy coding.

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

Jul 052007
 

Rob Novak’s and my session, BP311: The Great Code Giveaway – Web 2.0 Edition, at Lotusphere 2007 is added as one of the 14 (so far) podcasts that IBM put up on the DeveloperWorks website. The podcast is a recording of the session and a transcript of it is also available, even though they did spell my name wrong in there. Click here to listen or read. You can also go download the session materials and code.

Jul 032007
 

The Dojo Toolkit has released the brand new Dojo 0.9 in beta. Very exciting! This is a brand new Dojo that is much faster than the 0.4 release, easier to customize the branding and with great accessibility (a11y).

SPEED: Stripped of all ‘excessive’, redundant, and backwards-compatible code, the new Dojo core is a speed-demon. It consists of a streamlined, compact Base (aka: dojo.js) which provides a plethora of reliable features for you and your application to expand upon. Our goal was to keep the new Base under 50K on disk and we’re happy to say that even with the many improvements to it since M2, Dojo Base still clocks in under the wire and gzipped it’s even smaller: 24K. The base of the new widget system (dijit.js) is even lighter, weighing in at 21K on disk and 11K on the wire.

You can download it here.

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.