Darryl Lyons’ Blog

AJAX, ColdFusion and Web technology…

Entries Comments



Category: AJAX


Ext 1.0 JavaScript framework released

17 April, 2007 (22:20) | AJAX, JavaScript | By: Darryl Lyons

I have been using the Ext (formally yui-ext) JavaScript framework for some time now, and just recently they released a major new version. It is jam packed with goodness, including the best grid I have seen, tree, dialogs, layouts, forms, and more… If you are looking for a serious cross-browser user interface lib, then I strongly suggest you give these guys a go. Oh, and it’s FREE.

YUI-Ext is extremely useful

4 January, 2007 (20:23) | AJAX, JavaScript | By: Darryl Lyons

I’ve recently discovered the great work by Jack Slocum in his Yahoo Extensions library. Basically, he has taken the YAHOO User Interface library (YUI) and extended it to the point of creating his own very useful framework.

If you want a robust, cross-browser user interface JavaScript library, I urge you to check out this guy’s work. So far I have been very impressed, and am looking for ways to incorporate his work into my own development.

AJAX (On-Demand JavaScript) with ToScript()

24 June, 2006 (22:54) | AJAX, ColdFusion, JavaScript | By: Darryl Lyons

I recently discovered the neat little method toScript() had been added to ColdFusion 7.0. I immediately thought that this would have to be quicker at serialising ColdFusion variables into their JavaScript equivilent than any existing JSON serialisers.

It also occurred to me that ToScript() could be used as an alternative data delivery mechanism to XML or JSON for "AJAX-enabled" web applications.

Using ToScript() for AJAX

The easiest way to use ToScript() in an "AJAX" sense is to use the On-Demand JavaScript pattern.

I've posted about the On-Demand JavaScript pattern before, so I thought I would re-use that same code, but improve it a little so that it is cross-browser (tested in Mozilla 1.5.x, IE6) compatible, and a little less verbose.

There are a number of parts to this example:

  1. index.html: Contains an empty table, ready to populate, and the trigger to call the JavaScript.
  2. getData.cfm: Serialises a query as a JavaScript array of objects (structs).
  3. getData.js: Creates a SCRIPT tag on the fly that points to the getData.cfm template as its SRC.

You can also download this example.

index.html

This code simply includes the getData.js JavaScript file, and defines an empty table, awaiting population. I've put a link above the table to trigger the population based upon data returned from ColdFusion.

HTML:
  1. <title>AJAX with ToScript()</title>
  2.  
  3. <script src="getData.js"></script>
  4. *
  5. {
  6.         font-family: sans-serif;
  7.         font-size: 10pt;
  8. }
  9.  
  10. caption
  11. {
  12.         background-color: #333333;
  13.         font-weight: bold;
  14.         text-align: left;
  15.         color: white;
  16.                
  17. }
  18.  
  19. thead tr
  20. {
  21.         background-color: #CCCCCC;
  22.         font-weight: bold;
  23.         text-align: left;
  24.                
  25. }
  26.  
  27. tr
  28. {
  29.         background-color: whitesmoke;
  30. }
  31.  
  32. td, caption
  33. {
  34.         padding: 4px;
  35. }
  36. </style>
  37. </head>
  38.  
  39.  
  40. <a href="javascript:getArtists()">Call getArtists() method</a>
  41.  
  42. <br/><br/>
  43. <table id="artistTable">
  44.         <caption>Artists</caption>
  45.         <thead>
  46.                 <tr>
  47.                         <td>ID</td>
  48.                         <td>Last Name</td>
  49.                         <td>First Name</td>
  50.                         <td>City</td>
  51.                 </tr>
  52.         </thead>
  53.         <tbody>
  54.         </tbody>
  55. </table>
  56.  
  57. </body>
  58.  
  59. </html>

getData.js

The getDataFromServer(id, url, callback) method dynamically creates a SCRIPT tag., where the source is set to a combination of the url and callback arguments. When the SCRIPT tag has loaded, whatever inside it is evaluated, including the specified callback method reference. The callback is placed there by getData.cfm.

The getArtists() method simply calls getDataFromServer with specified parameters. Notice that the callback is set to populateArtists.

The populateArtists(data) method is called when the SCRIPT tag has finished loading. getData.cfm contains the qArtists JavaScript variable, and a call to populateArtists, with qArtists being passed as a parameter. The table on the page is then populated.

