| By Steven Webster | Article Rating: |
|
| April 4, 2006 10:15 AM EDT | Reads: |
27,435 |
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.
Published April 4, 2006 Reads 27,435
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
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.
![]() |
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. |
||||
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Adobe Unveils LiveCycle Enterprise Suite 2 for Deployment in the Cloud
- Adobe Flex Developer Earns $100K in New York City
- Adobe May Cooperate with Apple to Transplant Flash Player to iPhone
- Ph.D. in Twitter Anyone?
- Eolas Sues the Internet
- Adobe LiveCycle Enterprise Suite 2 for Cloud Computing
- Adobe Betas Target RIAs and Cloud Computing
- Special Report on the Emerging Cloud Computing Trend
- Adobe Cans Another 9% of its Workforce
- My Thoughts on Ulitzer
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Ulitzer Live! New Media Conference & Expo
- Adobe’s Aiming ColdFusion at Multiple Clouds
- Eval JavaScript in a Global Context
- Fig Leaf Software to Exhibit at Government IT Conference & Expo
- Cloud Executives Feature on Cloud Computing Expo Power Panel
- Software Flexibility in the Cloud - Part 4 of 5
- Cloud Computing Journal: Adobe to Deliver ColdFusion in the Cloud
- Is Microsoft as Free as Open Source?
- Adobe Reader Sued
- Adobe Unveils LiveCycle Enterprise Suite 2 for Deployment in the Cloud
- Where Are RIA Technologies Headed in 2008?
- Cover Story: How to Increase the Frame Rates of Your Flash Movies
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Your First Adobe Flex Application with a ColdFusion Backend
- Adobe Flex 2: Advanced DataGrid
- i-Technology Blog: Death-Knell For "Rich Media? Hardly!
- Adobe/Macromedia - Microsoft, Look Out!
- How To Create a Photo Slide Show ...
- Adobe Flex Interface Customization - Themes, Styles, Skins
- Personal Branding Checklist
- Has the Technology Bounceback Begun?
- "Real-World Flex" by Adobe's Christophe Coenraets





































