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:
- index.html: Contains an empty table, ready to populate, and the trigger to call the JavaScript.
- getData.cfm: Serialises a query as a JavaScript array of objects (structs).
- 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:
-
-
-
<title>AJAX with ToScript()
</title>
-
-
-
-
*
-
{
-
font-family: sans-serif;
-
font-size: 10pt;
-
}
-
-
caption
-
{
-
background-color: #333333;
-
font-weight: bold;
-
text-align: left;
-
color: white;
-
-
}
-
-
thead tr
-
{
-
background-color: #CCCCCC;
-
font-weight: bold;
-
text-align: left;
-
-
}
-
-
tr
-
{
-
background-color: whitesmoke;
-
}
-
-
td, caption
-
{
-
padding: 4px;
-
}
-
</style>
-
</head>
-
-
-
-
<a href="javascript:getArtists()">Call getArtists() method
</a>
-
-
-
-
-
-
-
-
-
-
-
</tr>
-
</thead>
-
-
</tbody>
-
</table>
-
-
</body>
-
-
</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:
-
function getDataFromServer(id, url, callback)
-
{
-
var oScript = document.getElementById(id);
-
var head = document.getElementsByTagName("head").item(0);
-
-
if (oScript)
-
{
-
// Destory object
-
head.removeChild(oScript);
-
}
-
-
// Create object
-
oScript = document.createElement("script");
-
-
var dtRf = new Date();
-
-
oScript.setAttribute("src",url + "?callback=" + callback + "&rf=" +dtRf.getTime());
-
oScript.setAttribute("id",id);
-
-
head.appendChild(oScript);
-
-
}
-
-
function getArtists()
-
{
-
getDataFromServer("artistData","getData.cfm","populateArtists");
-
}
-
-
function populateArtists(data)
-
{
-
var oTBody = document.getElementById("artistTable").tBodies[0];
-
-
// Loop over the data in the JS array, and add to table
-
for (var i=0; i <data.length; i++)
-
{
-
// Create a new TR element
-
var oTR = document.createElement("TR");
-
oTBody.appendChild(oTR);
-
-
// Create a call for each element in struct
-
var oTD = document.createElement("TD");
-
oTD.innerHTML = data[i].artistid;
-
oTR.appendChild(oTD);
-
-
var oTD = document.createElement("TD");
-
oTD.innerHTML = data[i].lastname;
-
oTR.appendChild(oTD);
-
-
var oTD = document.createElement("TD");
-
oTD.innerHTML = data[i].firstname;
-
oTR.appendChild(oTD);
-
-
var oTD = document.createElement("TD");
-
oTD.innerHTML = data[i].city;
-
oTR.appendChild(oTD);
-
-
}
-
}
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:
-
<cfsetting enablecfoutputonly="true">
-
-
<cfquery datasource="cfartgallery" name="qData">
-
SELECT *
-
FROM artists
-
ORDER BY lastname, firstname
-
</cfquery>
-
-
<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...