Welcome!

Adobe Flex Authors: Liz McMillan, RealWire News Distribution, Maureen O'Gara, Yakov Fain, Keith Swenson

Related Topics: Adobe Flex

Adobe Flex: Article

Developing Adobe Flex Rich Internet Applications with Cairngorm Microarchitecture

Using the Cairngorm Store sample application

Binding the Model and View Together
One of the primary reasons for wanting data in the presentation tier of an n-tier application is to display that data. Furthermore, the R in RIA is about presenting data in a rich and immersive way. One of the unsung features of the Flex application framework is the data binding capabilities of Flex. Data binding allows two objects to act as a source and a destination. Changes to the source object are reflected immediately in the destination object. When the destination object is a visual component and the source object is client-side data, you suddenly have a powerful means for ensuring that changes to the client-side state are rendered to the user in real time. The user's view is never stale; the model (the client-side state) is always notified by the view (the user interface) if you have used data binding to bind the model and view together.

At Adobe Consulting, we witnessed development teams convolute solutions for updating the user interface whenever the underlying model changed. Furthermore, these teams became tangled in a mess pretty quickly when displaying data in different parts of the view in different ways. Let's say you have a series of numbers that have been updated on a server. Depending on a user's location in the application, this may cause their table or graph display to update or update data in a dashboard summary about key assumptions for a business. By refactoring architecture towards keeping the data in a client-side model, and leveraging data binding between this model and the different view components, you eliminate much of the complexity around this kind of interactivity and responsiveness in an RIA.

Furthermore, we found that each developer kept the client-side state he needed for his parts of the application development (in his parts of the code base). Consequently, when another developer needed to use that data in another part of the application, she would have to create convoluted and complex solutions to ensure the data was visible from more than one place.

Often we found that developers referenced other data with long chains of component references, such as mx.core.Application.application.storeView.textualList.productGrid. Such strategies are incredibly brittle to change - adding or removing any components (storeView, textualList) would require that a developer update any references to productGrid.

Additional strategies include passing data up and down through MXML component instantiations. Consider the following graphical representation of MXML components, where data is in a leaf node of the tree and is required in another developer's leaf node. The only solution is to find a common branching point for both leaf nodes and then, from that branching point, pass the data down through the component chain with component instantiations, as follows:

<myView:MyComponent data="{this.data}" />

Once again, this is a strategy that is incredibly brittle to changes in the implementation of the view. It leads to regular errors because it incorrectly passes data down the chain somewhere. Debugging these errors is a laborious job of tracing the component paths to confirm that data has been correctly passed between components. It's a frustrating task.

Enter the Model Locator Pattern
Watching developers fall repeatedly into these traps, the Adobe Consulting team conceived the Model Locator pattern as a best practice for Flex developers to adopt. The Model Locator pattern is unique because it is not a pattern we borrowed from the Core J2EE Pattern catalog. Instead, we created this pattern particularly for Flex application development. Our motivation was to have a single place where the application state is held in a Flex application and where view components are able to "locate" the client-side model that they wish to render.

Our Model Locator pattern strategy encourages the use of data binding so that view components bind directly to the client-side state held in the single instance of the ModelLocator class. In this way, whenever the model is updated in ModelLocator, all view components binding to the model receive notifications (through the underlying data-binding mechanism) and update themselves to render the new model on the client.

In Cairngorm, we provide a marker interface for the Model Locator pattern, and in the Cairngorm Store we have a single class that implements this marker interface, org.nevis.cairngorm.samples.store.model.ModelLocator.

As you take this opportunity to review the source for this ModelLocator class, let me point out a few examples of its usage. In the Cairngorm Store, there is always a notion of the "currently selected product." This is the item that the user has selected. The application stores an instance of a ProductVO in the model locator, uses the selectedItem property in the application to render the ProductDetails panel, and uses the property to decide what to add to the shopping cart when the user presses the Add to Cart button.

See the ModelLocator source in the following entry:

public static var selectedItem : ProductVO;

You will learn how to use data binding to ensure that the currently selected item always appears in the product details view.

