AJAX Components - Part 3 | WebReference

AJAX Components - Part 3


AJAX Components - Part 3

David Johnson, Alexei White, and Andre Charland

Digg This Add to del.icio.us

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.

Building the Component

It is easiest to start by building the imperative version of the component and then enabling the use of a declaration to preset any component parameters. This approach is generally a wise one because it ensures a quality API from the point of view of an imperative developer, and it makes the component accessible to those that don't want to use the declaration. Let's look at how to build a declarative component for an application in which we want a list of Customers presented to a user that is populated from a server-side data handler using AJAX.

Basic Functionality

As a first requirement, we create our DataGrid control in the exact same way as any other instance of a class using the new keyword and pass the HTML element as a single constructor argument that refers to the element in which we want our component to be rendered in. However, as with any development effort, whether you use Extreme Programming or the Waterfall approach, we start by doing at least a bit of design up front. A DataGrid control can be represented fairly simply in a UML class diagram, as shown in Figure 4.3.

The SimpleGrid class consists of a collection of column definitions, header and footer, and collection of rows. Furthermore, there are a number of methods that are inherited from the Component class that are used by the declarative framework to instantiate, render, and destroy the component, such as render() and dispose(). There is a one-to-many relationship between the SimpleGrid and the Column class where the Column class contains all the information needed to render a column of data such as the column header, footer, data, width, type, and CSS properties. Similarly, the SimpleGrid class inherits from the Component class where all the requisite functionality for declaration parsing and templating is defined.

Because we design our component from a UML model, we take advantage of that and actually generate the scaffolding JavaScript code for our component including getters and setters for all the properties, method stubs, and the inheritance chain. So, to start, we get quite a bit for free just from using the tools that we have traditionally used for server or desktop development in C++ or Java.

Our initial SimpleGrid constructor and Component class look something like this:

In the SimpleGrid constructor, all we have done is create the three different template processors for the header, footer, and the data with some initial default templates. What happen to these templates is that the information from the DataGrid declaration merges with the initial templates to produce secondary templates. The advantage of doing this is that the declaration might not change during the lifetime of the component, yet the data is likely to change. With that in mind, after merging the declaration information with the templates, we cache the result so that we can reuse those generated templates as the data changes and make the tem-plating process much more efficient.

To instantiate an instance of the SimpleGrid class based on an XHTML declaration, we use the following deserialize method, which also uses the generic deserialization method of the Component base class:

The deserialization method is responsible for finding elements in the declaration and copying those attributes from the XHTML element to the JavaScript object. In the case of the SimpleGrid class, it copies over attributes from the <ea:grid> XHTML element and then proceeds to search for any <ea:column> elements that are then deserialized into SimpleGridColumn JavaScript objects and added the columns collection of the DataGrid. The SimpleGridColumn objects also deserialize the declaration further to get information about the column header, data, and footer.

At this point, we deserialize the state of the SimpleDataGrid from an XHTML declaration into a JavaScript object with just two lines of JavaScript code:

where myGrid is the id of the declaration in the web page. To bring everything together and actually get the component to automatically deserialize, we use the same initComponents() function we used when converting the Google Map to be a declarative component. All we need to do is create a factory method that is responsible for creating an instance of the SimpleGrid class and put a reference to that method in the global hash table that maps XHTML element names to their respective factory methods:

Now, our DataGrid is still not rendering and it doesn't have any data to render. We can remedy this by adding the render method to the SimpleGrid class that looks like this:

The render method takes the cached rendering templates that were created in the deserialization method and applies those generated templates to the data, which results in the contents of the DataGrid being generated after which that content is placed into the web page DOM using the innerHTML property of the XHTML declaration element. The dataSource field of the SimpleDataGrid containing the data to be rendered can be populated simply by setting it to some static array of customer data like this: