Dynamic Table Tutorial

The aim of this document is to give you an overview of how our Spry data framework works by walking you through the conversion of an HTML table containing static data to one that can load its data dynamically.

Here's what the table we'll be working with looks like:

Employee ID Last Name First Name Phone Username
123456 Smith Edward (415) 333-0235 esmith
127937 Johnson Neil (415) 333-9475 njohnson
126474 Williams Steve (415) 333-4573 swilliams
120585 Jones John (415) 333-9345 jjones
127493 Brown Joe (415) 333-5938 jbrown

The markup for this table would look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Static Table Sample</title>
</head>
<body>
<table border="1">
	<tr>
		<th scope="col">Employee ID </th>

		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>

	</tr>
	<tr>
		<td>123456</td>
		<td>Smith </td>
		<td>Edward</td>

		<td>(415) 333-0235 </td>
		<td>esmith</td>
	</tr>
	<tr>
		<td>127937</td>

		<td>Johnson</td>
		<td>Neil</td>
		<td>(415) 333-9475 </td>
		<td>njohnson</td>

	</tr>
	<tr>
		<td>126474</td>
		<td>Williams</td>
		<td>Steve</td>

		<td>(415) 333-4573 </td>
		<td>swilliams</td>
	</tr>
	<tr>
		<td>120585</td>

		<td>Jones</td>
		<td>John</td>
		<td>(415) 333-9345 </td>
		<td>jjones</td>

	</tr>
	<tr>
		<td>127493</td>
		<td>Brown</td>
		<td>Joe</td>

		<td>(415) 333-5938 </td>
		<td>jbrown</td>
	</tr>
</table>
</body>

</html>
        

Source Listing - This is the initial markup of our static table.

Setting up a data set:

The first thing we want to do is to extract the data out into an XML file named employees-01.xml so we can load the data dynamically from the browser:

<?xml version="1.0" encoding="iso-8859-1"?>
<employees xmlns="http://www.foo.com/employees">

	<employee id="123456">
		<lastname>Smith</lastname>
		<firstname>Edward</firstname>
		<phone>(415) 333-0235 </phone>

		<username>esmith</username>
	</employee>
	<employee id="127937">
		<lastname>Johnson</lastname>
		<firstname>Neil</firstname>

		<phone>(415) 333-9475 </phone>
		<username>njohnson</username>
	</employee>
	<employee id="126474">
		<lastname>Williams</lastname>

		<firstname>Steve</firstname>
		<phone>(415) 333-4573 </phone>
		<username>swilliams</username>
	</employee>

	<employee id="120585">
		<lastname>Jones</lastname>
		<firstname>John</firstname>
		<phone>(415) 333-9345 </phone>

		<username>jjones</username>
	</employee>
	<employee id="127493">
		<lastname>Brown</lastname>
		<firstname>Joe</firstname>

		<phone>(415) 333-5938 </phone>
		<username>jbrown</username>
	</employee>
</employees>
        

Source Listing - The data from our static table in an XML format.

The names of the tags and attributes you use in your XML is up to you, but what is important, is that all of the data, for each row of the original table, is structured the same way and at the same level of the XML tag structure.

Now that our data is in an XML file, we'll need to modify our original file so that it can find the XML file. Since we no longer need all of the static data in the table, I've removed all but one row of static data, which we'll be using later on. First, we'll need to include the JavaScript files that define our data framework:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
</head>
<body>

<table border="1">
	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>
	</tr>
	<tr>
		<td>123456</td>
		<td>Smith </td>
		<td>Edward</td>
		<td>(415) 333-0235 </td>
		<td>esmith</td>

	</tr>
</table>
</body>
</html>
        

Source Listing - To use the data framework, you must first include xpath.js and SpryData.js.

Next, we'll add some JavaScript to define a data set that can load our data:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>

<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");
</script>
</head>
<body>
<table border="1">

	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>
	</tr>
	<tr>
		<td>123456</td>
		<td>Smith </td>
		<td>Edward</td>
		<td>(415) 333-0235 </td>
		<td>esmith</td>

	</tr>
</table>
</body>
</html>
        

Source Listing - Create an XMLDataSet with the JS 'new' keyword.

