Note: This tutorial was originally written for From A To Web. From A to Web, a training convention dedicated to the most modern technologies for the web, is now at its sixth edition. It is organized by Inside, a very well known training center. The next edition is planned for fall 2007—anyone who would like to suggest a topic is welcome to e-mail info@insidesrl.it!
Since the first release of the Spry framework for Ajax, Adobe also provided several interesting demo applications of considerable visual impact. Spry provides, among other benefits, a complete independence from server side programming platforms (ColdFusion, ASP.NET, PHP, etc)—therefore the use of these platforms within the Adobe demo applications is almost completely absent. The result is that the demos are by nature "read-only"—that is, they are limited to show data that already exists in static, predefined XML files and structures. The objective of this tutorial is to demonstrate that Spry can effectively be used to to visualize not only static data, but also dynamic data. In order to demonstrate this, I will work from the existing Adobe "Products" demo, and convert it into a simple example of how Ajax can also be effective in the manipulation of database-driven XHTML.
The original demo makes use of "static" XML rows containing the data relative to the products. The first step for having "dynamic" data is to transfer the data to a database and use a server-side language (in our case, ColdFusion), in order to generate XML rows in a "dynamic" way. The database contains two tables, one contains product, while the other contains the names of the categories to which they are associated. In the enclosed sample files linked above, you will find a Microsoft Access database, named products.mdb. To be able to use it in the application, you must first create an appropriate data source through the ColdFusion administrator—the data source that we will call "spry".