JavaScript:
  1. function getDataFromServer(id, url, callback)
  2. {
  3.         var oScript = document.getElementById(id);
  4.         var head = document.getElementsByTagName("head").item(0);
  5.        
  6.         if (oScript)
  7.         {
  8.                 // Destory object
  9.                 head.removeChild(oScript);
  10.         }
  11.        
  12.         // Create object
  13.         oScript = document.createElement("script");
  14.        
  15.         var dtRf = new Date();
  16.  
  17.         oScript.setAttribute("src",url + "?callback=" + callback + "&rf=" +dtRf.getTime());
  18.         oScript.setAttribute("id",id);
  19.  
  20.         head.appendChild(oScript);
  21.  
  22. }
  23.  
  24. function getArtists()
  25. {
  26.         getDataFromServer("artistData","getData.cfm","populateArtists");
  27. }
  28.  
  29. function populateArtists(data)
  30. {
  31.         var oTBody = document.getElementById("artistTable").tBodies[0];
  32.  
  33.         // Loop over the data in the JS array, and add to table
  34.         for (var i=0; i <data.length; i++)
  35.         {
  36.                 // Create a new TR element
  37.                 var oTR = document.createElement("TR");
  38.                 oTBody.appendChild(oTR);
  39.  
  40.                 // Create a call for each element in struct
  41.                 var oTD = document.createElement("TD");
  42.                 oTD.innerHTML = data[i].artistid;
  43.                 oTR.appendChild(oTD);
  44.  
  45.                 var oTD = document.createElement("TD");
  46.                 oTD.innerHTML = data[i].lastname;
  47.                 oTR.appendChild(oTD);
  48.                                
  49.                 var oTD = document.createElement("TD");
  50.                 oTD.innerHTML = data[i].firstname;
  51.                 oTR.appendChild(oTD);
  52.                
  53.                 var oTD = document.createElement("TD");
  54.                 oTD.innerHTML = data[i].city;   
  55.                 oTR.appendChild(oTD);
  56.                
  57.         }
  58. }

getData.cfm

This ColdFusion code queries the art gallery example database to return all of the artists. It then uses the new ColdFusion built-in function ToScript() to serialise the query into a JavaScript array of objects (structs).

You will also notice that I am placing #url.callback(qArtists)# directly after ToScript(). When this JavaScript is loaded (when the SCRIPT tag is added to the DOM), the JavaScript method specified as url.callback will be called. The method will be passed the the parameter qArtists, which is the JavaScript variable just created by ToScript().

CFM:
  1. <cfsetting enablecfoutputonly="true">
  2.  
  3. <cfquery datasource="cfartgallery" name="qData">
  4. SELECT *
  5. FROM artists
  6. ORDER BY lastname, firstname
  7. </cfquery>
  8.  
  9. <cfoutput>var #toScript(qData, "qArtists", false, true)# #url.callback#(qArtists);</cfoutput>

ToScript() vs. CFJSON

I decided to run a few tests comparing ToScript() to CFJSON. Not surprisingly, ToScript() came out on top. But can the output be used in place of JSON? No, it cannot. The key difference is that JSON is represented as a single statement, whereas ToScript() generates multiple statements. Therefore, you cannot simply run eval() on the ToScript() generated string to create a JavaScript object.

I will be really happy when the boys at Adobe create a ToJSON() method native to ColdFusion...

Apache release Extensible AJAX Platform (XAP)

23 June, 2006 (21:39) | AJAX, Java, JavaScript | By: Darryl Lyons

Apache have released an AJAX framework caled Extensible AJAX Platform (or XAP for short).

XAP is an XML-based declarative framework for building, deploying and maintaining rich, interactive Ajax powered web applications. It aims to reduce the need for scripting and help solve the development and maintenance challenges associated with large scale JavaScript programming.

Not too much content on the site yet. There are a few demonstrations available, along with the source. Will be interesting to see where this heads, given that XML-driven frameworks like Laszlo already exist.

Simple JavaScript Database

17 June, 2006 (12:13) | AJAX, JavaScript | By: Darryl Lyons

Found this ages ago, but didn't blog about it. This is a JavaScript database, complete with SQL query syntax support.

This example illustrates one way of creating a completely JavaScript database with AMASS storage.This was thrown together and just more or less illustrates the possibility of using AMASS storage and TrimPath query javascript in conjunction for an offline in browser database.

The AMASS storage library, like Dojo, uses a flash movie to store the data on the local machine. This is one of the things that interest me at the moment, as I am looking for a quick solution for local storage - either using AMASS, Dojo or an ActiveX (IE only).

Native XMLHTTPRequest support in IE7

11 June, 2006 (20:32) | AJAX, Browsers, JavaScript | By: Darryl Lyons

I had almost forgotten about XMLHTTPRequest being native in Internet Explorer 7. Has anyone done any benchmarks between native support and the ActiveX? I'd be interested in seeing if their is any difference, because I imagine they would just be piggy-backing the same technology.

Essentially IE7 will now allow you to do this (which is consistent with Mozilla/Firefox and Safari):

JavaScript:
  1. var o = new XMLHttpRequest();
  2. o.open(method, url, async);
  3. o.onreadystatechange = function_pointer;
  4. o.send();

Instead of this:

JavaScript:
  1. var o = new ActiveXObject("Microsoft.XMLHTTP");
  2. o.open(method, url, async);
  3. o.onreadystatechange = function_pointer;
  4. o.send();