The example above creates an Spry.Data.XMLDataSet object named "dsEmployees". The first argument to the XMLDataSet constructor is a URL to the data you want to load. In this particular case, it is a relative URL to our xml file named "employees-01.xml", but this first argument can also be a fully qualified or relative URL to some web service/application within your domain that requires URL arguments, so it doesn't have to be a static XML file.

The second argument to the XMLDataSet constructor is an XPath expression that describes where in the XML structure the data you are interested in lives. For our XML data, all of our data is in the "employee" node, so the result of our XPath expression "employees/employee" is the set of XML employee nodes.

Since data sets are tabular, the data in each of the employee nodes is flattened, producing an array of objects (rows) who's properties (columns) are the names of the tags or attributes:

[
    { "@id": "123456", "lastname": "Smith", "firstname": "Edward", "phone": "(415) 333-0235", "username": "esmith"},

    ...

    { "@id": "127493", "lastname": "Brown", "firstname": "Joe", "phone": "(415) 333-5938", "username": "jbrown"},
]

        

which can be visualized as a lookup table that looks something like this:

@id lastname firstname phone username
123456 Smith Edward (415) 333-0235 esmith
127937 Johnson Neil (415) 333-9475 njohnson
126474 Williams Steve (415) 333-4573 swilliams
120585 Jones John (415) 333-9345 jjones
127493 Brown Joe (415) 333-5938 jbrown

Attributes on tags are prefixed with an "@" character, so in the example above, we have a column named "@id" which represents the "id" attribute on the employee tag. If the firstname tag had a nickname attribute (example: <firstname nickname="Eddie">Edward</firstname>) on it, there would be a column named "firstname" with a value of "Edward" and another column named "firstname/@nickname" with a value of "Eddie".

Setting up a dynamic region:

Now that we have our data set all set up, lets turn our table into a dynamic region that has the ability to automatically regenerate itself as the data in the data set is loaded or changed. To do this, we first need to wrap our table with a div:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");

</script>
</head>
<body>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>

	</tr>
	<tr>
		<td>123456</td>
		<td>Smith </td>
		<td>Edward</td>
		<td>(415) 333-0235 </td>
		<td>esmith</td>
	</tr>
</table>
</div>

</body>
</html>
        

Source Listing - Use an "spry:region" attribute to turn some markup on the page into a dynamic region.

The "spry:region" attribute on the div we just added, tells our data framework that the contents of the div should be treated as a dynamic region. The value of the "spry:region" attribute is "dsEmployees" which tells our framework that this region is bound to data in the "dsEmployees" data set, and that this region should be regenerated anytime the data in "dsEmployees" is changed. If the dynamic region is bound to more than one data set, you would simply list the data set names, separated by spaces, as the value of the "spry:region" attribute (example: spry:region="dsEmployees1 dsEmployees2 dsEmployees3").

Now that we have a dynamic region defined, we can insert data from our data set into the region by using data references of the form "{<dataSetName::columnName>}":

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>

<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");

</script>
</head>
<body>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>

	</tr>
	<tr>
		<td>{dsEmployees::@id}</td>
		<td>{dsEmployees::lastname}</td>
		<td>{dsEmployees::firstname}</td>
		<td>{dsEmployees::phone}</td>
		<td>{dsEmployees::username}</td>
	</tr>
</table>
</div>

</body>
</html>
        

Source Listing - Use data references to insert data from a data set.

If the dynamic region is only bound to one data set, you can leave off the data set name in the data reference. For example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Static Table Sample</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");
</script>
</head>
<body>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>

	</tr>
	<tr>
		<td>{@id}</td>
		<td>{lastname}</td>
		<td>{firstname}</td>
		<td>{phone}</td>
		<td>{username}</td>
	</tr>
</table>
</div>

</body>
</html>
        

Source Listing - You can leave off the data set name in a data reference if the region is bound to a single data set.

If you load the code above into a browser, you should see the following:

Employee ID Last Name First Name Phone Username
123456 Smith Edward (415) 333-0235 esmith

Every data set has a notion of a current row. By default, the current row is zero, so with the code above the data framework replaced our data references with the values in the current row of the "dsEmployees" data set. We actually want our table to list all of the data in our data set, so we need to use a looping construct to iterate over all of the rows in our data set.

