AJAX Components - Part 2 | Page 4
[previous]
AJAX Components - Part 2
The Declaration
Now that we have looked at the importance of databinding and templating to building our AJAX components and applications, we can look at how to create an abstract declaration for a DataGrid component. To create a declarative DataGrid—or any other component for that matter—it is easiest to start by looking at the end product of the rendered HTML and then refactoring to break out the configurable aspects, as we did when looking at a behavioral component. Here is the first pass at defining a custom declaration for the behavioral DataGrid that we have already looked at. Note that we still use standard HTML markup but that will change.
There is not that much difference here from our behavioral DataGrid HTML; we have the static header and footer of the DataGrid, as we did previously; however, we have now specified a template for the grid rows to be rendered with rather than having the data for each row explicitly written in HTML. In place of the product name and price values, we have a new syntax that looks something like this {$FieldName
}. This syntax, which is borrowed from XSLT, is used to indicate where the data from the datasource should be placed, and the string after the $ character should correspond to a data field in the client side datasource, which could be XML, JSON, or otherwise. Based on what we see in other declarative languages, it would make most sense to use XPath expressions here. After connecting this View to the Model, what we ideally end up with is a rendered grid where the {$FieldName
} expressions are all replaced with data from the client side datasource. Assuming that the template is applied to a list of data, we also use the {$Index
} expression to render out the unique numeric index of each item in the collection. In this case, we use this index value to generate a dynamic CSS class name in the HTML that we also create dynamically from JavaScript. You can also be quick to notice that there is a problem here in that the footer of the grid contains the sum of the values in the price column and, therefore, must be calculated dynamically. Also notice that the text that appears at the top of each column, as well as the HTML element styles, and even what HTML elements are used for the structure, are all still statically defined in the HTML which can drastically increase the probability of human error when defining the appearance of the component and dramatically impact usability and user interface skinability. That being said, there are certainly instances where this degree of flexibility—as in the case of the behavioral component—can be advantageous. At any rate, we can get around this problem of having all class names defined explicitly by using an even more abstract representation of our DataGrid.
For example, although we have now defined a row-based template for the data contents of our DataGrid, we can also consider binding the header of the DataGrid to a datasource using a template such as this:
The td>
element is repeated for each column defined. In this case, the columns are not bound to the data in our primary Model that contains the product information but instead to another pseudo Model that contains information about the columns such as the column label, width, styles, and other information, such as whether the data in the column is to be summed. This enables us to template the grid header so that each column header can be rendered out to the DOM using this simple HTML template as well. Something similar can be devised for the footer; however, depending on the application scope, things can become complicated quickly.
The nature of a grid is based on columns of data; columns are the basic building block of a grid and contain all the necessary information such as the column header, column footer, and column data. Thinking about the class diagram of a grid, you can quickly realize that rather than trying to fit a rich grid structure to an entirely HTML-based definition, it can be far easier—both for the developer of the component and the application designer using the component—to define a declaration using custom HTML tags. A declaration that make things a bit easier for an application designer might look something like this:
This looks similar to the explicit HTML; however, it differs in a few important ways. The definition of the grid has been pivoted so that we consider the grid from the point of view of the columns, where each column has a header, data items, and footer, rather than from the point of view of the rows. By doing this simple change, it significantly simplifies the way we approach templating and databinding.
In the case of a DataGrid, we need several different templates. We need to template the DataGrid itself:
The header group template:
The header item template:
The row item template:
The cell item template:
The footer group template:
And finally, the footer item template:
With a DataGrid type control, the templates are rather difficult as some of the templates depend on two sources of data. In particular, the templates are first "bound" to the state of the DataGrid; this ensures that the widths and styles of all the columns are set correctly according to the state of the DataGrid itself. The second binding takes place when the DataGrid binds to an external datasource as specified in the DataGrid state. The data cell item template is the most complicated template because it must contain information provided from both the state of the DataGrid—it needs to have certain formatting applied depending on the data type, for example—as well as information from the externally bound datasource. To ensure that each cell in the DataGrid is uniquely addressable, we generate the id
attribute of the <td>
element as id="{$id} cell-{$RowIndex}_{$index}"
where {$id}
comes from the Data Grid state—the unique indentifier of the DataGrid itself—{$index}
is the index of the column, and {$RowIndex}
is the index of the row. For all the details about the templating approach, you have to look through the source code provided with the book.
With this array of granular templates, you can render the component quickly and efficiently at various points throughout the component lifetime, such as when the component is rendered, when data is edited, or when data is created or deleted.
This chapter is excerpted from Enterprise AJAX: Strategies for Building High Performance Web Applications, authored by David Johnson, Alexei White, and Andre Charland, published by Prentice Hall, © Copyright 2007 Prentice Hall. All rights reserved.
[previous]
URL: