
Database, Query, Report, Summary, Table
Reta is doing a little data mining on this season's sales figures. She's scrolling through at a table showing a row for every transaction. Noticing that higher sales figures tend to come in the morning, she has the table sort by sales figure. There's too much data there, so she filters out any transactions below $1000, then groups the transactions by time of day.
Ajax Apps have their own databases, as well as access to external systems.
Users need a way to explore all that data, in order to verify it, understand how it works, predict future trends, and so on.
You can't anticipate what users will need to do with that data.
Report on some data in a rich table, and support common querying functions. A Data Grid has the familiar database client interface: a table with a row for each result and a column for each property. Think of it as a traditional table on steroids. Typical database client functionality is as follows, and it's feasible to achieve each of these in an Ajax interface:
Each column can be usually be sorted by clicking on the header. To let the user sort by more than one category, use a sorting algorithm which preserves the order of equal values. Then, users can click on one header followed by the other.
The user can filter in to retain data matching certain criteria, or filter out to exclude that data.
Data can be grouped by similarity. A large table is essentially broken into smaller tables, where each item in a smaller table is similar to the other items in that table.
Calculations can be performed across the whole table. For example, a sum or average for a column; or a sum of the products of two columns in each row.
Some Data Grids allow fields to be edited.
With the magic of ???, the grid can become a “Virtual Workspace”, giving the illusion of holding a massive set of data. In reality, the data lives on the server and each “User Action” leads to a new server call. Most queries lead to a structured response, such as an “XML Message” or a “JSON Message”, containing a list of results for Javascript rendering, or alternatively an “HTML Message” with the specific view the user will see. The semantic style has the advantage of encouraging performance optimisations such as “Predictive Fetch”, which are essential if you want the grid to feel responsive.
Editing a table directly can be more productive for experts, though it's often more difficult for novices than editing a single record in a form, since a form usually has a more verbose interface. Grid mutability adds a couple of extra considerations:
You need to validate the data. In a live context, this might mean showing a “Progress Indicator” during validation, then “Highlight”ing invalid columns.
Cells should ideally morph into input widgets when a user begins editing them. For instance, create a dropdown when the user begins to change a constrained field.
The OpenRico Data Grid example shows a list of movies, each with several fields: ranking, title, genre, rating, votes, and year (Figure 1.53, “OpenRico Grid Movie Demo”). You can scroll down the list and sort each column header. You can also bookmark a position in the table (an example of “Unique URLs”).
NumSum is a spreadsheet, and a spreadsheet is a special, powerful, case of a “Data Grid”; they are to Data Grids what Data Grids are to conventional tables (Figure 1.54, “NumSum”).
Oddpost is an Ajax mail client with a very similar look-and-feel to desktop clients like Outlook. The subject headers table is a form of Query-Report Table. As with the OpenRico example, you can scroll through the table and sort by column.
Delta Vacations appears as a “Live Search” example, but it also serves as an example of filtering. Initially, all hotels in a destination are shown, and typing a search term retains only matching results.
The OpenRico Data Grid example uses OpenRico's LiveGrid API. In the initial HTML, there are two tables: one for the column headers and one for the data. Note the data table declares all the visible table rows, initialised with the values in the first few rows. This is an example of a “Virtual Workspace” - the rows will always stay fixed, but their data will change as scrolling occurs:
<table id="data_grid_header" class="fixedTable" cellspacing="0" cellpadding=
"0" style="width:560px">
<tr>
<th class="first tableCellHeader" style="width:30px;text-align:center">#</th>
<th class="tableCellHeader" style="width:280px">Title</th>
<th class="tableCellHeader" style="width:80px">Genre</th>
<th class="tableCellHeader" style="width:50px">Rating</th>
<th class="tableCellHeader" style="width:60px">Votes</th>
<th class="tableCellHeader" style="width:60px">Year</th>
</tr>
</table>
<table id="data_grid" class="fixedTable" cellspacing="0"
cellpadding="0" style="width:560px; border-left:1px solid #ababab">
<tr>
<td class="cell" style="width:30px;text-align:center">1</td>
<td class="cell" style="width:280px"> Bend of the River</td>
<td class="cell" style="width:80px">Western</td>
<td class="cell" style="width:50px">7.3</td>
<td class="cell" style="width:60px">664</td>
<td class="cell" style="width:60px">1952</td>
</tr>
...
</table>
The grid is initialised on page load, with some configurable options passed in:
var opts = { prefetchBuffer: true, onscroll: updateHeader };
onloads.push( function() {
tu = new Rico.LiveGrid(
'data_grid', 10, 950, 'getMovieTableContent.do', opts )}
);
The grid will then handle all user events. Notice the "getMovieTableContent.do" argument in its construction. That's the URL which will feed the grid with further data, and must be capable of accepting in certain parameters, such as initial position and number of rows to retain. For example, to load the page initially and scroll all the way to the end (rows 940 and on), the “XMLHttpRequest Call” goes to the following URL: getMovieTableContent.do?id=data_grid&page_size=10&offset=940&_=. What's retrieved is 10 movies starting at 941, in an XHTML format shown below. The grid component then updates itself with those rows:
<?xml version="1.0" encoding="ISO-8859-1"?>
<ajax-response>
<response type="object" id='data_grid_updater'>
<rows update_ui='null' >
<tr>
<td>941</td>
<td convert_spaces="true"> El Dorado</td>
<td> <span style="font-weight:bold"> Western </span> </td>
<td>7.4</td>
<td>2421</td>
<td>1966</td>
</tr>
...
</rows>
</response>
</ajax-response>
As explained in the Solution, Data Grids are usually “Virtual Workspace”s.
To improve performance, retain data in a “Browser-Side Cache”.
To improve performance, consider “Predictive Fetch”es that preload nearby results and aggregation functions.
Longer updates should be accompanied by a “Progress Indicator”.
Christian Romney suggested the idea of a sort-and-filter pattern from which this pattern partly evolved, and also pointed out the Delta Vacations example.