You tell the data framework to iterate over the rows of a data set by specifying an "spry:repeat" attribute, on the node you want to repeat for each row in the data set. The value of the "spry:repeat" attribute should be the name of the data set you want to iterate over:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Static Table Sample</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>

<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");
</script>
</head>
<body>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col">Employee ID </th>
		<th scope="col">Last Name </th>
		<th scope="col">First Name </th>
		<th scope="col">Phone</th>
		<th scope="col">Username</th>

	</tr>
	<tr spry:repeat="dsEmployees">
		<td>{@id}</td>
		<td>{lastname}</td>
		<td>{firstname}</td>
		<td>{phone}</td>
		<td>{username}</td>
	</tr>

</table>
</div>
</body>
</html>
        

Source Listing - Use "spry:repeat" to repeat an element and its contents for every row of a data set.

If you load the code above into a browser, you should see:

Employee ID Last Name First Name Phone Username
123456 Smith Edward (415) 333-0235 esmith
127937 Johnson Neil (415) 333-9475 njohnson
126474 Williams Steve (415) 333-4573 swilliams
120585 Jones John (415) 333-9345 jjones
127493 Brown Joe (415) 333-5938 jbrown

Congratulations, you've converted your static table into a dynamic table that can load external data!

Before we conclude, let's take this example one step further by adding the ability to sort the items in the table based on a click in a specific column header. To do this, we add a spry:sort attribute to each column header:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");

</script>
</head>
<body>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col" spry:sort="@id">Employee ID </th>
		<th scope="col" spry:sort="lastname"Last Name </th>
		<th scope="col" spry:sort="firstname">First Name </th>
		<th scope="col" spry:sort="phone">Phone</th>
		<th scope="col" spry:sort="username">Username</th>
	</tr>
	<tr spry:repeat="dsEmployees">
		<td>{@id}</td>
		<td>{lastname}</td>
		<td>{firstname}</td>
		<td>{phone}</td>
		<td>{username}</td>

	</tr>
</table>
</div>
</body>
</html>
          

Source Listing - Use the sort() method to sort the data in a data set. Any regions bound to the data set will automatically regenerate themselves.

The sort method on the "dsEmployees" data set takes the name of the data set column to use for the sorting operation. Sorting causes the order of the data in the data set to change, so anytime it is invoked, the dynamic region automatically regenerates itself to reflect the new ordering of the data. To see it in action, load the code above into a browser, and click on any of the column headers.

Aside from sorting, we can also completely change the data we display by simply changing the URL on the data set and telling it to reload its data:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:spry="http://ns.adobe.com/spry">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Static Table Sample</title>
<script type="text/javascript" src="../../includes/xpath.js"></script>
<script type="text/javascript" src="../../includes/SpryData.js"></script>
<script type="text/javascript">
var dsEmployees = new Spry.Data.XMLDataSet("../../data/employees-01.xml", "employees/employee");
</script>
</head>
<body>
<select onchange="dsEmployees.setURL(this.value); dsEmployees.loadData();">

	<option value="../../data/employees-01.xml" selected>Set 1</option>
	<option value="../../data/employees-02.xml">Set 2</option>
</select>
<div spry:region="dsEmployees">
<table border="1">
	<tr>
		<th scope="col" spry:sort="@id">Employee ID </th>
		<th scope="col"  spry:sort="lastname">Last Name </th>
		<th scope="col"  spry:sort="firstname">First Name </th>
		<th scope="col"  spry:sort="phone">Phone</th>
		<th scope="col"  spry:sort="username">Username</th>
	</tr>
	<tr spry:repeat="dsEmployees">
		<td>{@id}</td>
		<td>{lastname}</td>

		<td>{firstname}</td>
		<td>{phone}</td>
		<td>{username}</td>
	</tr>

</table>
</div>
</body>
</html>
          

Source Listing - You can load new data by changing the URL on the data set and calling loadData().

When running the code above in a browser, you can use the select form widget to switch between two different sets of data.

Congratulations! With a few lines of JavaScript, you've turned your static table page into something that can load and display data from any number of XML files. Keep in mind that you can turn almost any HTML element on the page into a dynamic region. Take a look at some of the demos that are distributed with the framework to get an idea of just how flexible it is.


Copyright © 2006. Adobe Systems Incorporated.
All rights reserved.