Chapter 17: Working with Pop-up WindowsWorking with Custom Pop-up Windows You can create custom pop-up windows in a Flex application for many purposes: l Presenting detailed information
Trang 1Chapter 17: Working with Pop-up Windows
Working with Custom Pop-up Windows
You can create custom pop-up windows in a Flex application for many purposes:
l Presenting detailed information to the user that’s too complex to easily fit into an Alert
dialog box
l Collecting configuration and preference information before executing an operation
l Providing a pop-up window that can be reused as a custom component
l Collecting data through a data entry form wrapped in a pop-up window
Tip
A custom pop-up window component must be extended from a class that implements the IFlexDisplayObject interface This interface is implemented by the UIComponent class, which in turn is in the inheri- tance hierarchy of all MX containers and controls This essentially means that any component can be used as a custom pop-up window If you want to create a custom pop-up window based on a Spark component, though, you should base your custom pop-up window on the Spark TitleWindow component n
Defining a custom pop-up window
Custom pop-up windows can be defined as custom MXML components If you want to create a window that looks like a dialog box, you can use either the Panel or TitleWindow container
While either component has the appearance of a dialog box, the Spark Panel component can’t be dragged around the screen by the user If you want full dialog box functionality, create your cus-tom pop-up window components as subclasses of the TitleWindow component
Creating the component
The steps for creating an MXML component that will be used as a pop-up window are the same as for any other MXML component:
1 Create a new MXML component based on spark.components.TitleWindow.
2 Save the new component in your project as a file with the mxml file extension.
The following code defines an MXML component designed to collect login information, and it might be saved as a file named LoginWindow.mxml:
Trang 2Part II: Designing Flex Applications
Sharing data with events
The custom component that will be used as a pop-up window should share information with the rest of the application using custom events The LoginWindow component described in the pre-ceding code sample would share events for logging in and for canceling the operation In order to share the login information, you need to create a custom event class to contain the login data
Listing 17.5 is a custom event class with public properties for the user name and password values that will be collected by the custom component
LISTING 17.5
A custom event class designed for use with a custom Login component
package events {
import flash.events.Event;
public class LoginEvent extends Event {
public var username:String;
public var password:String;
public function LoginEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
} override public function clone():Event {
var ev:LoginEvent = new LoginEvent(this.type);
ev.username = this.username;
ev.password = this.password;
return ev;
} } }
Trang 3Chapter 17: Working with Pop-up Windows
When the user clicks the custom component’s Log In button, the component shares data with the application by constructing and dispatching a custom event object:
var event:LoginEvent = new LoginEvent(“login”);
userInput.setFocus();
} ]]>
</fx:Script>
<mx:Form>
<mx:FormItem label=”User Name:”>
continued
Trang 4Part II: Designing Flex Applications
The code in Listing 17.6 is available in the Web site files as LoginTitleWindow.mxml in the chapter17
project’s src/popups folder n
Managing custom pop-up windows with the PopUpManager class
The PopUpManager is a singleton class with static methods that you use to manage custom
pop-up windows at runtime It has two methods that you can use to present a pop-pop-up window:
l addPopUp() Adds a new top-level window using a component that’s already been instantiated and is ready to use
l createPopUp() Creates a new instance of a component, presents the component as a
pop-up window, and returns a reference
Of these two methods, the addPopUp() method is more useful, because it enables you to struct and preconfigure a visual object prior to presenting it as a pop-up window
con-The PopUpManager also has these methods that you use to manipulate the position and order of pop-up windows:
l bringToFront() Gives top-level presentation and focus to a particular window
l centerPopUp() Positions a pop-up window in the horizontal and vertical center of its parent window
Finally, PopUpManager has a removePopUp() method to remove top-level windows from the display when they’re no longer needed, though they will still exist in application memory
Adding a pop-up window to the display
To add a new pop-up window to the application at runtime using the addPopUp() method, first declare an instance of the custom component you want to present This declaration will likely be outside of any functions so the pop-up window reference persists between function calls:
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 5Chapter 17: Working with Pop-up Windows
private var popup:LoginWindow;
Within a function that you call to display the pop-up window, instantiate the component and ate any required event listeners with accompanying event handler functions The LoginWindow
cre-component in this example dispatches events named login and cancel, so it requires two
addEventListener() calls:
popup = new LoginWindow();
popup.addEventListener(“login”, loginHandler);
popup.addEventListener(“cancel”, cancelHandler);
To present the window on-screen, call PopUpManager.addPopUp() with these arguments:
l childList:String The display child list in which you’re adding the pop-up window
Possible values include PopUpManagerChildList.APPLICATION,
PopUpManagerChildList.POPUP, and PopUpManagerChildList.PARENT (the default)
l modal:Boolean This argument determines whether the custom pop-up window is modal If not passed in, it defaults to false
l parent:DisplayObject The parent window over which the pop-up window is displayed
l window:IFlexDisplayObject The component reference you just instantiated
After adding the pop-up window to the application interface, you can center the window over its parent window with a call to PopUpManager.centerPopUp() If necessary, you can ensure that the new window has top-level focus with a call to PopUpManager.bringToFront().This makes a call to PopUpManager.addPopup() to present the LoginWindow custom com-ponent as a modal pop-up window and then centers it on the parent component:
PopUpManager.addPopUp(popup, this, true);
Removing a pop-up window
To remove a pop-up window, use the PopUpManager class’s static removePopUp() method
The method takes a single argument that references the pop-up window instance:
PopUpManager.removePopUp(popup);
Trang 6Part II: Designing Flex Applications
The application in Listing 17.7 uses the LoginWindow component as a pop-up window In each
of its custom event handler functions, it explicitly closes the pop-up window with a call to
private function showLoginWindow():void {
popup = new LoginTitleWindow();
popup.addEventListener(Event.CLOSE, closeHandler);
popup.addEventListener(“login”, loginHandler);
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 7Chapter 17: Working with Pop-up Windows
Alert.show(“You logged in as “ + event.username + “ with a password of “ + event.password, “Login Successful”);
PopUpManager.removePopUp(popup);
} private function closeHandler(event:Event):void {
Alert.show(“You cancelled the login operation”, “Login Cancelled”);
PopUpManager.removePopUp(popup);
} ]]>
The TitleWindow container is a subclass of Panel, so it shares all of that container’s features:
It contains a title bar, a caption, a border, and a content area, and like the Panel, it can host a
controlBarContent area with wizard-like buttons at the bottom
The TitleWindow displays a close button in its upper-right corner, creating a common visual interface for pop-up windows
The close button doesn’t actually close the pop-up window Instead, it dispatches a close event with an event object typed as mx.events.CloseEvent Upon instantiating the custom compo-nent (and prior to adding it as a pop-up window), create a listener for the close event:
popup.addEventListener(CloseEvent.CLOSE, closeHandler);
Then, in the event handler function, call PopUpManager.removePopUp() to remove the
pop-up window from the application interface:
private function closeHandler(event:CloseEvent):void{
Alert.show(“You canceled the login operation”, “Login Canceled”);
PopUpManager.removePopUp(popup);
}
Trang 8Part II: Designing Flex Applications
528
If you don’t want to display the close button in the custom pop-up window, just create a custom skin for your pop-up and modify it as needed To do this, follow these steps:
1 Open the custom pop-up window file in Flash Builder’s Design mode.
2 Right-click anywhere on the design area and select Create Skin.
3 As shown in Figure 17.12, enter the package and name of the new skin you want to
create As with all custom components, you should place the skin component in a subfolder of the project’s source-code root.
FIGURE 17.12
Creating a new custom skin based on the TitleWindow component’s default skin
4 Set Host component to spark.components.TitleWindow.
5 Select Create a copy of and use the default value spark.skins.spark.
TitleWindowSkin (this is the default skin for the Spark TitleWindow component).
6 Click Finish to create the new custom skin.
7 When the new custom skin file appears in Flash Builder’s Design mode, click the
close icon in the skin’s upper-right corner as shown in Figure 17.13.
8 Press Delete to remove the button from the skin Alternatively, you can use Source
mode and comment out the <s:Button> tag
9 Save your changes.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 9Chapter 17: Working with Pop-up Windows
10 Open the custom pop-up window file in Source mode and look at the
<s:TitleWindow> starting tag It now includes the skinClass attribute that assigns your new custom skin:
If you want to use the custom skin with all dialog boxes in your application, you can set the
skinClass style in an embedded or external style sheet For example, this CSS code assigns the new skin for all components that are based on the Spark TitleWindow component:
<fx:Style>
@namespace s “library://ns.adobe.com/flex/spark”;
s|TitleWindow { skinClass: ClassReference(“skins.CustomTitleWindowSkin”);
} </fx:Style>
Trang 10Part II: Designing Flex Applications
530
Summary
In this chapter, I described how to create pop-up windows as part of a Flex application interface
You learned the following:
l Pop-up windows are typically used to present and collect information in a windowing style application
l You use the Alert class to present simple informational messages and to enable a user to confirm or decline an operation
l The PopUpMenuButton control combines a Button and single-level Menu that’s similar
in presentation to a ComboBox
l You use the PopUpButton control to present any visual container or control as a pop-up window
l Custom pop-up windows are defined in the same way as any custom component
l The Spark TitleWindow is designed to be used as a custom pop-up window and enables dragging of the resulting window by the user
l You can remove the close button from the TitleWindow interface by creating a custom skin
l You use the PopUpManager class’s static methods to add and remove custom pop-up windows at runtime
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 12Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 13C H A P T E R
Modeling and Managing Data
IN THIS CHAPTER
Using the <fx:Model> tag
to model data items Embedding data with
<fx:Model>
Creating value object classes
in ActionScript Storing data sets in client memory with the
ArrayList and
ArrayCollection classes Filtering and sorting data with the ArrayCollection
class Traversing, searching, and bookmarking data objects with the IViewCursor
interface
Flex applications are stateful; that is, they have the capability to
remem-ber data persistently for the duration of the user’s session in a way that classic Web applications usually don’t One of the most common tasks you must accomplish as an application developer is to create a frame-work for storing data that the application can use at runtime
The content of an application’s data can come from many sources: XML files, databases or other server-side resources, or remote functions wrapped by and exposed as SOAP-style or Representational State Transfer (REST)-style Web services Regardless of how the data comes to an application, though, a Flex application stores the data in exactly the same way: as a data model
In this chapter, I describe common techniques for modeling data in Flex applications I start with creating single-object data models: ActionScript classes designed to hold one instance of a data entity at a time (A data instance might represent a row in a database table or a single element in an XML file.) You can represent such data instances with the <fx:Model> tag,
a generic data object, or, more commonly, you create your own custom
ActionScript classes, known variously by the design pattern names Value
Object and Transfer Object.
In the second part of the chapter, I describe the use of data collections:
ordered collections of data instances managed by the ArrayList and
ArrayCollection classes I describe how and where to declare these classes and then describe how to use the powerful ArrayCollection class
to filter, sort, bookmark, and traverse data in client application memory
On the Web
To use the sample code for this chapter, import the chapter18.fxp Flex project archive from the Web site files into your Flex Builder workspace n
Trang 14Part III: Working with Data
534
Creating a Data Model
A data model is a way of representing data (information) in a client application It’s a truism of database applications that you can’t do much without knowing your data structure Take an appli-cation that represents the personal information of your contact list Whether you store this data in
an e-mail client or a complex server-side database application such as SQL Server or MySQL, the software that manages the data has to know its structure
In classic relational databases, data is stored in tables Each table has columns that represent the bits of data that are created for each row in the table A database table representing contact infor-mation might have any number of columns Each column has a name and a data type For exam-ple, a contacts table might have the data structure shown in Table 18.1
TABLE 18.1
A Simple Database Table Structure
When data is returned to a Flex application in this structure, you need a way to store it The goal is
to create an object that can serve as a container for this data and can share this data structure to the best of the Flex framework’s capability
Figure 18.1 shows a UML diagram describing the structure of an object that would be able to hold this data
You can create a data model to store the data in two ways: by using the <fx:Model> tag to declare a generic untyped data object and by creating a custom ActionScript class Of these approaches, the custom ActionScript version is significantly more powerful and flexible The
<fx:Model> approach is fast and easy to code, and it might be used during early prototyping of
an application, but an application that’s built for durability and easy long-term maintenance ally requires custom ActionScript classes to represent data in Flex application memory
gener-Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 15Chapter 18: Modeling and Managing Data
Using the <fx:Model> element
The <fx:Model> element compiles XML markup into a generic ActionScript Object New Feature
The <fx:Model> element was used with the mx prefix in previous versions of the Flex SDK As with all sual elements, it must be declared within an <fx:Declarations> element in a Flex 4 application n
nonvi-You could implement the data structure described in the UML diagram in Figure 18.1 as a data object with this code:
Trang 16Part III: Working with Data
At runtime, as the user interacts with form controls, the controls’ values are passed to the Model
object through the binding expressions
Trang 17Chapter 18: Modeling and Managing Data
</data>
</fx:Model>
</fx:Declarations>
<s:VGroup top=”20” horizontalCenter=”0”>
<s:Label text=”{contact.firstName} {contact.lastName}”/>
l The object and all its properties are automatically bindable You don’t have to include
the [Bindable] metadata tag, and you can refer to any of the object’s properties with binding expressions, as in:
<s:Label text=”{contact.firstName} {contact.lastName}”/>
l The <fx:Model> tag uses simple XML syntax to declare its property names
After a data object has been declared with the <fx:Model> tag, you refer to its data using dot syntax The object’s id, assigned in the <fx:Model> start tag, actually refers to the model’s root element if there is a sole root element In the preceding example, this element is named <data>, but its name isn’t important; you refer to the root by the model object’s id and then to its named properties as child objects of the model:
l You can declare only a single instance of an object Unlike strongly typed ActionScript
classes, which are designed to be instantiated as many times as necessary, if you want another data object you have to declare it explicitly
l Because <fx:Model> is a compiler tag that doesn’t represent an ActionScript class,
it has no methods or properties.
Trang 18Part III: Working with Data
538
Importing data with <fx:Model>
The <fx:Model> tag does have one very useful capability: It can be used to compile data into an application This technique is useful only when two circumstances are true:
l It is a relatively small amount of data Large amounts of embedded data result in an
increase in the size of the compiled application For applications that are deployed over the Web, embedding data results in a slower download and longer delay before the appli-cation starts for the first time On the positive side, the data is instantly available to the application without having to be downloaded at runtime
l The data is completely static If any of the data under consideration might change
dur-ing the lifetime of the application, you should load the data at runtime usdur-ing the
HTTPService component or another runtime loading mechanism
To embed data with the <fx:Model> tag, first save it as an XML file The names of the XML file’s data elements can be anything you like; the only requirements are that the XML file be well formed and have a single root element The following XML structure is suitable for use with the
<fx:Model id=”bookData” source=”data/books.xml”/>
As with hard-coded data, the Model element’s id points to the XML structure’s root element
From there, the data typing of each element depends on the number of elements with a particular name If the preceding structure contains two or more <book> elements, the expression book-Data.book returns an Array If the XML structure’s root element contains only a single child
<book> element, the expression bookData.book instead returns an ActionScript Object
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 19Chapter 18: Modeling and Managing Data
Tip
To ensure that you always have an Array to work with, you can use the ArrayUtil.toArray() method wrapped around an expression that might return an Object due to the number of elements in the XML data structure At application startup, declare a separate Array variable and fill it as shown here:
import mx.utils.ArrayUtil;
[Bindable]
private var bookArray:Array;
private function initApp():void{
bookArray = ArrayUtil.toArray(bookData.book);
} n
Using Value Objects
A value object, also known variously as a transfer object, a data transfer object, and a bean, is a class
designed to hold data for a single instance of a data entity The design pattern is named Transfer Object in the world of Java Enterprise Edition (JEE) application server development, where it’s implemented as a Java class
Web Resource
The Transfer Object design pattern is described in the J2EE design pattern catalog at http://java.sun
com/blueprints/corej2eepatterns/Patterns/TransferObject.html In the most recent sion on the Sun Web site, the graphics still refer to the design pattern as Value Object, its old name Don’t be confused; it’s really the same pattern! n
ver-Value object classes have these advantages over the <fx:Model> tag:
l Class properties can be strongly datatyped Each property is declared with standard able declaration syntax and typically has a data type declared after the colon:
vari-public var myDateProperty:Date;
l Class properties can have default values As when declaring a variable inside or outside a function, you can declare default values by appending the value after an = assignment operator This code declares a Date property with the default set to the current date:
public var myDateProperty:Date = new Date();
l You can use implicit setter and getter accessor methods Accessor methods enable plex logic and authentication when setting or getting data and creating read-only proper-ties (properties that can be read from the application but can only be set internally within the value object class)
com-l When you integrate a Flex client application with an application server that supports data transfer with AMF (Action Message Format), such as ColdFusion, BlazeDS, LiveCycle Data Services, PHP, and others, client-side value object classes defined in ActionScript can be mapped to equivalent classes on the server (written in the server’s native language, such as Java, ColdFusion Markup Language, PHP, or C#) This enables you to pass data between the application tiers with minimal code in both tiers
Trang 20Part III: Working with Data
540
Using the New ActionScript Class wizard
You can use Flex Builder’s ActionScript Class wizard to create a simple ActionScript class Follow these steps to create a new value object class to represent Book data:
1 Open the chapter18 project if it isn’t already open Notice that the project contains
a valueObjects package
2 Right-click on the valueObjects package and select New ➪ ActionScript Class.
3 Set the class name as Contact, as shown in Figure 18.2.
4 Click Finish to create the new ActionScript class.
FIGURE 18.2
The New ActionScript Class wizard
The completed ActionScript class is created in the file Contact.as in the valueObjects folder and should appear in the Source view editor as follows:
package valueObjects{
public class Contact {
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 21Chapter 18: Modeling and Managing Data
public function Contact() {
} }}
The class is ready to fill in with properties and other functionality
Value object class syntax
Value objects are implemented in Flex as simple ActionScript classes, and their syntax is mined by basic ActionScript syntax requirements In this section, I describe each part of a value object class, its purpose, and some best practice recommendations
deter-Declaring a package
A package is a collection of related classes As in many other languages, including both Java and
ColdFusion, packages are tied to the folder structure of an application’s source code
In ActionScript 3.0, each public ActionScript class must be wrapped inside a package declaration that’s implemented as a code block The package declaration tells the compiler where the class is stored based on its package within the project’s source root folder or other locations in the proj-ect’s build path
As shown in Figure 18.3, the Contact value object class is stored in the valueObjects subfolder
of the project’s source root
FIGURE 18.3
The project structure, including the valueObjects subfolder
Trang 22Part III: Working with Data
542
The package declaration looks like this:
package valueObjects{
public class declaration here
}
Caution
When you generate a new class file with the New ActionScript Class wizard, the package declaration is created for you However, if you move the class source code later, you’re responsible for manually updating the pack- age declaration in the class source code n
Declaring the public class
The class declaration for a public class is placed inside the package code block Value object classes are always declared as public, so they can be used by the rest of the application Also, value object classes typically don’t explicitly extend any other class, as they usually don’t have to inherit existing functionality
The name of an ActionScript public class must match the name of the source-code file in which it’s defined The name is case-sensitive, and by convention always has an initial uppercase character
The public class declaration looks like this:
package valueObjects{
public class Contact {
class members declared here
}}
As noted in the preceding example, members of the class, including properties, functions, and stants, are declared inside the class declaration’s code block
con-Tip
You can declare private classes in an ActionScript class source-code file These classes are available for use only by the public class in whose source-code file the private class is declared The private class doesn’t actu- ally have a private access modifier declaration, and it’s declared outside the package declaration:
package valueObjects{
public class Book {
public var page1:Page = new Page();
public function Book() {
}
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 23Chapter 18: Modeling and Managing Data
}}class Page {
public var pageNumber:int;
public var text:String;
} n
Declaring ActionScript class properties
ActionScript class properties are declared as variables, using this syntax:
[access modifier] var [property name]:[data type];
The access modifiers at the beginning of a property declaration should be one of these keywords:
l internal Properties that can be set and read by the current class and by any classes in the same package
l private Properties that can only be set and read by instances of the class in which they’re declared
l protected Properties that can be set and read by the current class and by any of its subclasses
l public Properties that can be set and read by the rest of the application
Note
The default access modifier is internal; if you leave the access modifier off a property declaration, the erty is available only to the current class and any other classes in the same package You’ll also see a compiler warning indicating that you should include an explicit access modifier n
prop-The name of a property is subject to naming rules for all ActionScript identifiers: It can include alphabetical, numeric, and underscore characters, and it must start with an alphabetical character
or an underscore The following naming conventions are considered to be best practices by most developers:
l The initial character in a property name is lowercase
l Private properties have an initial underscore (_) character
Neither of these conventions is a technical requirement, but by following them you create code that makes sense to other developers
To add public properties representing the data structure in Table 18.1, follow these steps:
1 Open the Contact.as file you created in the previous exercise.
2 Place the cursor inside the class declaration’s code block, but before the constructor
method.
Trang 24Part III: Working with Data
544
3 Declare each of the required properties with appropriate data types, as follows:
public var contactId:int=0;
public var firstName:String;
public var lastName:String;
public var dob:Date;
public var address:String;
public var city:String;
public var zipCode:String;
public var telephone:String;
4 Save the file to disk.
Making properties bindable
Value objects benefit from having their properties marked as bindable, so that as the property ues change at runtime, they can broadcast those changes to any objects with binding expressions
val-You can make individual properties bindable by adding the [Bindable] metadata tag before each property declaration This code makes the firstName and lastName properties bindable, but doesn’t do the same for the contactId property:
public var contactId:int=0;
[Bindable]
public var firstName:String;
[Bindable]
public var lastName:String;
Alternatively, you can add a single [Bindable] tag before the class declaration to make all its erties bindable:
prop-package valueObjects{
[Bindable]
public class Contact {
public var contactId:int=0;
public var firstName:String;
public var lastName:String;
remaining property declarations
}}
Follow these steps to make all the value object class’s properties bindable:
1 Open Contact.as
2 Create an empty line just before the class declaration, and add a [Bindable]
meta-data tag.
3 Save the changes to disk.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
Trang 25Chapter 18: Modeling and Managing Data
Listing 18.2 shows the completed value object Contact class
LISTING 18.2
A completed value object class
package valueObjects {
[Bindable]
public class Contact {
public var contactId:int=0;
public var firstName:String;
public var lastName:String;
public var dob:Date;
public var address:String;
public var city:String;
public var zipCode:String;
public var telephone:String;
public function Contact() {
} } }
On the Web
A completed class that’s similar to Listing 18.2 is available in the Web site files as ContactComplete.as in the chapter18 project n
Using private properties and accessor methods
If you prefer, you can use private properties and set and get accessor methods This is a preferred syntax for some developers, because it follows the object-oriented practice of encapsulation and hiding data members from public usage
To declare a private property in an ActionScript class, replace the public access modifier with the keyword private If you like, you also can follow the practice of using an underscore (_) prefix
as the property name’s initial character:
private var _firstName:String;
To make the property accessible to the rest of the application, you then create set and get accessor methods In ActionScript 3, these methods use explicit set and get keywords to indicate that the functions should be accessed by the class consumer as though they were properties