Building the Flex UI
To get started, you need to set up a development environment for writing your Flex and ColdFusion source code. For building Flex applications, you can use Adobe Flex Builder 3, which can be installed as a standalone application or used to add Flex development tools to an existing Eclipse environment. Flex Builder 3 provides code editing with full code-assist and documentation for both ActionScript 3.0 and MXML, the two languages used to create classes in Flex.
ActionScript 3.0 is an ECMA language designed for developers accustomed to Java, C#, JavaScript, or C. It uses semicolons at the end of lines and curly braces for blocks. In a Flex RIA, ActionScript 3.0 is used primarily to model application entities and behavior. MXML, on the other hand, provides a simple tag-based language for declaratively creating classes. It is a flavor of XML, and is primarily used to define user interfaces. To handle events and behavior, it can contain embedded ActionScript 3.0 code.
In addition to its code editor, Flex Builder 3 provides a full-featured visual editor for MXML interfaces. You can drag-and-drop controls from tool palettes into desired locations within the interface. Once you place the controls, you can use toolbars to modify control properties, apply Cascading Style Sheet (CSS) attributes to change their look-and-feel, and even bind controls to data or ActionScript 3.0 classes. Because the visual editor is extensible, you can add and manipulate your own developer-defined controls as if they were native Adobe controls.
To examine your application at runtime, Flex Builder 3 provides an interactive debugger built on top of the existing Eclipse debugger framework. This provides a view of breakpoints, variables, and expressions that's almost identical to ColdFusion or Java debuggers. If you need to examine memory or processor utilization, an interactive profiler is also available.
To begin building Task List, install ColdFusion 8, Flex Builder (which includes the Flex SDK), and the CFEclipse Eclipse plug-in for ColdFusion (www.cfeclipse.org). Use the Flex Builder 3 New Project wizard to choose a ColdFusion server deployed within a JBoss environment.
When the wizard completes (and if you were creating a Flex project using Java as a back end), you create and edit a number of Flex-specific XML files in the server-side Java application server's configuration directories. The instant the wizard completes, ColdFusion creates a Flex application that is already connected to a ColdFusion server. The Flex application's source code and debugging builds are stored in your Eclipse workspace.
With a client-side Flex project created, you can now create a client-side model of your single domain object. Right-click the Task List project in the Flex Builder 3 Flex Navigator pane and choose New ActionScript Class to get started. Using the wizard, create a Task class and place it within the com.firemoss.tasks package. When the wizard completes, the actual source-code file is in the project's src/com/firemoss/tasks directory. (When you download the code accompanying this article, you'll find the source code for this class in Tasks/src/com/firemoss/tasks.)
package com.firemoss.tasks.model { import mx.utils.UIDUtil; // Alias'd to server-side class / component [RemoteClass(alias="com.firemoss.tasks.model.Task")] // Bindable makes this class a subject for data binding [Bindable] /** Model of a Task. */ public class Task { /** Unique Id. */ public var id:String = UIDUtil.createUID(); /** Name of the task. */ public var task:String; /** Is the task complete? */ public var complete:Boolean; } }
Listing One provides ActionScript 3.0 Javadoc-like comment capabilities for automatically generating documentation. Annotations within square braces let metadata be added to the class. Using the ASDoc utility within the Flex SDK, you can produce API documentation for your ActionScript 3.0 classes. In the Task class, annotations are used to add two key metadata items:
- A Bindable annotation states that an instance of the class may act as a subject for data binding, meaning that an instance of Task dispatches events when its properties change.
- RemoteClass, which states that there is a server-side equivalent to this class, also named com.firemoss.tasks.model.Task.
With the model of a Task created, turn to the UI. When the Flex project wizard completes, it creates the Tasks.mxml file to act as the main interface. Because the application is simple, it employs the Autonomous View pattern for its sole UI, embedding within Task.mxml all knowledge of the model, services, and control code. (In larger Flex applications, you should use more scalable architectures, such as Model View Controller.)
Inside Tasks.mxml, MXML tags define properties and server connections. In Listing Two, Task instances are stored using classes from the Flex SDK's Collections API. An ArrayCollection stores a list of all tasks, and a ListCollectionView subscribes to the master collection and defines an automatically updated subset of tasks that are complete. Both of these collections are "bindable," which means they can serve as a subject for observation by other classes and UI controls. When the subject object changes its properties, observers are notified and may update themselves accordingly. This provides a loosely coupled architecture ideal for creating flexible, engaging UIs.
<!-- MODEL --> <!-- Master list of all tasks --> <mx:ArrayCollection id="tasks" /> <!-- Filtered list of completed tasks --> <mx:ListCollectionView id="incompleteTasks" filterFunction="filterIncompleteTask" list="{tasks}"/>
Once data is stored in collections, Task List needs to display a list of tasks. It does this in Listing Three with a List component that shows a vertically scrolling list of items. The List instance is bound to the currently selected collection of tasks. As the collection changes, List automatically redraws itself.
<!-- List of tasks --> <mx:List id="taskList" height="100%" width="100%" labelField="task" dataProvider="{showCompletedTasks.selected ? tasks : incompleteTasks}" change="taskListChangeHandler(event)"> <mx:itemRenderer> <mx:Component> <view:TaskItemRenderer /> </mx:Component> </mx:itemRenderer> </mx:List>
By default, List shows a label for each of its items. However, Task List needs to show both the label and a CheckBox to enable user interaction. Any of Flex's list-based controls can employ a custom item renderer, which is typically an MXML-based class that defines a UI for each item. In Task List, I use a custom renderer that displays a CheckBox and the task's name.
Below the list of tasks, the application must display a form to let users enter new tasks; see Figure 2. MXML includes a rich set of form controls. By combining tags like Form, FormItem, TextInput, and StringValidator, you create a form with complete client-side validation solely through declarative tags.
Last on Task List's set of defined MXML elements are server connections. Flex provides a RemoteObject tag for RPC-style communication with server-side ColdFusion and Java components. In Task List, a RemoteObject tag using the preconfigured "ColdFusion" destination lets the application communicate with a server-side ColdFusion component.
For real-time messaging, Flex provides Producer and Consumer tags. A Consumer lets an application subscribe to real-time messages published by the server. A Producer publishes messages to the server for rebroadcast to other users of the application. In Listing Four, a Consumer tag using the preconfigured "ColdFusionGateway" connection lets ColdFusion send real-time messages to the Task List application running within the user's browser.
<!-- BUSINESS SERVICES --> <!-- Subscribes to realtime messages from the application server --> <mx:Consumer id="consumer" destination="ColdFusionGateway" message="taskMessageHandler(event)" /> <!-- Allows RPC-style invocations of server-side service methods --> <mx:RemoteObject id="taskService" destination="ColdFusion" source="com.firemoss.tasks.service.TaskService" > <mx:method name="listTasks" result="listTasksResultHandler(event)" /> <mx:method name="saveTask" /> </mx:RemoteObject>
To wire all of these MXML components together, Task List uses ActionScript 3.0 functions within Tasks.mxml that act as event handlers. These event handlers define what actions are taken when users indicate task completion or click the "OK" button to add a new task. They also handle real-time task updates received from the server; see Listing Five. With event handlers in place, the client-side Flex application is ready to be used.
/** Invoked when the server completes an operation of taskService */ private function listTasksResultHandler(event:ResultEvent):void { // Server returns an Array of Task instances: update our model. this.tasks.source = event.result as Array; }