Figure 1. The configuration screen for the ColdFusion data source. More details are available in the official documentation.
Generating XML markup using language side-server templates like CFML is natural to anyone with experience in the dynamic generation of XHTML code. You only have to keep in mind the more restrictive syntactic rules that regulate the use of the XML.
We will start creating a file called "products.cfm" that, once completed, will take the place of "products.xml" inside of the Spry demo. The CFML code from the file, really quite simple, will look like this:
<cfcontent type="text/xml"><?xml version="1.0" encoding="iso-8859-1"?>
<cfquery name="products" datasource="spry">
SELECT *
FROM Products_view
</cfquery>
<products>
<cfoutput query="products">
<product>
<id>#products.prod_id#</id>
<name>#products.prod_name#</name>
<category>#products.cat_name#</category>
<boximage>images/#products.prod_image#</boximage>
<desc><![CDATA[#products.prod_description#]]></desc>
</product>
</cfoutput>
</products>
Proceeding from the first line, we find a tag whose scope is to make the web server send the content of the file using the appropriate MIME-TYPE (and not the one used for normal XHTML pages). It is a simple yet essential detail, and its absence may create unexpected and difficult to diagnose problems.
Following is the extraction of the data through a <cfquery> tag that reads a view in the database (Microsoft Access uses the term "query" instead of the commonly used "view"). The tag <cfoutput> then allows us to "write" our data.
Before passing to the successive phase, make sure of the correct operation of products.cfm, specifically because the nature of Ajax makes the debug more difficult compared to the traditional web applications, so it is a good rule to proceed with small steps and make sure that everything works as expected.
Aiming the browser at the products.cfm page, we should visualize the XML markup dynamically generated from ColdFusion:

Figure 2. The XML markup dynamically generated from ColdFusion
At this point we can proceed to the modification of the Spry demo in order to be able to load the data generated through the database. We need to edit the JavaScript code that initializes the two datasets in order to load the data from the recently created file:
var dsProducts = new Spry.Data.XMLDataSet(
"products.cfm",
"products/product")
var dsProductFeatures = new Spry.Data.XMLDataSet(
"products.cfm",
"products/product[name = '{dsProducts::name}']/features/feature")
Once this is done, it's necessary to verify the code in a browser to assure the demo still works correctly.
The original demo makes use of the classic "master-detail" development pattern with the substantial difference (compared to traditional web applications) that instead of using two separate pages, only a single page is used (divided in two areas) and the page is not reloaded every time we need to visualize a different record.
In the "details" area on the space originally occupied by the accordion, we insert a form, which in turn will contain the Spry "detailregion" that allows us to view the data of every single record through specific fields (a textfield, a textarea, and a hidden field). The code, with minimal modifications compared with the original code, is:
<form action="action.cfm" method="post">
<div id="sidebar">
<p spry:detailregion="dsProducts" id="boxshot">
<img src="{boximage}"
alt="product box shot"
width="238"
height="130" /></p>
<div id="Acc1" class="Accordion" tabindex="0">
<div class="AccordionPanel">
<div class="AccordionPanelTab">
<h3>Edit Data</h3>
</div>
<div spry:detailregion="dsProducts"
class="AccordionPanelContent">
<div>
<input name="prod_name"
type="text"
value="{name}" />
</div>
<div>
<textarea name="prod_description">
{desc}
</textarea>
</div>
<div><input type="submit" value="Save data" class="submit" /></div>
<input name="prod_id" type="hidden" value="{id}" />
</div>
</div>
</div>
</div>
</form>
Always following a policy of taking small steps, we open this in a browser and verify the data is correctly displayed inside the form:

Figure 3. Using a browser to verify the data is correctly displayed inside the form
The next step is to create the CFM file that will contain the necessary code to edit the data—one really minimalistic "action page":
<cfif NOT StructIsEmpty(form)>
<cfquery datasource="spry">
UPDATE Products_tbl
SET
prod_name = <cfqueryparam cfsqltype="cf_sql_varchar" value="#form.prod_name#">,
prod_description = <cfqueryparam cfsqltype="cf_sql_longvarchar" value="#form.prod_description#">
WHERE prod_id = <cfqueryparam cfsqltype="cf_sql_numeric" value="#form.prod_id#">
</cfquery>
</cfif>
This is very simple SQL code that updates the database based on the content of the fields in the form. The only worthy detail to notice is the use of the <cfqueryparam> tag, which guarantees some security against the use of potential "SQL injection" attempts.
At the moment Spry does not offer a specific tool to create forms in Ajax, therefore we will use a set of libraries conceived for this scope. The entire set of libraries is around 20 kb and is spread inside of four modular JS files, which we will include inside of index.html:
<script type="text/javascript" src="includes/tmt_core.js"></script> <script type="text/javascript" src="includes/tmt_net.js"></script> <script type="text/javascript" src="includes/tmt_form.js"></script> <script type="text/javascript" src="includes/tmt_ajaxform.js"></script>
The use of the ajaxform library requires one custom attribute added to the <form> tag:
<form action="action.cfm" method="post" tmt:ajaxform="true">
The library, while loading the page, will automatically recognize the presence of this attribute. The form will then not be sent in the traditional way, but through an asynchronous HTTP request by way of XMLHttpRequest. This modification sends the content of the form to the action.cfm template, which in turn will update the data without the need to "refresh" the page.
However, there is still an essential problem to be solved; with every transfer of data from the form it is necessary to update the records view. In other words, instead of forcing a refresh of the entire page, we will make Spry read the new data contained inside products.cfm and consequently update the "dynamic region".
To start we modify the JavaScript code that defines the Spry dataset so as to disable the cache:
<script type="text/javascript">
var dsProducts = new Spry.Data.XMLDataSet("products.cfm", "products/product", { useCache: false });
var dsProductFeatures = new Spry.Data.XMLDataSet("products.cfm", "products/product[name = '{dsProducts::name}']/features/feature");
</script>
Then we will make use of a second custom attribute from the ajaxform library:
<form action="action.cfm" method="post" tmt:ajaxform="true" tmt:ajaxformcallback="dsRefresh">
The attribute "tmt:ajaxformcallback," as you'd guess from the name, allows you to assign a callback function that will be invoked from the library every time the submission of the form is successfully completed.
The scope of the callback function is to invoke the loadData() method comprised in the API of the object dataset created by Spry:
<script type="text/javascript">
function dsRefresh(){
dsProducts.loadData();
}
</script>
This last step completes the implementation of our small demo.
For more information about Spry, visit the Spry pages on Adobe Labs.
Massimo Foti lives in Lugano, Switzerland. He is a freelance webdeveloper with many years of experience in ColdFusion, CSS, SQL, database design, JavaScript and AJAX. You can find more about Massimo at www.massimocorner.com.