Additionally, through ModelLocator, you can find the list of products for sale in the Cairngorm Store from anywhere in the application by storing an ArrayList of these products on ModelLocator, as follows:

public static var products : Array; // containing ProductVO objects

Also notice how the application stores constants in ModelLocator. In this application, these constants allow you to track the state of the application (there are three possible states) as follows:
public static var workflowState : Number;

//------------------------------------------------------------

public static var VIEWING_PRODUCTS_IN_THUMBNAILS : Number = 1;
public static var VIEWING_PRODUCTS_IN_GRID : Number = 2;
public static var VIEWING_CHECKOUT : Number = 3;

Finally, you have a complex ShoppingCart component that encapsulates all the functionality associated with adding and removing items to a list of items that the customer may want to purchase. You stored the shoppingCart instance on the ModelLocator and initialized it within the ModelLocator in the initialise() method.

Having all the attributes on the Model Locator pattern as static attributes ensures that the Model Locator pattern is a simple implementation of a singleton. You ensure, for instance, that one and only one instance of a ShoppingCart exists per user.

The single instance of ModelLocator is initialized immediately when the main application is initialized. In the Main.mxml file (the entry point for the Cairngorm Store) you have declared the following method as a handler for the creationComplete event on the main Application tag:

<mx:Script>
<![CDATA[

    import org.nevis.cairngorm.samples.store.model.ModelLocator;

    private function onCreationComplete() : Void
    {
       ModelLocator.initialise();
    }

]]>
</mx:Script>

This code ensures that all the client-side state (such as our shopping cart) correctly initializes when the application starts.

Next, I'll take a look at data binding to the ModelLocator in greater detail. But to whet your appetite, let me say that when you create components that rely upon client-side data rather than adopt any of the convoluted strategies that result in a brittle implementation of the view, you can instead locate client-side state by binding to the singleton ModelLocator from any component in the application.

By way of example, we have a SideArea.mxml component in the Cairngorm Store that contains the ProductDetails and ShoppingCart components. ProductDetails requires the currently selected item, so that it can display the name, description, price, and image of the item the user has selected. Because the currently selected item is stored in ModelLocator as an instance Product VO called selectedItem, you can pass this item into our ProductDetails component as shown below:

<details:ProductDetails
      id="productDetailsComp"
      width="100%" height="325"
      currencyFormatter="{ ModelLocator.currencyFormatter }"
      selectedItem="{ ModelLocator.selectedItem }"
      addProduct="addProductToShoppingCart( event )" />

The highlighted line of code shows that within the ProductDetails.mxml file, there is an attribute called selectedItem that is an instance of a Product VO. You have just used data binding (the curly brace notation) to ensure that anytime selectedItem on ModelLocator is updated, the ProductDetails view updates accordingly.

The continuation of this article can be found at www.macromedia.com/devnet.

More Stories By Steven Webster

Steven Webster is the practice director for Rich Internet Applications at Adobe. Previously, he was the technical director at iteration::two, a world-leading Rich Internet Application consultancy based in Edinburgh, Scotland. Webster is the author of Reality J2EE: Architecting for Flash MX and coauthored ActionScript 2.0 Design Patterns for Rich Internet Applications (ActionScript 2.0 Dictionary) and Developing Rich Clients with Macromedia Flex with Alistair McLeod. Steven speaks regularly at conferences and user group meetings on technical and business aspects of RIAs. Steven is the core contributor to the open-source Cairngorm project, a microarchitecture for RIAs based on J2EE patterns which was innovated by iteration::two over a number of Flash and Flex RIA developments.

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
Sys-Con Italy News Desk 04/04/06 10:44:53 AM EDT

This series presents an open-source architectural framework to Flex developers called Cairngorm. In this series I explain the thought leadership behind Cairngorm, the design challenges that Adobe feels Cairngorm addresses best, and the projects for which Cairngorm is an appropriate skeleton for development.

SYS-CON India News Desk 04/03/06 05:58:01 PM EDT

This series presents an open-source architectural framework to Flex developers called Cairngorm. In this series I explain the thought leadership behind Cairngorm, the design challenges that Adobe feels Cairngorm addresses best, and the projects for which Cairngorm is an appropriate skeleton for development.