Dojo JavaScript Toolkit 0.3 released

4 June, 2006 (11:07) | AJAX, JavaScript | By: Darryl Lyons

Dojo Foundation have released 0.3 of their JavaScript toolkit. Some interesting features caught my attention, especially the local file storage class, that uses Flash's offline storage abilities. Some interesting experiments with data caching could be had here.

Use TABLE tags for AJAX applications

17 May, 2006 (20:49) | AJAX | By: Darryl Lyons

I've recently come the realisation that DIVs are just too much hard work when it comes to writing a stable, responsive and rapid user interface framework for AJAX-applications. Our large AJAX CRM application used DIVs and CSS Expressions heavily to achieve a "windows-like", fluid user interface. Each time a new pane was added, so were a bunch of CSS rules with expressions in them (absolute positioned elements that reference other elements to set width, height, top, left, etc).

I've now gone back to the dark ages, and converted the entire thing to use good old tables. I can tell you, it is a LOT more responsive. A lot of people may not realise the CSS expressions are evaluated each time something happens in the UI. For example, if you move your mouse, then the CSS expressions are being evaluated. So you can quickly guess that if you're adding more DIVs to the DOM with CSS expressions, you're certainly not speeding things up!

I'll also mention that I am talking about an "application" here -- not a Web site, and our standard platform is Internet Explorer (HTA). You can argue all you like that I should be using DIVs for visual layout, but I think it is more important to use what works.

Tables are just easier and quicker...

AJAX Diary: Race conditions and using cflock

18 February, 2006 (17:00) | AJAX, ColdFusion | By: Darryl Lyons

Within traditional web applications, it is highly unlikely that you will come across a scenario where a race condition will ocurr in the current session, unless you are accessing shared scopes. However, within an AJAX application, which is more like a frame-based Web site (remember them?), they can occur only too often.

Background

In our CRM application, there is a method that returns a "client ID". This method checks to see if a record exists in the database, and if not, creates it, and then returns the ID. If it already exists, then it simply returns the record. This record is in a tracking table that we use to reference records in an external system. All tables in our schema join to the tracking table, not the external database. Suffice to say, this method is called in a lot of places where client information is accessed.

<cffunction name="getClientID" returntype="string">
<cfset var local = StructNew()>
<cfset local.qClient = getClientID(arguments.account)>

<cfif NOT local.qClient.recordcount>
// Some logic to create a new tracking ID -- insert into db, etc.
</cfif>

<cfreturn local.qClient.ID>
</cffunction>

Now, you would probably state that there should be a scoped or named lock around this code. However, the likelihood of two sessions trying to create this record at the same time is very remote. Furthermore, most locking in the past has been where you are making changes to shared scopes such as SESSION, APPLICATION or SERVER.

Problem

Our new AJAX interface to our CRM has shown us that we need to be more careful, and use locking more judiciously. The scenario is this. The user clicks on a client record in a search result. This in turn loads the client information card. Three seperate, almost simultaneous, requests are sent to the server to retrieve different pieces of data. Each of the requests just happens to call the aforementioned method at some point. Even though the requests themselves are not occurring at the same time, a race condition is still created...

All three requests are now essentially calling the method, let's call it getClient(), at the same time. The database lookup to determine whether or not the record exists are being performed within a millisecond of each other. All three lookups return no records, so the conditional block of code is executed to insert a new record! So, the end result is three records in the database where there should have only be one!

Solution

Now, we pretty much had two options -- change the calls on the client so that the record check is performed once, or put a named lock around the code, so that we force requests to queue for execution.

We went for the later. Changing all of the calls to the method would require significant refactoring of the model, so that just wasn't an option.

<cffunction name="getClient" returntype="string">
<cfset var local = StructNew()>
<cflock name="getClient.getClientID" timeout="10">
<cfset local.qClient = getClientID(arguments.account)>

<cfif NOT local.qClient.recordcount>

<cflock name="getClient.getClientID.insert" timeout="10">
<cfset local.qClient = getClientID(arguments.account)>
<cfif NOT local.qClient.recordcount>
// Some logic to create a new tracking ID -- insert into db, etc.
</cfif>
</cflock>

</cfif>
</cflock>

<cfreturn local.qClient.ID>
</cffunction>

In the example above, I've put a named lock around the query to the database, and the check of the recordcount. If the recordcount is zero, then we perform another lock, and then do the check all over again. The reason for this is that in the time between acquiring the lock and performing the first check, a database record could have been inserted. The double lock technique just minimises the chance of this happening.

So, why was this only an issue now? Well, the old "traditional" user interface was a HTML page. The processing of the single request was top-down. By that I mean that if various elements of the user interface happened to call the getClient() method, they would be synchronously executed, thereby avoiding the scenario I have described.

Some other resources