Table of Contents

Next Page

Professional Adobe Flex 2
Professional Adobe Flex 2
byRich Tretola, Simon BarberandRenaun Erickson
Wrox Press 2007 (718 pages)
ISBN:9780470102671

With numerous practical examples that you can tweak and apply in your own environment, this hands-on guide offers best practices that will enable you to begin developing and deploying applications in Flex 2 that meet your requirements.

Table of Contents
 | Professional Adobe Flex 2
 | Introduction
 | Part I - Getting Started
 | Chapter 1 | - | Introducing Flex 2.0
 | Chapter 2 | - | Introducing Flex Builder 2.0
 | Chapter 3 | - | Flex 2.0 Basics
 | Chapter 4 | - | Using Flex Builder 2.0
 | Part II - Developing in Flex 2.0
 | Chapter 5 | - | Programming Languages
 | Chapter 6 | - | Building User Interfaces
 | Chapter 7 | - | Customizing the User Interface
 | Chapter 8 | - | Flex UI Topics
 | Chapter 9 | - | Flex Data
 | Chapter 10 | - | Flex Charting
 | Chapter 11 | - | Data Access
 | Part III - Creating and Extending Flex Components
 | Chapter 12 | - | Creating MXML Components
 | Chapter 13 | - | Flex Component Properties
 | Chapter 14 | - | Flex Components
 | Chapter 15 | - | Custom Formatter, Validator, and Effect Components
 | Part IV - Programming ActionScript 3.0
 | Chapter 16 | - | Overview of ActionScript Programming
 | Chapter 17 | - | Data Types and Classes
 | Part V - Building and Deploying Flex 2.0 Applications
 | Chapter 18 | - | Building and Deploying Flex Applications
 | Chapter 19 | - | Debugging and Testing
 | Chapter 20 | - | Deploying Flex Applications
 | Part VI - Advanced Flex 2.0
 | Chapter 21 | - | Using the Cairngorm Framework
 | Chapter 22 | - | Using the Flex-Ajax Bridge
 | Chapter 23 | - | Using the ActionScript 3.0 Libraries
 | Chapter 24 | - | Using ColdFusion/Flex Connectivity
 | Part VII - Integration Techniques
 | Chapter 25 | - | Rich Media Integration
 | Chapter 26 | - | Integration with External Applications
 | Appendix A | - | Flex 2.0.1
 | Index
 | List of Figures
 | List of Listings

Next Page


Back Cover

Previous Page
Next Page

Back Cover

If you want to learn how to create robust, scalable applications using the power of Flex 2, then this is the book for you. This book walks you through all aspects of this powerful software and shows you how to build your own custom components. You'll gain a thorough understanding of the Software Development Kit (SDK), Flex Data Services (FDS), Flex Builder 2 Integrated Development Environment (IDE), Flex Charting, and much more.

Integrated throughout the pages, you'll find best practices that will enable you to begin developing and deploying applications in Flex 2 that meet your requirements. You'll also discover the most effective ways to use frameworks, MXML, and ActionScript 3. And with the help of numerous practical examples that you can tweak and apply in your own environment, this hands-on guide will quickly get you quickly up and running.

What you will learn from this book

  • Steps for developing an application using Flex Builder
  • How to build customized user interfaces with Flex controls and containers
  • Ways to access data and chart components
  • Tips for creating and extending Flex components
  • Methods for programming and data typing ActionScript classes
  • All about integrating Flex 2 with rich media and external applications
  • How to use the Cairngorm framework, the Flex-Ajax bridge, ActionScript 3.0 libraries, and more

Who this book is for

This book is for programmers and Web developers who want to create Internet applications using Flex 2. You should have prior experience with Flash, ActionScript, and an XML-based language.

Previous Page


Professional Adobe Flex 2

Rich Tretola
Simon Barber
Renaun Erickson
Image from book
Wiley Publishing, Inc.

Published by
Wiley Publishing, Inc.
10475 Crosspoint Boulevard
Indianapolis, IN 46256
www.wiley.com

© 2007 by Wiley Publishing, Inc., Indianapolis, Indiana

Published simultaneously in Canada

ISBN: 9780470102671

10 9 8 7 6 5 4 3 2 1

Library of Congress Cataloging-in-Publication Data

Tretola, Rich, 1971-
Professional Adobe Flex 2 / Rich Tretola, Simon Barber, Renaun Erickson.
p. cm.
Includes index.
ISBN 978-0-470-10267-1 (pbk.)
1. Internet programming. 2. Application software--Development. 3. Web site development--Computer programs. 4. Flex (Computer file) I. Barber, Simon, 1980- II. Erickson, Renaun, 1977- III. Title. IV. Title: Professional Adobe Flex Two.
QA76.625.T74 2007
005.2'768--dc22

2007008855

No part of this publication may be reproduced, stored in a retrieval system or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, scanning or otherwise, except as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, without either the prior written permission of the Publisher, or authorization through payment of the appropriate per-copy fee to the Copyright Clearance Center, 222 Rosewood Drive, Danvers, MA 01923, (978) 750-8400, fax (978) 646-8600. Requests to the Publisher for permission should be addressed to the Legal Department, Wiley Publishing, Inc., 10475 Crosspoint Blvd., Indianapolis, IN 46256, (317) 572-3447, fax (317) 572-4355, or online at http://www.wiley.com/go/permissions.

LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND THE AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS WORK AND SPECIFICALLY DISCLAIM ALL WARRANTIES, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES OR PROMOTIONAL MATERIALS. THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY SITUATION. THIS WORK IS SOLD WITH THE UNDERSTANDING THAT THE PUBLISHER IS NOT ENGAGED IN RENDERING LEGAL, ACCOUNTING, OR OTHER PROFESSIONAL SERVICES. IF PROFESSIONAL ASSISTANCE IS REQUIRED, THE SERVICES OF A COMPETENT PROFESSIONAL PERSON SHOULD BE SOUGHT. NEITHER THE PUBLISHER NOR THE AUTHOR SHALL BE LIABLE FOR DAMAGES ARISING HEREFROM. THE FACT THAT AN ORGANIZATION OR WEBSITE IS REFERRED TO IN THIS WORK AS A CITATION AND/OR A POTENTIAL SOURCE OF FURTHER INFORMATION DOES NOT MEAN THAT THE AUTHOR OR THE PUBLISHER ENDORSES THE INFORMATION THE ORGANIZATION OR WEBSITE MAY PROVIDE OR RECOMMENDATIONS IT MAY MAKE. FURTHER, READERS SHOULD BE AWARE THAT INTERNET WEBSITES LISTED IN THIS WORK MAY HAVE CHANGED OR DISAPPEARED BETWEEN WHEN THIS WORK WAS WRITTEN AND WHEN IT IS READ.

For general information on our other products and services please contact our Customer Care Department within the United States at (800) 762-2974, outside the United States at (317) 572-3993 or fax (317) 572-4002.

Trademarks: Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries, and may not be used without written permission. Microsoft and Excel are registered trademarks of Microsoft Corporation in the United States and/or other countries. All other trademarks are the property of their respective owners. Wiley Publishing, Inc., is not associated with any product or vendor mentioned in this book.

Wiley also publishes its books in a variety of electronic formats. Some content that appears in print may not be available in electronic books.

Dedication

To the love of my life, Kim, and my beautiful daughters, Skye and Coral.

- Rich Tretola

The work on this book is dedicated to my family and friends, most notably Phil, Tina, Joanna, and Kimberley.

- Simon Barber

The book for Einar and Ranel, my love to Eve and the boys.

- Renaun Erickson

Acknowledgments

This book would not have been possible without the hard work of my co-authors Simon and Renaun, and I want to thank them both for their contributions. I would also like to thank the Acquisitions Editor, Chris Webb, and the Development Editor, Kevin Shafer, for their commitment to getting the project completed through many challenges.

Special thanks to the members of the Internet Services team at Herff Jones, including Michael McKellip, Jeff Titus, Bill Davis, Tim Johnson, Rob Schimp, Brent Johnson, and my manager, Jeff Patrick. The support of these team members and management has enabled me to transition my development career to be focused on Rich Internet Application development.

Most importantly, I would thank my wife, Kim. She has given me two beautiful daughters, Skye and Coral, and is my best friend. Without her support, it would not have been possible for me to transform my career path to software development. She has supported me through good times and bad, and has always believed in me, and for this I am eternally grateful. Aloha no au ia 'oe.

- Rich Tretola

Thank you to my co-authors, Rich and Renaun; without you this would never have been possible. Also, I would like to thank Chris Webb, the Acquisition Editor, for all his hard work in making this book a success.

Many thanks go out to my family, co-workers, and friends, without whom this would not have been possible.

- Simon Barber

I would like to first thank Chris Webb for helping me become a part of this project. I would like to thank Rich and Simon for the opportunity to contribute as an author on the project. All the hard work of the editor Kevin Shafer and other technical editors is an experience I’ll never forget - thank you.

- Renaun Erickson

Credits

Contributing Writers
Marco Casario
Marc Leuchner
Andrew Muller

Executive Editor
Chris Webb

Development Editor
Kevin Shafer

Technical Editors
Charles Freedman
Andy McIntosh
Drew McLean
Clint Modien
Josh Tynjala

Production Editor
Christine O’Connor

Copy Editor
Kim Cofer

Editorial Manager
Mary Beth Wakefield

Production Manager
Tim Tate

Vice President and Executive Group Publisher
Richard Swadley

Vice President and Executive Publisher
Joseph B. Wikert

Compositor
Laurie Stewart, Happenstance Type-O-Rama

Project Coordinator
Hether Kolter

Proofreader
James Brook, Word One

Indexer
Robert Swanson

Anniversary Logo Design
Richard Pacifico


Introduction

The Flex product line was originally released by Macromedia in 2003, then followed up by Flex 1.5, and now Flex 2 by Adobe in 2006. Flex 2 marks a milestone for the Rich Internet Applications (RIAs) development community because it has developed into a mature product with excellent development tools and resources. Although previous versions were expensive and targeted large corporations, this has changed with Flex 2 because the new pricing model puts the power of Flex into the hands of all developers and companies for as little as free. Developers worldwide rejoiced when Adobe announced that it would be releasing portions of Flex at no charge, as well as a very reasonably priced development environment for those who choose to use it.

Flex applications run within the Flash Player, which is the single-most downloaded piece of software in the history of the Internet. Because so many people already have the Flash Player and the Flash Player is so easily upgraded, Flex applications being built today will be available to run on a large section of the population’s computers.

There is a growing wave of excitement around Flex, and we find ourselves in the early stages of a revolution of the Internet. Flex will play a large part in reshaping the Internet from the 1990s into a new, richer, more interactive Internet, sometimes referred to as Web 2.0. A great opportunity exists to make your mark on Web 2.0 by using Flex technologies, and this book will help you get there.

Who This Book Is For

If you have been using Flex since its version 1 release (or you are someone who is starting with Flex), this book will provide valuable information for handling just about any possible request during the development of your applications. It will also prove itself to be an invaluable resource as a reference manual. The examples provided throughout this book are concise and very easy to understand. Code samples within this book have been carefully written so that they can be easily applied to real-world applications. If you are someone who wants to start building Flex applications (or is already doing so), this book will help you take your applications to a higher level.


What This Book Covers

This book covers all aspects of Flex 2, including the Software Development Kit (SDK), Flex Data Services (FDS), Flex Builder 2 Integrated Development Environment (IDE), Flex Charting, and much more. You will learn about MXML (which is a tag-based programming language), as well as ActionScript 3 (which is the companion scripting language), and where to use each. This book will also show you how to use Flex components and how to create your own custom components. You will see how to structure your applications with frameworks and best practices.


How This Book Is Structured

This book has been broken down into seven sections, each covering specific areas of Flex. These sections are as follows:

  • Getting Started - This section introduces Flex and Flex Builder. It covers some of the Flex basics and demonstrates how to use Flex Builder.

  • Developing in Flex 2.0 - This section focuses on building user interfaces, customizing those interfaces, accessing data from your Flex application, and Flex charting components.

  • Creating and Extending Flex Components - This section shows you how to create components using both MXML and ActionScript, as well as how to customize them.

  • Programming ActionScript 3.0 - This section discusses programming and data typing ActionScript classes.

  • Building and Deploying Flex 2.0 Applications - This section focuses on building, debugging, and deploying Flex applications. It also covers the configuration of the integrated JRun server.

  • Advanced Flex 2.0 - This section discusses the usage of the Cairngorm Framework, the Flex-Ajax Bridge, ActionScript 3.0 libraries, and ColdFusion/Flex connectivity.

  • Flex 2.0 Integration Techniques - The last section covers integration with rich media and external applications.

Appendix A also includes an overview of Flex 2.0.1, and discusses what is new with this updated release of Flex 2.


What You Need to Use This Book

Although all of the examples in this book were created using the Windows operating system, almost all will also run perfectly on the other operating systems supported by Adobe. For the best results, you should use Flex Builder to compile the examples in the book. However, if you are a non-GUI kind of person, you can certainly compile them using the free Flex SDK.


Conventions

To help you get the most from the text and keep track of what’s happening, a number of conventions have been used throughout the book.

Important

Boxes like this one hold important, not-to-be forgotten information that is directly relevant to the surrounding text.
Tip

Tips, hints, tricks, and asides to the current discussion are offset like this.

As for styles in the text:

  • Important new terms and important words are highlighted when they are introduced.

  • Keyboard strokes are shown like this: Ctrl+A.

  • Filenames, URLs, and code within the text are shown like this: persistence.properties.

  • Code is presented in the following two ways:

In code examples, new and important code is highlighted with a gray background.
The gray highlighting is not used for code that's less important in the present
context, or has been shown before.


Source Code

As you work through the examples in this book, you may choose either to type in all the code manually, or use the source code files that accompany the book. All of the source code used in this book is available for download at http://www.wrox.com. Once at the site, simply locate the book’s title (either by using the Search box or by using one of the title lists), and click the Download Code link on the book’s detail page to obtain all the source code for the book.

Tip

Because many books have similar titles, you may find it easiest to search by ISBN; for this book the ISBN is 978-0-470-10267-1.

Once you download the code, just decompress it with your favorite compression tool. Alternatively, you can go to the main Wrox code download page at http://www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books.


Errata

We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books (such as a spelling mistake or faulty piece of code), we would be very grateful for your feedback. By sending in errata you may save another reader hours of frustration and at the same time you will be helping us provide even higher quality information.

To find the errata page for this book, go to http://www.wrox.com and locate the title using the Search box or one of the title lists. Then, on the book details page, click the Book Errata link. On this page, you can view all errata that has been submitted for this book and posted by Wrox editors. A complete book list including links to each book’s errata is also available at www.wrox.com/misc-pages/booklist.shtml.

If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport.shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.


p2p.wrox.com

For author and peer discussion, join the P2P forums at p2p.wrox.com. The forums are a Web-based system for you to post messages relating to Wrox books and related technologies and to interact with other readers and technology users. The forums offer a subscription feature to email you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums.

At http://p2p.wrox.com you will find a number of different forums that will help you not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:

  1. Go to p2p.wrox.com and click the Register link.

  2. Read the terms of use and click Agree.

  3. Complete the required information to join, as well as any optional information you wish to provide, and click Submit.

  4. You will receive an e-mail with information describing how to verify your account and complete the joining process.

Tip

You can read messages in the forums without joining P2P, but in order to post your own messages, you must join.

Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the Web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing.

For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works, as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.


Part I: Getting Started

Chapter List

Chapter 1: Introducing Flex 2.0
Chapter 2: Introducing Flex Builder 2.0
Chapter 3: Flex 2.0 Basics
Chapter 4: Using Flex Builder 2.0


Chapter 1: Introducing Flex 2.0

Flex 2.0 is arguably the most important new Internet development tool set released to date. It will help speed the migration of the Internet to the Web 2.0 that we have been promised for so long now. Not only has Adobe introduced an extremely easy-to-use development environment in Flex Builder 2.0, but it has also released an SDK allowing for Flex Rich Internet Applications to be developed with absolutely no fees. So what are Rich Internet Applications? Let’s start with a definition.

Rich Internet Applications

A Rich Internet Application (RIA) is an application that runs in the traditional browser but utilizes an intermediate layer that can bypass the traditional page refresh that has been a standard of most current Web applications. The most common tools that can achieve this intermediate layer include JavaScript used in Asynchronous JavaScript and XML (Ajax) applications, as well as Flex or Flash using the Flash Player. Other RIA solutions include OpenLaszlo (which utilizes the Flash Player as well as Ajax), XUL (which is dependent on a Mozilla-compatible browser), and the Windows Presentation Foundation (which is part of the Microsoft .NET Framework 3.0).

OpenLaszlo

Like Flex, OpenLaszlo can compile to SWF and, because it is open source, it is also free for developers to use. OpenLaszlo applications are built using JavaScript, as well as an Extensible Markup Language (XML) based programming language named LZX, and compiled to SWF. It is very similar to Flex, and because it was available for free, it garnered a larger amount of attention during the days of Flex 1.5. Because OpenLaszlo compiles to SWF, it enjoys the same write-once-run-anywhere feature that is synonymous with Flex and Flash applications. The one advantage to OpenLaszlo over Flex is that the next version of OpenLaszlo (code-named legals) will allow write-once-and-compile to either an SWF or a dynamic HTML (DHTML), or Ajax, application. The major disadvantages of OpenLaszlo are that it has a smaller set of built-in components than Flex, and it has always been at least one full version behind in optimization for the most current Flash Player.

Ajax

Ajax is a combination of HTML or Extensible HTML (XHTML), Cascading Style Sheets (CSS), and JavaScript to create an application-type feel from a standard Web page request. CSS and JavaScript can be used to trigger updates to the visual aspect of the page, and XMLHttpRequests can be used to fetch data in the background of the page. The combination of these techniques allows a single Web page to change its appearance and update its data without any additional page requests from the server. There are many limitations to this type of RIA, including compatibility issues with browser versions, as well as differences in (or lack of) JavaScript support necessary for the RIA to perform as expected.

XUL

XML User Interface Language (XUL) is an XML-based language developed by the Mozilla project. It is a tag-based language that contains many predefined widgets (buttons, radio buttons, and so on) that will be rendered only by a Mozilla-compatible browser such as Firefox. Although it can also be used in the creation of RIAs, XUL has been most widely used in the creation of Mozilla applications and extensions.

Windows Presentation Foundation

Windows Presentation Foundation (WPF) consists of an engine and a framework that will be preinstalled in Windows Vista, and introduces Extensible Application Markup Language (XAML) as a new tag-based language. XAML is very similar to MXML because it is a tag-based XML language with attributes whereby each tag creates an object model class. XAML tags are fully extendable, allowing developers to create custom classes. XAML, along with C# (which is the programming language), would correspond to MXML and ActionScript 3 in Adobe Flex.

WPF is used for both traditional desktop applications and browser-based RIAs. With Microsoft’s backing, WPF and XAML are sure to make a large contribution to Web 2.0 and RIA. Microsoft has stated that it will also introduce Windows Presentation Server Everywhere (WPF/E), which will provide support for other browsers and platforms. One major advantage of WPF is that it will support three dimensions out of the box, which is something that has been lacking in the Flash Player. A disadvantage of WPF is that it does not run within the Flash Player, and it will be a long time before Microsoft can expect the same penetration of its runtime as the Flash Player.

History of RIA

Although the concept of a Web application that performs more in line with the traditional desktop application has been around for years, RIAs were first introduced by Macromedia in March 2002.

Benefits of RIA

RIAs offer many benefits over traditional Web applications. Following are a few of the many advantages of RIAs:

  • RIAs offer a richer interface that provides a more engaging user experience without the need for page reloads.

  • RIAs offer real-time feedback and validation to the user, triggered by user events.

  • The look and feel of a traditional desktop application can be accomplished with an RIA.

  • RIAs also can include a full multimedia experience, including audio and video.

  • RIAs have capabilities such as real-time chat and collaboration that are either very difficult or simply impossible with traditional Web applications.


Overview of Flex

Flex was developed to create a development environment that more closely resembled the traditional development environment utilized by other programming languages. The goal was to take the already tremendously successful Flash visual development environment and open it up to programmers who are more comfortable with a code-based model.

In 2004, Macromedia released Flex 1.0, which caused a buzz in the world of RIAs because it was the first time that it was possible to compile Flash SWF files from code. In 2005, Flex 1.5 was released, which was a big improvement over Flex 1.0 and included many new features. A few of the notable new features included new charting components, updates to the datagrid component, and new component-skinning techniques for more control over the look and feel of Flex 1.5 applications.

Flex 1.5 was very successful, but was still targeted to the mid- to large-size company, and it was priced that way. For smaller companies and developers, Flex 1.5 was simply out of reach because of Macromedia’s pricing model. In 2006, Adobe released Flex 2.0 and announced that it was now possible to create and distribute Flex 2.0 applications absolutely free. This has created a large influx of developers into the Flex community, and shows tremendous growth potential.

Flex 2

Flex 2 is a tremendous upgrade over its predecessor. It includes a new version of the MXML tag-based language, as well as a new version of ActionScript. Adobe has built the Flex 2 Framework to be fully extendable, allowing developers to create custom components that extend or combine base components using either MXML or ActionScript 3.

Flex 2 is built to run within the all-new Flash 9 Player, which in itself includes huge performance increases over previous versions. Flex 2 includes a new development environment built on the Open Source Eclipse integrated development environment (IDE) named Flex Builder 2, the free Flex 2 SDK, as well as the new Flex Data Services (FDS) application server. Flex 2 also offers a new set of charting components that are not part of the basic free versions of the Flex SDK but can be purchased separately or as part of a Flex Builder package.

Flash Player 9

In May 1996, a small company named FutureWave Software released a product that it called FutureSplash Animator. FutureSplash was released as a browser extension using the new plug-in API from Netscape. Ironically, FutureWave attempted to sell its technology to Adobe, but at the time, Adobe wasn’t interested. Macromedia was interested in FutureSplash, and, in December 1996, acquired FutureWave Software. Macromedia renamed FutureSplash as Flash Player 1.0.

Following is a timeline of key events in this history of the Flash player:

  • 1997 - FutureSplash is renamed and released as Macromedia Flash 1.0.

  • 1997 - Flash 2 adds buttons, the Library, sound support, and color tweens.

  • 1998 - Flash 3 adds new animations and alpha transparency.

  • 1999 - Flash 4 adds MP3 audion streaming and motion tweens.

  • 1999 - 100-millionth download of the Flash Player.

  • 2000 - Flash 5 adds ActionScript 1.

  • 2000 - Flash Player installs reach the 92 percent penetration mark.

  • 2002 - Flash Player 6 adds support for Flash remoting, Web services, video, shared libraries, and components.

  • 2003 - Flash Player 7 introduces ActionScript 2.0 and streaming audio and video.

  • 2005 - Flash Player 8 adds filter effects, GIF and PNG images, bitmap caching, new video codec (On2 VP6), file upload and downloading, and FlashType.

  • 2006 - Flash Player 9 is released and introduces ActionScript 3, E4X XML parsing, regular expressions, and binary sockets.

The introduction of Flash Player 9 in 2006 represents the most significant release of any Flash Player to date. The incorporation of ActionScript 3 brings true object-oriented programming to Flex 2 and the upcoming Flash 9 authoring tool. Flash Player 9 boasts performance increases of up to ten times over Flash Player 8. Flash Player 9 is based on the ECMAScript standard and adds new features, including ECMAScript for XML (E4X), regular expressions, a standardized event model, and binary sockets.

Flash Player 9 also includes better memory utilization, improved application initiation speed, as well as improvements in the debugger and error reporting.

Flex Builder 2

Flex Builder 2 is the new development tool that (although it is not necessary for Flex development because any text editor can be used) offers the most complete development environment for rapidly creating Flex applications. Because Flex Builder 2 has been built on top of the mature Eclipse IDE, it will be very familiar to developers who have already been developing software in other languages using Eclipse as their tool of choice. Eclipse is a development environment that was built with extendability in mind, and this can also work to the benefit of Flex developers because it can be customized to suit the needs of the Flex developer. Chapter 2 provides a more comprehensive look into Flex Builder 2.

Flex Free SDK 2

The Flex Software Development Kit (SDK) is a free download from Adobe and includes the Flex framework (component class library), compiler, and debugger. Using the text editor of your choice, you can create the ActionScript and MXML files for your application, and then compile to SWF using the SDK. The SDK allows for data communication via Web services, HTTP services, and Flash remoting with ColdFusion as the back-end server.

Flex Data Services (FDS)

FDS is the server version of Flex that must be installed under any Java 2 Enterprise Edition (J2EE) server. FDS is essentially the next generation of Flex 1.5, which was sold only as a server.

As well as a full commercial edition, the FDS server is available in an Express edition, which is free and available for commercial use (but is limited to one CPU without clustering).

FDS is made up of several components and capabilities, including the following:

  • Flex Messaging Services (FMS)

  • Publish-subscribe messaging

  • Data push

  • RPC services

Flex Messaging Services

FMS is one of the pieces that make up FDS, and it allows for the creation of applications that support real-time messaging, as well as collaboration. The messaging service has support for Java Message Service (JMS), as well as other existing messaging services, allowing for the creation of cross-platform chat applications.

Publish-Subscribe Messaging

FMS uses the producer/consumer publish-subscribe metaphor, which allows for the creation of co-browsing applications. To understand what is meant by a co-browser application, imagine a company’s customer service representative being able to make edits to a form on the user’s screen in real time while the user watches.

Data Push

Data push is the capability for the server to push data changes to the client without any user interaction or polling of the servers. This can be critical when an application has hundreds or thousands of users connected, and they can all see changes to business-critical data in real time. This is a feature that is available only when using the FDS server.

RPC Services

Remote procedure call (RPC) services are the suite of services used to connect to external data. They include the following:

  • WebService - The WebService component can be used to access any Web service that complies with the WSDL 1.1 standard and returns data formatted as Simple Object Access Protocol (SOAP) messages over HTTP.

  • HTTPService - The HTTPService component can send HTTP GET, POST, HEAD, OPTIONS, PUT, TRACE, or DELETE requests. It does not support multipart requests.

  • RemoteObjects - The RemoteObject component uses Action Message Format (AMF) to transfer data that is a binary format and is the fastest of the RPC services. It is an ideal way to interact with server-side Java objects that are within the FDS server’s source path. It can also be used to connect to local or even remote ColdFusion servers. Both Java objects and ColdFusion components can be mapped to ActionScript objects, allowing for seamless integration between the server-side and client-side objects.

The WebService and HTTPService components are included for free with the Flex SDK, whereas the RemoteObject component is available only for use with the FDS server (Commercial or Free Express Edition) or ColdFusion 7.02.

Flex Charting

The Flex charting components are a set of rich charting components that enable easy development of professional dashboard and business intelligence (BI) systems. The charting components are sold as a stand-alone product or bundled with Flex Builder 2. A free trial of the charting components is available from Adobe. You can learn more about the charting components in Chapter 10.


Summary

This chapter defined RIA and gave some examples of the benefits of RIA, as well as the software options available for creating RIAs. It also provided an overview of Flex and its history, as well as the pieces that make up Flex. Most of the information on Flex covered in this chapter is covered in more depth later in this book.

Chapter 2 introduces the all-new Flex Builder 2 built on top of Eclipse.


Chapter 2: Introducing Flex Builder 2.0

Overview

One of the most significant pieces of the new Flex 2 product family is the all-new Flex Builder 2. The original Flex Builder was built on top of Dreamweaver, and, to put it bluntly, the community was not shy about letting Macromedia (now Adobe) know just how bad Flex Builder 1 actually was. Fortunately for the Flex development community, Macromedia acknowledged this, decided to scrap it completely, and started over using Eclipse as the base for Flex Builder 2.

Flex Builder 2 is light years ahead of the original, and most developers now use it as the tool of choice for doing Flex MXML and ActionScript development. Most modern systems will not have any problems running Flex Builder 2.

Following are the official requirements from Adobe for Flex Builder on Windows:

  • Intel Pentium 4 processor

  • Microsoft Windows XP with Service Pack 2, Windows XP Professional, Windows 2000 Server, Windows 2000 Pro, or Windows Server 2003

  • 512MB of RAM (1GB recommended)

  • 300MB of available hard-disk space

  • Java Virtual Machine: Sun JRE 1.4.2, Sun JRE 1.5, IBM JRE 1.4.2

Following are the official requirements for Mac (as of this writing, the Mac version is still in beta):

  • PowerPC or Mactel (1GHz or greater)

  • Mac OS X 10.4.7

  • 1GB of RAM recommended

  • 300MB of available hard-disk space

  • Java Virtual Machine: Sun JRE 1.5

  • Eclipse 3.2 (plugin configuration only)


Flex Builder 2.0 Eclipse Standalone and Plugin

Flex Builder 2 is available in two different distributions. The standalone version operates exactly the same as the plugin version, but is a lighter-weight application. The standalone version runs on top of a stripped-down version of Eclipse, which makes it a smaller install and a smaller memory footprint. However, for those who have already been using the full version of Eclipse for other development (such as Java, ColdFusion, and so on), Flex Builder comes as a plugin that installs into Eclipse, just like the many other Eclipse plugins. If you are using the Eclipse standalone version with a previous ActionScript plugin, it is recommended that you uninstall it before installing the Flex 2 plugin to avoid any conflicts with file associations.


Creating a Flex Project

To create a Flex project, simply choose New and then Flex Project from the File menu, as shown in Figure 2-1.

Image from book
Figure 2-1: Creating a new Flex project

Choose the way you want your application to access data and how it should be compiled, as shown in Figure 2-2. Selecting Basic will automatically compile your application each time you save a file within Flex Builder. If you choose Flex Data Services (FDS) as your method for accessing data, you also have the option to compile your application using the FDS server at run-time.

Image from book
Figure 2-2: Selecting the type of project

Next, as shown in Figure 2-3, enter a project name and either browse to a location or choose the default location for your project file storage.

Image from book
Figure 2-3: Defining the storage location of project files

Next, you will need to name the main file for your application. Figure 2-4 shows this step with the main application file being named Index.mxml. Note that you should not name the main file of your application the same as an existing component or a component you intend to build. This could create bizarre, non-verbose conflicts in the project.

Image from book
Figure 2-4: Naming the main application file

At this point, you can switch to the Library Path tab to add SWC libraries to your project. You can also choose to add SWC files to your project after it has been created. Choose either the Add SWC Folder or Add SWC button to add the library to the project (Figure 2-5).

Image from book
Figure 2-5: Adding a library during project creation

To add a library to an existing project, simply right-click the project name within the Navigator window and choose Properties. Next, select Flex Build Path and then choose the Library Path tab (Figure 2-5). Choose either the Add SWC Folder or Add SWC button to add the library to the project. For more information on SWC files, see Chapter 14.

Image from book
Figure 2-6: Adding a library to an existing project


Flex Builder Perspectives

Flex Builder has multiple perspectives. A perspective defines a set of editors and view panels that are useful to the task at hand. For example, Flex Builder will switch to a different perspective if you are debugging an application. Switching to a perspective will alter the views and editors that show within the Eclipse application. Switching perspectives will happen automatically in some situations. The default perspective is the Development perspective, and it includes a Source mode (Figure 2-7) and a Design mode. The other perspective is the Debugging perspective.

Image from book
Figure 2-7: The Development perspective in Source mode

The Development Perspective Source Mode

The Source mode is a basic code editor that will include code hints, code completion, syntax coloring, and real-time error reporting for both MXML and ActionScript code. Figure 2-8 shows the Development perspective with the Outline view of the Source mode enabled. The Outline view shows the hierarchy of your MXML code when editing an MXML file, or the properties and methods of your class files when editing an ActionScript class. Either way, you can go directly to a line of code by clicking the entry in the Outline views.

Image from book
Figure 2-8: Outline view of Development perspective in Source mode

The Development Perspective Design Mode

As shown in Figure 2-9, switching to the Design mode makes available two panels on the right-side screen: the States panel and Components panel. The Editor panel located in the middle of the screen changes to become a visual editor, allowing the drag-and-drop positioning of components, as well as drag-and-drop of components from the Components panel. The States panel allows you to create new states that can be designed visually as well. For more information on how to use states, see Chapter 8.

Image from book
Figure 2-9: The Development perspective in Design mode

Note that you cannot switch to Design mode when editing an ActionScript file. It is only available for editing MXML files.

Note that, by default, the Components panel appears in the same pane as the Outline view on the left of the screen, and the States and Properties appear on the right.

Another part of Design mode, the Properties view, has multiple sections, as well as the following property view options:

  • Standard property view options - There are three separate sections within the Standard view of the Properties view:

    • Common section - This allows for editing of the component properties, as shown in Figure 2-10.

      Image from book
      Figure 2-10: The Common section of the Properties view

    • Style section - As shown in Figure 2-11, this makes use of color selectors, sliders, combo boxes, and buttons to allow for easy editing of the selected component’s style properties. The changes are reflected in real time within the design editor.

      Image from book
      Figure 2-11: The Style section of the Properties view

    • Layout section - This is the area where you make changes to layout properties, including width and height when working in directional layouts. It also includes x, y, and the layout constraints when working within an absolute layout. Use the checkboxes within the constraint options section to anchor the selected component to one or more corners of the parent container. Figure 2-12 shows the Layout section with a component anchored to the bottom-right corner of the parent container. Any changes made will be reflected in the design editor in real time.

      Image from book
      Figure 2-12: The Layout section of the Properties view (note that the controls shown will not be available if the application is not using absolute layout)

  • Category property view options - The Category view shown in Figure 2-13 is a tree layout of the available properties. They can be edited by updating the text fields next to each property. Some of the text fields will include visual editors to make editing of colors and known property options easier.

    Image from book
    Figure 2-13: The Category view of the Properties view

  • Alphabetical property view options - As shown in Figure 2-14, the Alphabetical view includes all of the same properties shown in the Category view, but in a simple alphabetical list, rather than a tree layout.

    Image from book
    Figure 2-14: The Alphabetical view of the Properties view

To use the Properties view to make changes to your components, simply click a component within the design editor, which will update the Properties panel to show the options available for the selected component.

The Debugging Perspective

Switching to the Debugging perspective allows you to run the Flex debugger, set breakpoints, watch variables, and step through your code. To switch to the debugging perspective, simply choose Flex Debugging perspective from the perspectives menu at the top-right corner of the editor, as shown in Figure 2-15. The Flex Debugging perspective will not be available as shown in Figure 2-15, unless it has been opened at least once before. To show it for the first time, you must either click the Open Perspective button in the top right or navigate to Window Image from book Perspective Image from book Flex Debugging.

Image from book
Figure 2-15: Switching to Flex Debugging perspective

Debugging Your Application

Flex Builder 2 offers debugging capabilities that allow you to find bugs within your application. A debugger allows you to stop and start the application to find problems, or to examine or substitute values for variables. To debug your application, you must first switch your perspective to the Flex Debugging perspective using the buttons within the tabs at the top of the editor window, as shown earlier in Figure 2-15. Once you are in the Flex Debugging perspective, you can set breakpoints by right-clicking the line of code you wish to break on, and selecting Toggle Breakpoint from the context menu, as shown in Figure 2-16. You can also simply double-click the line of code to toggle on and off a breakpoint.

Image from book
Figure 2-16: Adding a breakpoint

Note that the Debugging perspective is automatically opened when a breakpoint is encountered, or when a run-time error is thrown.

The Debugging perspective also includes views to read, edit, and watch variables, manage breakpoints, and watch expressions. These include the Console view, the Variables view, the Breakpoints view, and the Expressions view.

Console View

The Console view displays any trace statements that are within your source code while your application is running within a debug session. This view will become one of your best friends while debugging your Flex applications. The Console view also displays run-time errors.

Variables View

The Variables view of the debugger allows you to easily copy, find, change, and watch your variables while debugging your application. To do so, simply right-click a variable name, and then use the context menu shown in Figure 2-17 to perform any of the aforementioned functions. Selecting Watch from the context menu will add the variable to the Expressions view (discussed shortly).

Image from book
Figure 2-17: Variables view of the Debugging perspective

The Variables view contains many icons and symbols that can be a bit confusing. The following table provides definitions for the various symbols.

Open table as spreadsheet
Symbols | Definition
Red Square | Defines a private variable
Green Circle | Defines a public variable
Yellow Diamond | Defines a protected variable
Blue Diamond | Defines an internal variable
Orange Box (Package) | Defines a variable scoped to a user-defined namespace

The following table provides definitions for the various icons.

Open table as spreadsheet
Icons | Definition
C icon | Defines a constant variable
D icon | Defines a dynamic variable
S icon | Defines a static variable
Getter Icon | Indicates that the variable has a getters

Breakpoints View

The Breakpoints view is an easy place to manage your breakpoints while in a debugging session. As shown in Figure 2-18, you can right-click a breakpoint and use the context menu to change the status, or to remove a breakpoint. You can also use the breakpoints toolbar for additional functionality, including jumping to the breakpoint within the source code, skipping all breakpoints, as well as expanding and collapsing the breakpoint tree.

Image from book
Figure 2-18: Breakpoints view of the Debugging perspective

Expressions View

Use the Expressions view to add and edit expressions on the variables you are watching. You can also choose to re-evaluate the expressions you are watching because the data may have changed as you proceeded through the debug session. As shown in Figure 2-19, you can right-click an expression and use the context menu.

Image from book
Figure 2-19: Expressions view of the Debugging perspective

Starting the Debugger

To run the debugger and start a debugging session, click the arrow next to the bug button on the toolbar, and then select the application you wish to debug. If the application is not listed, choose Debug As and select Flex Application, as shown in Figure 2-20.

Image from book
Figure 2-20: Running an application in debug mode

Chapter 19 provides more information on debugging.


Compiling Your Application

Flex Builder 2 will compile your application as you build it, unless you specifically tell it not to by unchecking Build Automatically in the Project menu. Each time you save a file, Flex Builder will compile the SWF file, as well as generate the wrapper files and supporting files for running, debugging, and history management. By default, these files are compiled to the bin directory within your project, although this can be changed within the Flex Build Path section of the project properties.


Running Your Application

To run your application, you must simply select the down arrow next to the green arrow button on the toolbar, and then select the application you wish to run from the list (Figure 2-21). If the application is not yet in the list, choose Run As and select Flex Application. To run the same application again, you can simply select the button with the green arrow.

Image from book
Figure 2-21: Running an application


Summary

This chapter discussed the all-new Flex Builder 2 IDE. After reading this chapter, you should be able to create a project, edit it in either Source or Design view, and then run the application. This chapter also examined the tools available to use Flex Builder to debug your Flex application.

Chapter 3 introduces the pieces that make up Flex. This includes the programming model, examples of MXML and ActionScript, the Flex class library, charting components, data services, and messaging services.


Chapter 3: Flex 2.0 Basics

The first two chapters of this book introduced you to the Flex 2 product line and the concepts of Rich Internet Applications (RIA). This chapter explains how to build a Flex 2 application using the Application Model. First, before you build anything, you are introduced to the XML markup language (MXML) and ActionScript.

The following section, “Flex 2 Programming Model,” explains what the different elements are when developing your applications. The elements described are MXML, ActionScript, and the Flex 2 Framework.

Flex 2 Programming Model

The Flex 2 Programming Model consists of MXML, ActionScript, and the Flex class library. To build a full-fledged application, you must have a good knowledge of all these technologies. To start off, you are introduced to the basics of MXML. Then you are shown how ActionScript and MXML work together to create powerful, rich user interfaces.

The third element of the programming model is the Flex 2 Framework, which contains Flex components, managers, and behaviors. This component-based development model allows developers to incorporate pre-built components, extend the component library by creating new components, or combine pre-built components to create composite components.

MXML

The first element of the programming model, MXML, is an XML language that defines the user interface for an application. MXML is also used to define non-visual aspects such as server-side data sources and bindings between the user interface and the server side.

To write a Flex application, you must be able to write MXML and ActionScript. As mentioned earlier, MXML is an XML language that is used to lay out your user interface.

MXML is very similar to HTML in that it provides tags for user interface elements. If you have worked with HTML, then MXML should be very familiar to you. MXML has a much broader tag set than HTML, and defines visual components such as data grids, buttons, combo boxes, trees, tab navigators, and menus, as well as non-visual components, Web service connections, data binding, and effects.

The biggest difference between HTML and MXML is the MXML-defined file that is compiled into a Shockwave file (SWF) and rendered by the Flash Player. MXML can be written in a single file or in multiple files. MXML requires that you close off every tag that you declare in your Flex application. Otherwise, the Flex compiler will throw an error.

Example Application Using MXML

One of the great things about MXML is that it can be written in a wide range of integrated development environments (IDEs) that support text editing because it’s a plain XML file.

The following example shows the mandatory "Hello World" application. It consists of an <mx:Application> tag and two children, the <mx:Panel> and <mx:Label> tag.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >

    <mx:Panel title="Example Application using MXML">

        <mx:Label text="Hello World!" fontWeight="bold" fontSize="30" />

    </mx:Panel>
</mx:Application>

The <mx:Application> tag is always the root tag of a Flex application. The <mx:Panel> tag defines a Panel container that includes a title, title bar, status message, border, and an area for its children (that is, the <mx:Label> control). The <mx:Label> tag is a Label control that simply displays text.

Figure 3-1 shows the "Hello World" application rendered in the Flash Player.

Image from book
Figure 3-1: "Hello World" application rendered in the Flash Player

ActionScript

The second element of the programming model, ActionScript, extends the functionality of a Flex application. ActionScript provides control and object-manipulation features that are not available in strict MXML.

The ActionScript programming language is used in Adobe’s Flash Player. Included are built-in objects and functions that allow you to create your own objects and functions like many object-oriented programming (OOP) languages.

ActionScript 3.0 offers a robust programming model that is more familiar to developers with basic knowledge of OOP. ActionScript is executed by the ActionScript Virtual Machine (AVM), which is part of the Flash Player. The code is compiled into a bytecode format by the compiler, such as the one built into Flex Builder 2.

ActionScript and JavaScript are very similar, so being familiar with JavaScript will make your life easier when using ActionScript. JavaScript is derived from The European Computers Manufacturers Association (ECMA) document ECMA-262, which is the international standard for the JavaScript language. ActionScript is based upon the ECMA-262 Edition 4 specification, so this is where the similarities come in between the two languages.

ActionScript 3.0 contains a lot of new features, such as run-time exceptions, run-time types, sealed classes, method closures, ECMAScript for XML (E4X), regular expressions, namespaces, and new primitive types. All these new features allow the developer to speed up the development process.

One important point to note is that Flex Builder 2 converts all MXML files into ActionScript before the code is compiled into bytecode for use with the AVM.

ActionScript in MXML

Flex developers will find that ActionScript extends the capabilities of Flex when developing applications. In ActionScript, you can define event listeners, create new classes, handle callback functions, and define getters and setters, packages, and components.

Following are some of the ways that ActionScript can be used in Flex applications:

  • ActionScript is inserted between the <mx:Script> tags. This code can be comprised of new functions, error handling, or events, and can perform any other tasks your Flex application may require.

  • Create new components in ActionScript.

  • Create new components and compile into SWC files (which are external components compiled to be reused in many applications).

  • Extend existing components with ActionScript classes.

  • Take advantage of ActionScript support for OOP concepts such as code reuse, inheritance, encapsulation, and polymorphism.

  • Use global ActionScript functions that are available in any part of an SWF file where ActionScript is used, or in any user-defined class.

  • Use the standard Flex components that comprise the Flex Class Libraries. All the components and libraries are written in ActionScript.

Overview of ActionScript Compilation Process

A Flex application can consist of MXML files, ActionScript classes, SWF files, and SWC files.

The Flex compiler transforms the main MXML file and its children into a single ActionScript class linking in all the reference-imported classes. Once the transformation is complete, the end result is a single SWF file that can be deployed on the server.

Every time you make changes to your application, a new SWF file is generated. You may find it more convenient to remove the reusable components and compile those into SWC files, which can be included in a library path for your application.

ActionScript Code in MXML

ActionScript code is only allowed to be declared in between the following tag in MXML files:

<mx:Script>
    <![CDATA[
        ...
    ]]>
</mx:Script>

Statements and expressions must be wrapped in functions; otherwise, you will receive a compiler error. Also, you cannot define classes or interfaces in the <mx:Script> tag, because the MXML file you have defined is a class in itself.

You may have noticed the odd CDATA construct. This is used to tell the compiler not to interpret the script block as XML, but rather as ActionScript. The <mx:Script> tag must be located at the top-level component tag of the MXML file. Multiple <mx:Script> tags can be defined, but for readability, it’s recommended to have them in one location.

The following example shows ActionScript being defined in an MXML file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               public var s:String;

               public function foo():void
               {
                    s = "Hello World!";
               }

          ]]>
     </mx:Script>

</mx:Application>

In MXML, you can use ActionScript to refer to visual or non-visual components. You do this by specifying the id property of the component in MXML. Then you use id to refer to the component in ActionScript.

The following example shows how this is achieved:

<mx:Panel title="Example Application using MXML" width="300" height="200">

          <mx:Label id="lbl1" text="Hello World!" fontWeight="bold" fontSize="30" />

</mx:Panel>

If you want to access the <mx:Label> control, you must refer to the id property in ActionScript. To do this, the following code must be used:

var str:String = lbl1.text;

The code gets the value from the Label control named lbl1.

Import and Include

There is a noticeable difference between the terms “importing” and “including” in reference to ActionScript. Importing is adding a reference to a class file or package so that you can access the objects and properties of the external classes, as shown in the following example:

import mx.controls.TextInput;

Including ActionScript is copying the lines of code of an external ActionScript file into another. This can either be done in the <mx:Script> tag using the include directive, or the <mx:Script source="filename"> tag to add the ActionScript into your Flex applications.

The following example is using the include directive within the <mx:Script> tag:

<mx:Script>
    <![CDATA[
        include "filename.as";
    ]]>
</mx:Script>

Introduction to ActionScript Components

This section provides a brief overview of how to create reusable components using ActionScript. Later in this book, you will build more complex components using MXML and ActionScript.

Custom components can contain graphical elements, define some kind of business logic, or extend existing components in the Flex framework. Defining your own components in ActionScript has several advantages:

  • Divide your application into individual models that can be developed and maintained separately.

  • Implement commonly used logic within the components.

  • Build a collection of components that can be reused among all your Flex applications.

When creating custom components, you may find it useful to extend the component from the Flex class hierarchy. This allows you to inherit functionality already built into the Flex components.

As shown in the following example, you can define a custom TextInput and derive it from the Flex TextInput control:

package myComponents
{
    public class MyTextInput extends TextInput
    {
        public function MyTextInput()
        {
            ...
        }
        ...
    }
}

The filename of the control MyTextInput must be in a filename called MyTextInput.as and stored at the root of your Flex application in a subdirectory name myComponents. As you may have already picked up, the package name reflects the location of the component, myComponents.

To use the custom component in your Flex application, you will need to write the following MXML:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:components="myComponents.*" >

    <components:MyTextInput label="Adobe Flex 2"/>

</mx:Application>

The code xmlns:components="myComponents.*" defines a namespace called components that points to the subdirectory myComponents. You can then reference the component as an MXML tag using the namespace prefix.

Flex Class Library

The Flex 2 Framework contains Flex managers, components, and behaviors. The component-based model allows developers to incorporate pre-built components, create new ones, or combine components into composite components.

Later in this book, you are introduced to more of the Flex 2 Framework.

The following lists some of the common packages that you will use in your Flex application:

  • mx.controls - Flex user interface controls

  • mx.collections - Flex collection components

  • mx.charts - Flex charting components

  • mx.utils - Flex utility classes

  • flash.events - Flex event classes

  • flash.net - Flex classes for sending and receiving from the network, such as URL downloading and Flash Remoting

There are many more packages in the Flex Framework, and listing them would be out of the scope of this chapter.


Flex Charting Components

The visual aspect that Flex charting offers over a simple table of numeric data is much easier for your Flex application users to comprehend. The Flex charting components are not included in the free Flex 2 SDK, and must be downloaded separately to use them inside your Flex application.

Charting Types

Charts come in many different types, including the following:

  • Area charts - The AreaChart control is used to represent data that emphasizes a change in values by filling in the portion of the graph beneath the line connecting various data points. The chart allows for an icon or symbol to represent each data point along the line or a simple line without any icons or symbols. These custom symbols are part of the built-in data series renderer functionality, which you learn about in future chapters.

  • Bar charts - The BarChart control is used to represent data across categories, and is ideal for showing the variations in the value of an item over time, or for showing the values of several items at a single point in time. It is essentially a column chart rotated 90 degrees to the right.

  • Column charts - The ColumnChart control is used to represent data using vertical bars (called columns) to display different values of one or more items. They are used to compare values across categories. They are ideal for showing the variations in the value of an item over time.

  • Bubble charts - The BubbleChart control is used to represent data with three values for each data point. A bubble chart is a type of xy (scatter) chart. The first of the three values determines the position along the x-axis, the second value determines the position along the y-axis, and the third value determines the size of the bubble symbol.

  • Candlestick charts - The CandlestickChart control is used to represent data that contains open, high, low, and close values for each time period you want to display. The hollow or filled portions of the candlestick are called the body. The long thin lines above and below the body represent the high/low range and are called shadows. The high is marked by the top of the upper shadow, and the low by the bottom of the lower shadow.

  • Line charts - The LineChart control is used to represent data over time or categories as a series of points using coordinates. Icons and symbols can be used at each data point along the line with visual markers.

  • Pie charts - The PieChart control shows the size of items that make up a data series proportional to the sum of the items. It always shows only one data series, and is useful when you want to emphasize a significant element in the data.

  • Plot charts - The PlotChart control is used to represent data in Cartesian coordinates with one data point being along the x-axis and the other data point along the y-axis.

  • HighLowOpenClose (HLOC) charts - The HLOCChart control is most often used to represent data for stock prices, but can also be used for scientific data (for example, to indicate temperature changes). The HLOCChart control does not require the data point that represents the opening value.

Chapter 10 provides more detail about the charting capabilities of Flex.


Flex Data Services

Flex Data Services (FDS for short) allows developers to build applications deployed on standard Java 2 Enterprise Edition (J2EE) servers. FDS provides connectivity with existing server-side data and business logic to create powerful business applications. FDS offers many great features, including the following:

  • A robust messaging architecture that provides services that automatically synchronize data between client and server

  • Real-time data push and publish-subscribe messaging

  • Collaborative and disconnected applications

When developing an application, some consideration must be taken regarding how your data will flow from the client to the server and vice versa. FDS could be a viable option if you need the following features.

Data Management Service

Developing RIAs requires more powerful data management compared to the traditional request/response model. Creating a richer and more powerful experience will require data-intensive applications, and with this, new challenges arise. This is where data management services make things simple when working with distributed data.

Data Management Service adds functionality to provide data synchronization, data replication, and occasionally disconnected application services.

Data Synchronization

This process is managed by FDS, and it removes the complexity and room for error by providing a high-performance data synchronization engine between client and server. Existing solutions can be integrated with data synchronization to provide an end-to-end solution.

Data Paging

FDS takes care of paging large datasets, which allows you to focus your knowledge on application business logic instead of worrying about basic data management.

Messaging Service

The Flex Messaging Service is comprised of the basic messaging functionality in the form of publish-subscribe API for Flex applications. This allows Flex and Flash clients to use publish-subscribe messaging to integrate with back ends that use Java Messaging Service (JMS) systems.

Messages are sent asynchronously by passing packets of data (called messages) to and from a message service. A message is usually comprised of a header and a body, where the header contains the routing information and the body contains the application data.

In the jargon of the world of messaging, an application that sends messages is called a producer and an application that receives messages is called a consumer. The producer and consumer need not know anything about each other, because the producer sends messages to a messaging destination and the messaging service routes it to the appropriate consumers.

Figure 3-2 shows the flow of data from message producer to message consumer.

Image from book
Figure 3-2: Flow of data from message producer to message consumer

Publish-Subscribe Messaging

Publish-subscribe messaging has been around for a while, and works asynchronously. The way it works is a producer creates a message and sends it to some predetermined destination. At the same time, a consumer attaches itself to the destination and listens for the sent messages. Producers and consumers (also known as message agents) collaborate by exchanging messages through a common gateway (which is the destination).

Examples of applications that would benefit from the use of publish-subscribe messaging are stock trading services, inventory control, visualization tools, and any application that requires messages to be sent to multiple subscribers.

Figure 3-3 shows a simple publish-subscribe message flow.

Image from book
Figure 3-3: Publish-subscribe message flow

Data Push

In FDS, you can push data changes from the server to the client without polling the server. This is robust and highly scalable to allow pushing of data to thousands of concurrent users.

RPC Services

You can develop a Remote Procedure Call (RPC) application without the use of FDS by using either HTTP services or Web services, and no server-side proxy service. To get the RPC service to work, it should either be in the same domain as the server hosting your application, or have a crossdomain.xml file on the remote server hosting your RPC service.

FDS RPC functionality allows you to develop enterprise functionality into your applications, including servicing data from different domains, a white list of permitted RPC services, server-side logging, localization support, and client authentication. The RemoteObject component is used to access remote Java objects using Action Message Format (AMF), without exposing them as compliant Web services.

FDS Alternatives

As of this writing, a company called Midnight Coders has an alternative solution to FDS called WebORB. It is a platform enabling development, deployment, and run-time execution of RIAs. The product allows connectivity between rich clients created with Flex, Flash, and Ajax, as well as server-side applications developed with .NET, Java, Ruby on Rails, and PHP. Most of these products will have an implementation of FDS in their commercial editions.


Summary

This chapter is just an overview of what’s to come in the world of Rich Internet Applications using Adobe Flex 2. Some of these topics may be a little over your head, such as the Flex Data Services, but you will quickly learn to integrate these technologies into your applications.

Chapter 4, “Using Flex Builder,” is where all the fun starts. Flex Builder is something you will need to get familiar with quickly to enter the world of RIA development.


Chapter 4: Using Flex Builder 2.0

Learning how to use the full potential of the Adobe Flex Builder 2 makes developing Flex applications easier and quite enjoyable. In the end, every application consists of text files, MXML, and ActionScript, which are compiled into a binary SWF file. The Flex Builder is the tool to help organize, visualize, create, and run commands on the application code.

This chapter teaches you how to learn more about the Flex Builder from within the Flex Builder. It covers basic layout and workbench areas, as well as how to customize the workbench experience. Finally, you learn about Flex Builder’s ability to build applications with both the Design and Source views.

Getting Started with Flex Builder

The Flex Builder is a fully integrated development environment (IDE). It provides tools to assist you in creating, debugging, packaging, and compiling code into SWF applications. Following are the included feature sets:

  • Text editor - Flex Builder 2 provides separate editors for MXML, ActionScript, and CSS code. You do not need to keep track of which editor is for which file type. This is because the Flex Builder automatically handles it for you. The editors also provide features that are discussed in this chapter, including code hinting, navigation, formatting, commenting, and others.

  • Design editor - The Design view editor is specific to the MXML editor. It provides a collection of views to help create components and applications visually by placing user-interface and data-access controls on the design mode stage.

  • Navigation features - The Navigator and the Outline views provide the ability to navigate not only projects, but also components. Flex Builder also provides the functionality to open code through definition links and view editors with line numbers to help locate specific code.

  • Build tools - The mxmlc compiler does all compiling of the applications, but what Flex Builder does is provide the ability to manage the process. You can configure projects to build automatically as you write code and save the file, or be built manually. Configuration settings are also set per project to give you full control of the compilation and deployment process.

  • Integrated debugger - Flex Builder integrates the mxmlc compile-time errors with the Console view for easy access to error locations. Run-time debugging is handled through the Flex Debugging perspective and the associated Console, Debug, Variables, Breakpoints, and Expressions views.

  • Integrated Adobe Flex 2 Help - The Flex Builder help system provides eight main categories, from how Flex works to the Flex 2 language reference. It also provides a list of links to other online Flex resources. The Dynamic Help view provides in real time contextual help as you write your code. Another help item is the Key Assist popup list, containing a quick view to all the shortcuts.

  • Eclipse plugins and third-party tools - Eclipse provides a plugin architecture embraced by the community with many well-done projects to support other development requirements. Most common are development and version control plugins such as Ant, Tomcat, CVS, Subversion, and ColdFusion. Along with the plugin architecture, Eclipse allows you to configure external tools from within the Flex Builder.

If you have built applications with other comparable development environments, you will find that the Flex Builder and Eclipse platform provides extensive capabilities.

Tip

Flex Builder 2 comes in two installation options. The first is the stand-alone Flex Builder with the prepackaged Eclipse environment included. The second option is to install Flex Builder as an Eclipse plugin into an existing Eclipse installation. Although this chapter uses the stand-alone Flex Builder in its examples, the information is still pertinent to the plugin edition as well.

When installing the Flex Builder Eclipse plugin into an installation with other ActionScript or MXML plugins, you must resolve editor conflicts through the Eclipse preferences window.

Learning Flex Builder

One of the most overlooked places to start learning about Flex Builder is the Flex Start Page. If you are like most developers, you probably vaguely remember seeing it the first time you opened up Flex Builder. Do not worry if you did skipped over it; you can bring the Flex Start Page back up by selecting Help Image from book Flex Start Page. The result is shown in Figure 4-1.

Image from book
Figure 4-1: Flex Start Page

The next step to finding extensive information on Adobe Flex 2 and related technologies is Flex Help itself. Figure 4-2 shows the Flex Builder Help system, which opens as a separate application outside of Eclipse when you select Help Image from book Help Contents from the Flex Builder menu system.

Image from book
Figure 4-2: Flex Help application

Figure 4-2 also shows the name of the eight main titles in the Flex Help library. The library is quite extensive, and many times you’ll want to narrow your search to specific sections of the library. You do this by clicking the blue “Search scope” link found on the top middle area of Figure 4-2. The search mechanism uses groups of topics as named search lists that can be selected as the current search scope. Figure 4-3 shows the two dialog windows used to create and select a search list for just the “Using Flex Builder 2” section of the Flex library.

Image from book
Figure 4-3: Dialog windows used to create and select a search list

The selection of scope will now filter all search results to only pull information from the “Using Flex Builder 2” help section. The search scope not only affects the external help system, but also affects the Help view search mode available inside Flex Builder. You can see that in Figure 4-4, which demonstrates a search result on the term “debugging.” The search returns the same filtered results as the Help view search mode shown in Figure 4-5.

Image from book
Figure 4-4: Search result on the term “debugging”
Image from book
Figure 4-5: Help view search mode

The ability to use the external help application or the internal Help view search mode demonstrates the flexibility of Flex Builder’s options. One of the nice help features is called Dynamic Help. It uses the same help view area as the Help view search mode. Open the Dynamic Help view, shown in Figure 4-6, by selecting Help Image from book Dynamic Help.

Image from book
Figure 4-6: Dynamic Help view

The Dynamic Help works as you select or move the editor cursor over key words. The Dynamic Help view shown in Figure 4-6 displays the reference link to mx.logging.Log in connection to the Log class in CustomLoggerMain.mxml source editor being highlighted.

The Go To section in Figures 4-5 and 4-6 is another way to switch between the different modes of the Help view. Related Topics is another definition given to the Dynamic Help view mode. The bookmarks option displays a list of bookmarked help pages. You bookmark the current help page by clicking the Bookmark Document icon located in the top-right section of the help page.

There it is - the power to pull information from the Flex library as you continue learning about Flex Builder from within the Flex Builder itself.

Flex Builder Workbench Basics

The Flex Builder workbench is made up of perspectives, editors, and views. The following table provides definitions to better explain the basics of the Flex Builder workbench and other related topics.

Open table as spreadsheet
Term | Definition
Perspective | A group of views and editors in a workbench.
Editor | Specific functionality to edit files of specific types.
View | Container for functionality, also as known as panels.
Workspace | Defines an area of the file system that contains project resources.

Perspectives, Editors, and Views

The grouping of views and editors related to what current development actions are taking place are organized in perspectives. Adobe Flex Builder 2 provides two default perspectives: one for development and one for debugging. Flex Builder provides hooks into the IDE to change perspectives automatically, depending on the task at hand. For example, when you create a new project and are not presently in the Flex Development perspective, a prompt will ask if you would like to switch perspectives, as shown in Figure 4-7.

Image from book
Figure 4-7: Prompt asking if you would like to switch perspectives

The Flex Development perspective includes two modes that are dependent on the MXML editor. The first mode is Source mode, which also defines the layout for the perspective when an ActionScript or CSS editor is in use. The MXML editor in Design mode is the second mode of the Flex Development perspective.

The following table shows the default development view configuration, as well as which Flex Development perspective mode the view appears in.

Tip

The specific list of views in each perspective described here defines the default configuration layout. You can customize any perspective for your specific development environment needs. Chapter 2 introduces the basic views and provides figures for most of the views discussed here.
Open table as spreadsheet
View Name | Group | Typical Layout Area
Navigator | Source/Design | Left Side
Outline | Source/Design | Left Side
Editor | Source/Design | Middle
Problems | Source/Design | Bottom
Components | Design | Left Side
States | Design | Right-Top
Properties | Design | Right-Bottom

The following table shows the default debugging view configuration, as well as which Flex Development perspective mode the view appears in.

Open table as spreadsheet
View Name | Group | Typical Layout Area
Navigator | Debugging | Left Side
Debug | Debugging | Middle-Top
Editor | Debugging | Middle
Variables | Debugging | Right-Top
Breakpoints | Debugging | Right-Top
Expressions | Debugging | Right-Top
Console | Debugging | Bottom

The following table shows the default optional views, as well as what groups and which Flex Development perspective mode the view appears in.

Open table as spreadsheet
View Name | Group | Typical Layout Area
Search | Any | Bottom
Console | Any | Bottom
Tasks | Any | Bottom

To open any view in the current perspective, select Window Image from book Other Views…, and a popup of all the available views will open. Figure 4-8 shows the dialog window that pop ups upon selecting the Other Views menu item.

Image from book
Figure 4-8: Dialog window that pop ups when selecting other views

Later in this chapter, you learn how to navigate and customize the views in the Flex Builder workbench.

Workspace

Workspaces are larger than perspectives, and allow you to organize resource and configuration groupings on the same machine. Each workspace must have a separate location on the file system. The process of creating new workspaces and retrieving old ones is called switching workspaces. You will find the menu item under File Image from book Switch Workspace…, as shown in Figure 4-9.

Image from book
Figure 4-9: Switching workspaces

Figure 4-10 shows the workspace switch dialog box. To select a new workspace you can browse or type in a new location on the file system.

Image from book
Figure 4-10: Workspace switch dialog box

Switching to different workspaces makes sense if you work in different environments with many clients or separate projects. For example, an author of a book can create a workspace specific for the example projects needed to be published, but also keep a workspace for other clients or personal projects. Each workspace will reference different projects and can configure the layout of perspectives and views differently. If you have used other Adobe products, such as Flash 8 Professional or Dreamweaver, workspaces work similarly to the workspace layout feature found in those products.


Flex Builder Basics

With the workbench and the basic parts explained in the previous sections, let’s examine how to use the workbench. The project is the most basic organizational unit used by the Flex Builder workbench. Managing and navigating the project and its resources make up a big part of a developer’s daily tasks.

Working with Projects

There are three project types defined by the Flex Builder: Flex Project, ActionScript Project, and Flex Library Project. Figure 4-11 shows the three Flex Builder project types, along with the some other Eclipse basic projects.

Image from book
Figure 4-11: Three Flex Builder project types

The icons next to the specific project wizard found in Figure 4-11 also show up in other places of the workbench, in particular the Navigator view. New projects can be created a few different ways:

  • You can select a wizard by right-clicking in the Navigator view and selecting New Image from book Project..., or from the main menu’s File Image from book New Image from book Other….

  • You can choose a specific project wizard type straight from the main menu by selecting File Image from book New Image from book <specific type>, or from the context menu in the Navigator view New Image from book <specific type>. The specific type options are Flex Project, ActionScript Project, or Flex Library Project.

  • You can import a previous project by selecting from the main menu File Image from book Import…, or by selecting Import… from the context menu in the Navigator view. This method is not covered in the book, but is noted here for reference.

Each project type has a specific wizard for creating a project. The wizard for creating a new Flex project walks you through the application data access setup, project file location, and the build path setup dialog windows. In particular, Figures 2-2 through 2-6 in Chapter 2 show the wizard dialog windows for creating a new Flex Project.

The ActionScript Project is used for creating applications with ActionScript code that does not use any of the Flex Framework. The DrawCircles.as class introduced in the next section, “Multiple Applications,” is an example of an ActionScript application. The DrawCircles.as code is defined in Listing 4-1 later in this chapter. The non-Flex Framework application only needs to extend the Sprite class, and can be run just like a typical Flex application.

Listing 4-1: DrawCircles.as
Image from book

package {
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;

    public class DrawCircles extends Sprite {
        private var childCount:int = 0;
        public function DrawCircles() {
         stage.scaleMode = StageScaleMode.NO_SCALE;
         stage.align = StageAlign.TOP_LEFT;
            doDrawCircle( 0x336699 );
            doDrawCircle( 0x993333 );
            doDrawCircle( 0x339933 );
        }

        private function doDrawCircle( color:uint ):void {
            var child:Shape = new Shape();
            child.graphics.beginFill( color );
            child.graphics.lineStyle( 2, 0xCCCCCC );
            child.graphics.drawCircle( 30, 40, 30);
            child.graphics.endFill();
            child.x = (childCount * 65) + 10;
            child.y = 0;
            addChild(child);
            childCount++;
        }
    }
}
Image from book

The Flex Library Project is covered in the “Compiling Components with Flex Builder” section of Chapter 14.

After creating the project, there are few things to learn about how to add and manage resources within the project. Projects can have multiple applications, link to external resources, be built automatically or manually, and publish source code.

Multiple Applications

When you create a project, it creates a default MXML application file. There a multiple ways to add more applications to a project.

Tip

The default MXML application file receives the same name as the project, unless the project name contains spaces or special characters. If the latter is the case, the filename is defaulted to main.mxml.

Create a Flex Project with basic data access called Chapter4. You should see a Chapter4.mxml file as shown in Figure 4-12.

Image from book
Figure 4-12: Chapter4.mxml file

The following steps outline the first of two methods on how to add multiple applications to the project:

  1. Create a new MXML application by selecting Flex Image from book New Image from book MXML Application, or by selecting New Image from book MXML Application from the right-click context menu from the Navigator view.

  2. Type MyApp into the filename input box located on the New MXML Application dialog window shown in Figure 4-13.

    Image from book
    Figure 4-13: New MXML Application dialog window

The first approach is quite simple, and creates the MXML application file for you, as well as assigning the application to the project. The green sideways triangle located over the top-left area of the MXML file icon indicates the file is a runnable application for the project, as shown in Figure 4-14. The blue circle over the bottom-right area of the MXML file icon indicates which application is the default runnable application.

Image from book
Figure 4-14: Sideways triangle located over the top-left area of the MXML file icon

The following steps outline the second approach to add an application to the project:

  1. Create a new MXML or ActionScript file. For example, select File Image from book New Image from book File.

  2. Name the file DrawCircles.as.

  3. Open the DrawCircles.as file and add the source code shown in Listing 4-1 to the file.

  4. Right-click the DrawCircles.as file and select Set as Default Application. Or you can right-click the Chapter4 project name and select Properties.

    Tip

    Note that the Set as Default Application menu item is disabled for ActionScript files in non-ActionScript typed projects in Flex Builder 2.0.1. You must change the nature of the project or create a new project of ActionScript project nature. Or you could manually set the default application through the project’s Properties window.

  5. Select Flex Applications, as shown in Figure 4-15.

    Image from book
    Figure 4-15: Selecting Flex applications

  6. Click the Add… button and select the DrawCircles.as file, as shown in Figure 4-16.

    Image from book
    Figure 4-16: Selecting the DrawCircles.as file

  7. Click OK and go back to the workbench.

Now, DrawCircles.as will have an icon indicator showing that it is a runnable application. Click the DrawCircles.as file and run the application. The DrawCircles application is shown in Figure 4-17.

Image from book
Figure 4-17: Running the DrawCircles application

You can now add MXML or ActionScript applications to any project you want to and know how to run it.

Tip

A lot of the examples in the Flex language reference documentation are ActionScript applications, just like DrawCircles.as. Therefore, it’s important to understand how to run ActionScript applications.

Linking External Resources

A linked folder on the file system links external resources in a project. Select File Image from book New Image from book Folder to activate the New Folder Wizard. Name the folder myPictures, click the Advanced Image from book button, and check the “Link to folder in the file system” checkbox, as shown in Figure 4-18.

Image from book
Figure 4-18: New Folder Wizard

Click the Finish button and a folder pointing to the My Pictures folder is created in the project. This can be used for quick access to other resources from within the Flex Builder to save the developer from using an operating system file explorer application.

Building Applications Automatically and Manually

To set a project to build automatically, first click inside the Navigator view on the project name or a file in the project. Then, select Project Image from book Build Automatically.

There are situations where manually building is warranted (for example, when you want the build script to run unit tests, move files, or manipulate other resources outside the Flex compiler). The most common methods of doing advanced manual builds use Apache Ant, which is out of the scope of this book.

An important feature for any build process is the Clean command. To clean a project, select Project Image from book Clean… with the project you want cleaned selected in the Navigator view. The Clean command forces the build scripts to delete all cache and output files, and then compile all source files from scratch. This single feature can resolve a lot of build project compile issues, especially if you are changing large chunks of files within a project.

Publishing Source

The project feature makes it easy to publish the source of your application. Figure 4-19 shows the wizard that opens by selecting Project Image from book Publish Application Source… from the main menu system.

Image from book
Figure 4-19: Publish Application Source Wizard
Tip

This feature works only for Flex applications. ActionScript applications will not have the View Source menu option on the right-click context menu.

Running this feature inserts a value into the viewSourceURL property of the default MXML application tag. To access the published source, run the application and select the View Source context menu item when you right-click the SWF. Figure 4-20 shows what the generated publish source application looks like.

Image from book
Figure 4-20: Generated publish source application

Running Applications

After building your applications, you can run or debug them a couple of different ways from within Flex Builder. The content covered in this section does not discuss debugging, but many of the launch configuration options apply to debugging as well. In-depth information about debugging applications is covered in Chapter 19. The simplest method of running an application is by pressing the green Run button, or by selecting Run Image from book Run <ProjectName>.

Applications can be configured to be run through a browser, or through the stand-alone player. The configuration option for running or debugging applications is called the launch configuration. Figure 4-21 shows the toolbar icon that allows you to open a specific application’s launch configuration for any applications in the currently selected project in the Navigator view.

Image from book
Figure 4-21: Opening the launch configuration

The Create, Manage, and Run Configurations dialog box provides three tabs with configuration options: Main, Source, and Common. To configure an application to run in a stand-alone Flash Player, uncheck the “Use defaults” checkbox in the Main tab. Then select the Run (or Debug) browse button, and select the application SWF file instead of the default HTML file, as shown in Figure 4-22.

Image from book
Figure 4-22: Main tab of the Create, Manage, and Run Configurations dialog box

Clicking the Run command launches the application in the stand-alone Flash Player. Other standard preferences located in the Windows Image from book Preferences Image from book Web Browser allow for the default browser used to run the application to be changed.

Navigating and Customizing the Flex Builder Workbench

Customizing the workbench to your specific development needs revolves around the understanding of the topics from previous chapters. To change perspectives, you can click the perspective-specific button, or select the perspective from the drop-down list, as shown in Figure 4-23.

Image from book
Figure 4-23: Changing perspectives

Also shown in Figure 4-23 is the ability to select the Other… option that allows adding other perspectives to the perspective toolbar. To create a new perspective, select the Window Image from book Perspective Image from book Save Perspective As… menu item. A dialog box will appear, where you fill in the new perspective name and click OK.

Tip

The steps to delete a Flex Builder perspective are to go to Windows Image from book Preferences Image from book Perspectives, select the perspective, and click the Delete button.

The current state of each view is saved for the current perspective automatically. There are a couple options to customize the layout of your views in a perspective. Each view can be minimized, restored, and maximized.

Tip

A quick way to maximize and minimize views or editors is to double-click the view/editor tab containing the name of the specific workbench item.

To move or dock a workbench item, view, or editor, click the tab area with the name and drag it to the new location. As you drag the workbench item over potential areas, a dotted line will appear, indicating the potential layout placement. If you want a particular view to live outside the Flex Builder’s layout constraints, you can right-click the view and toggle the Detached menu item. Detaching the view from Flex Builder then opens up a new window, which is not the layout constraint for the view. You can dock workbench items on the left, right, top, bottom, in layers, tiled, or many other ways. Figure 4-24 shows views and editors in various docking positions.

Image from book
Figure 4-24: Views and editors in various docking positions

A special layout feature in Flex Builder is called fast views. You can drag any view down into the fast view’s default lower left-hand corner location. The fast view places the view’s icon into a toolbar-like container, allowing for toggle-style visible views. The fast view toolbar can also be customized to be docked on the left, bottom, or right side of the Flex Builder.

Moving around the workbench can be greatly enhanced by learning more about the common keyboard shortcuts. You can view a quick list of the available shortcuts by selecting the Help Image from book Key Assist… menu item. All actions in the Flex Builder can be assigned new keyboard shortcuts through the Windows Image from book Preferences Image from book Keys configuration tabs.

Moving around the code files is a very common task when using the Flex Builder. There a few good methods that help developers move around the files efficiently.

The first is the open definition feature. To use this feature, click any property or object in a code file and press F3. For example, open up the DrawCircles.as file and select the doDrawCircle method on line 13, and press F3. The open definition action takes you to the declaration point of doDrawCircle. This works on methods, properties, and classes, including Flex Framework source files found in the Flex 2 SDK installation folder.

The outline view is a very powerful tool to very quickly move around a class structurally. The outline view provides a tree structure of the class and its elements. By clicking a node in the outline tree, the editor updates to the correlating line in the code.

The Navigation view has a specific feature called working sets, which can be defined to contain different resource items across projects. The set of commands to create, edit, and select working sets is found in the Menu icon on the Navigation view toolbar.

The last navigation feature discussed here is the search functionality in the Flex Builder. To bring up the global search functionality, select the Edit Image from book Find in Files… menu item. The action will open a dialog box, shown in Figure 4-25, providing a search input box, filename filtering, and scope settings.

Image from book
Figure 4-25: Search dialog box


Developing with Design Mode

Flex Builder’s Design mode and supporting views provide the features to create applications visually. The Flex Framework visual components contain the following characteristics:

  • Size

  • Events

  • Styles

  • Behaviors

  • Skins

The Design mode’s development workflow capabilities relate directly to manipulating the visual component’s characteristics. This is demonstrated in the following sections.

Building a Flex User Interface

Follow these steps to create a basic application using Components view and Flex Properties view:

  1. Open the Chapter4.mxml file located in the Chapter4 project.

  2. Click the Design mode button.

  3. Drag a Label control from the Components view onto the stage area.

  4. Click the Label instance and then, in the Flex Properties view, change the following properties:

    • ID - txtTitle

    • Text - Professional Flex 2 by Wrox

    • Constraint checkboxes - Left 20 and Top 20

  5. Drag a Button control from the Components view onto the stage area.

  6. Click the Button instance and then, in the Flex Properties view, change the following properties:

    • ID - txtSwitch

    • Label -Switch

    • Constraint checkboxes - Left 20 and Top 45

Figure 4-26 shows the proper layout of the controls on the stage, and the Flex Properties view displays the values for the Label control.

Image from book
Figure 4-26: Proper layout of the controls on the stage and Flex Properties view

Before continuing to the next part of the example, this is a good time to point out two icons on the Design mode editor toolbar. These two icons are the Refresh and Show Surrounding Containers (F4) icons located after the Design mode button and before the States combo box. You can also change the design stage size to a common resolution size, or change it to some custom values for your specific project needs. The Flex Properties category and alphabetical views both are methods of viewing the properties for controls or components currently selected.

Adding View States and Transitions

The next step in developing the example application visually is to create states of the application. Each Flex application has a default state that all child states relate to. You can nest states relatively in a tree hierarchy structure. The hierarchical structure constrains the application state changes, but does not restrict how the states can be navigated. The example application will have a switchBottom state that moves the label and button to the bottom of the application.

  1. Open the States view and right-click the <Base state> (start).

  2. Select the New State… context menu item.

  3. Name it switchBottom and click OK.

  4. Select the switchBottom state. The States combo box located in the Design mode editor’s toolbar can also be used to switch between states.

  5. Select the Label control and change the Top property to Bottom property with the same value.

  6. Select the Button control and change the Top property to Bottom property with the same value.

  7. Select the Button control and add currentState = ""; to the On Click property.

  8. Select the <Base state>.

  9. Select the Button control and add currentState = "switchBottom"; to the On Click property.

Run the application. When you click the button, it will move the button and label to the bottom of the application. States can be used for many purposes. For example, a good usage might be for forms having a large number of fields that might not be filled out by everyone. You can have the base state show a form of all the required input form items, and an optional state that opens up to show all the other fields. A good rule of thumb to know when a specific usage of states might be less optimal is to ask yourself if the states cover the same data and/or user logic.

Adding Interactivity with Behaviors

States changes can look very rigid when large layout changes are taking place on the page. To alleviate this, you can use different effects or behaviors. The Design mode supports behavior development through the Flex Properties view.

  1. Click the Label control and select the Flex Properties view, along with changing it to the Category view.

  2. Open up the Effects folder node.

    • Set mouseDownEffect property to WipeRight.

    • Set moveEffect property to Fade.

  3. Open up the Events property folder node.

    • Set mouseDown to txtTitle.text = (txtTitle.text == "Is Great" ) ? "Professional Flex 2 by Wrox" : "Is Great";

  4. Click the Button control and select the Flex Properties view, along with changing it to the Category view.

  5. Open up the Effects folder node.

    • Set moveEffect property to Fade.

From changing states, text, and adding effects to the controls of the Flex application, the Design mode is a powerful visual tool. You do not have to touch any source code to make complex applications, or change simple component properties and behaviors.


Programming Flex Applications

Although visually creating applications has many benefits, most likely the development process will require changing source MXML, ActionScript, and CSS files. Flex Builder provides the normal code-editing features usually found in IDEs.

Code Editing in Flex Builder

The code assistance or code hinting is not only for MXML files, but is also available in ActionScript and CSS source files. As you use the code assistance, Flex Builder will also automatically insert any package import dependencies. There are also other tag, method, and syntax completion benefits derived from using the code assistance tool that help the developer be more productive.

Tip

The CSS code assistance provides a list of valid values with dash-separated values. It is still valid to name the style properties in camel-case notation (that is, background-color and backgroundColor are valid CSS properties, even though code assistance only displays background-color).

Flex Builder supports code folding to help you organize and view source code. The code folding icons show up as blue circles in the left gutter of the code with either minus or plus signs.

Another, lesser-known source code navigation feature of Flex Builder is creating bookmarks. Any line of code can be bookmarked for viewing and link access through the Bookmark view.

To add a bookmark to a line of code, you first select the line of code, then right-click in the left gutter, and select the Bookmark… context menu item. It will be placed in the Bookmark view’s list, where each bookmark can be double-clicked to return to the specific source file and line number. To delete bookmarks, open up the Bookmark view and right-click the bookmark to be deleted. Select the Delete button from the context menu.

Just as with Bookmarks, you can also assign tasks manually in the same process. The Task view allows for simple to-do list functionality to be used while working with many source files.

The part of making your development life easy while editing source files is to learn the shortcuts. The following table lists a few of the more useful shortcuts defaulted in Flex Builder.

Open table as spreadsheet
Shortcut Keys | Name | Description
Ctrl+Shift+T | Open Type | Opens a full list of types dialog box.
F3/Ctrl+click | Go to Definition | Jumps to identifier’s declaration code.
Ctrl+O | Quick Outliner | Pop ups outline view with filtering ability.
Shift+F2 | Find in Language Reference | Opens context-sensitive help.
Ctrl+Space | Content Assist | Opens code-hinting popup window.
Right-click in gutter | Folding | Code folding features.


Summary

In this chapter, you have learned how to use Flex Builder. You learned the basic definitions of what Flex Builder is and how the workbench works. This chapter also provided a good overview of how to work with projects by setting up custom workbenches, and learning how to navigate through projects. Finally, you learned about the skills to develop an application through the Design mode, as well as about the Source mode.

Chapter 5 discusses the building of your first Flex applications. You not only learn the basic components that make up your Flex applications, but you explore a list of Flex application capabilities such as CSS, skinning, custom components, basic data access, and handling events.


Part II: Developing in Flex 2.0

Chapter List

Chapter 5: Programming Languages
Chapter 6: Building User Interfaces
Chapter 7: Customizing the User Interface
Chapter 8: Flex UI Topics
Chapter 9: Flex Data
Chapter 10: Flex Charting
Chapter 11: Data Access


Chapter 5: Programming Languages

Chapter 3 introduced you to MXML and ActionScript, and how they work together to build rich client applications in Flex. This chapter goes into more detail regarding Flex’s programming languages.

Developing MXML Applications

The process of developing using MXML allows you as the developer to separate application logic from the user interface. This is great because you can lay out all or most of the user interface before writing a single line of code. You may find this useful when showing clients what the application may look like initially. Obviously, the interface will change over time as more and more users use the application, but at least you can visualize what it may look like when it is finished.

MXML allows developers to build applications from the end user’s perspective, because it is the user interface to the business and data access logic.

UI Layout Using Containers

MXML supports two kinds of user interface components: controls and containers. Controls are buttons, combo boxes, text inputs, and date fields. Containers, on the other hand, are rectangular boxes that contain the controls and/or other containers.

When laying out controls, you may find it useful to use containers such as the HBox, VBox, and Grid. The HBox container lays out child components horizontally. The VBox container lays them out vertically, and the Grid container is used to lay out child components in columns and rows.

Flex also has navigator containers that are used to control user navigation through the application. Following are examples of navigator containers:

  • The ViewStack navigator container is the same as the TabNavigator and Accordion containers in that only one child container is visible at a time, but the ViewStack does not have any way to navigate between them by default.

  • The TabNavigator container contains a collection of child containers in which only one child is visible at a time. Flex automatically creates a TabBar container at the top of the TabNavigator container, with a tab corresponding to each child container. Each tab can have its own label and icon. When the user clicks a tab, the corresponding child container becomes visible as the selected child of the TabNavigator container.

  • The Accordion container has a collection of child containers, but only one is visible at a time (like the TabNavigator). The difference is that the Accordion has navigator buttons called accordion headers, which you use to navigate between the children.

There are ways to associate a navigation control with a ViewStack container to navigate between the children. This is done by assigning the ViewStack container’s id property to the navigation control’s dataProvider property. You can associate a LinkBar, TabBar, or ToggleButtonBar container with a ViewStack container to provide a navigation interface.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*"
     xmlns:view="com.wiley.view.*">

     <mx:LinkBar dataProvider="{myViewStack}" />

     <mx:ViewStack id="myViewStack">
         <mx:VBox label="VBox 1" width="400" height="400" />
         <mx:VBox label="VBox 2" width="400" height="400" />
         <mx:VBox label="VBox 3" width="400" height="400" />
         <mx:VBox label="VBox 4" width="400" height="400" />
         <mx:VBox label="VBox 5" width="400" height="400" />
     </mx:ViewStack>

</mx:Application>

In this code example, the <mx:LinkBar> control’s dataProvider property is assigned to the <mx:ViewStack> container id property <mx:LinkBar dataProvider="{myViewStack}" />. To label each button in the LinkBar control, you must assign a name to the label property of the ViewStack container’s children.

Figure 5-1 shows what the preceding code looks like when compiled into an SWF file.

Image from book
Figure 5-1: A ViewStack container and LinkBar navigator

UI Controls

Flex has a variety of user interface controls, such as TextInput, ComboBox, Button, and LinkButton. These controls are usually added to the interface once you have the layout and navigation of your application defined.

The following example contains a VBox (vertical box) container with two child components, a TextInput control and a Button control:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:VBox>
          <mx:TextInput id="myText" />
          <mx:Button label="Click" click="myText.text = 'Button Clicked!!!!'" />
     </mx:VBox>

</mx:Application>

XML Namespaces

In a typical XML document, tags are associated with a namespace. This allows you to refer to more than one set of tags in the same XML document:

<namespace:Tag>Some Text</namespace:Tag>

In MXML, you define an XML namespace using the xmlns property within the root tag of your application or component. Do not specify a prefix if you want to use the default namespace. To add additional tags, you will need to specify a tag prefix and a namespace. In the main file of your Flex application within the <mx:Application> tag, you will notice an xmlns property that indicates the tags in the MXML namespace use the prefix of mx: and a namespace of http://www.adobe.com/2006/mxml:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

The XML namespace allows you to use custom tags that are not found within the MXML namespace. This will come in handy when you need to define your custom components that are located outside the default namespace.

The following component is located in the subdirectory [applicationroot]/mycomponents/view. To access the MXML component (MyComponent.mxml) you need to define a namespace xmlns:mycomponent?view="mycomponents.view.*". The namespace mycomponentview can be allocated any name of your choice as long as it’s one word and without punctuation marks.

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
     width="400"
     height="300">

     <mx:VBox>
          <mx:TextInput id="myTextInput" />
          <mx:Button label="Click" />
     </mx:VBox>

</mx:Canvas>

To be able to define this component outside of the mycomponents.view.* namespace, you will need to add a namespace to the root tag of the MXML file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*"
     xmlns:view="mycomponents.view.*">

     <view:MyComponent />

</mx:Application>

This is done by adding the property xmlns:view=”mycomponents.view.*” to the root tag, which, in this case, happens to be the Application tag. Now all you need to do is instantiate the component by adding the tag <view:MyComponent />.

Data Binding with Components

Data binding is a powerful feature of Flex that allows you to tie data in one object to another. This feature lets you pass data between client-side objects in your application. Binding automatically copies the value of a property in the source object to a property in the destination object when the source property changes.

This allows you to pass data between different layers of the application, such as the UI, data models, and data services.

Flex provides three ways to use data binding:

  • The curly braces {} syntax

  • The <mx:Binding> tag in MXML

  • The BindingUtils static methods in ActionScript

Even though data binding is a powerful feature, it may not always be appropriate for all situations. You may find that a piece of data only needs to be updated occasionally, or you need strict timing when updating your user interface.

The requirements for data binding are a source property, a destination property, and an event that triggers to indicate when to copy the data from the source to the destination.

The following example shows the Label control with its text property bound to the TextInput control’s text property. When you type, the TextInput control’s text property (the source property) is copied to the Label control’s text property (the destination property).

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

 <mx:TextInput id="myTextInput" />
 <mx:Label text="{myTextInput.text}" />

</mx:Application>
Tip

Chapter 9 provides more information about data binding.

RPC Services

A Remote Procedure Call (RPC) lets your applications interact with remote servers to provide data to your applications or send data to a server.

Flex has several types of RPC services that allow access to local and remote server-side or business logic. Your applications can connect to a Web service using the Simple Object Access Protocol (SOAP), a Java object residing on the server using Action Message Format (AMF), or an HTTP URL that returns data in a custom format (such as XML or JSON).

Flex provides components for all three RPC services, which can be defined in MXML or ActionScript:

  • WebService component, which provides access to the SOAP-based Web services.

  • HTTPService component, which provides access to HTTP URLs that return custom data.

  • RemoteObject component, which provides access to Java, PHP, and .NET objects using the AMF protocol. With the RemoteObject component, you can access methods of server-side objects, such as Java objects, without manually configuring the objects as Web services. You need to configure the objects that you want to access as Remote Service destinations in the Flex services configuration file, which is part of Flex Data Services.

The following example shows an application using the HTTPService component to call a Flickr service that returns a list of recent photos. The application binds to srv.lastResult.rsp.photos.photo, which is the HTTPService component’s id property (srv) and the result of the last invocation (lastResult property).

Flickr will return the result in XML and, by default, the HTTPService component will serialize the data into an object. This allows you to access the list of photo objects using the syntax srv.lastResult.rsp.photos.photo. You may have noticed in the TileList control that there are two new tags: <mx:itemRenderer> and <mx:Component>. These are used to define custom inline item renderers for the TileList control. You learn more about item renderers in later chapters, but for now, all it does is replace the current item renderer with a custom Image control to show the thumbnails from Flickr.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[

               [Bindable]
               public var flicrkURL:String = "http://api.flickr.com/services/rest/
?method=flickr.photos.getRecent&api_key=8709b73b4ed150ca12cf33a8d4c0e2a4";

          ]]>
     </mx:Script>
 <mx:HTTPService id="srv"
          url="{flicrkURL}"
          useProxy="false" />

     <mx:Button label="Get Recent" click="srv.send()" />

     <mx:TileList id="myList" dataProvider="{srv.lastResult.rsp.photos.photo}"
width="450" height="300">
          <mx:itemRenderer>
               <mx:Component>
                    <mx:VBox width="80" height="80">
                         <mx:Image source="http://static.flickr.com/{data.server}/
{data.id}_{data.secret}_s.jpg" />
                    </mx:VBox>
               </mx:Component>
          </mx:itemRenderer>
     </mx:TileList>

</mx:Application>

Figure 5-2 shows the application rendered in a Web browser. The thumbnails are displayed within the TileList control, and the data was extracted from Flickr using the HTTPService component.

Image from book
Figure 5-2: Photos retrieved from Flickr

Data Validation

In Flex, you can use the validator components to validate data stored in a data model or a user-interface component. There is a set of standard validator components that comes with the Flex SDK, and you can also build your own by extending the Validator class.

The following example uses the CreditcardValidator component to validate the credit card number in the TextInput control. The ComboBox control contains the different card types (for example, American Express, Mastercard, and Visa).

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
         <![CDATA[
                 import mx.controls.Alert;
         ]]>
     </mx:Script>

 <mx:Model id="creditcard">
        <card>
            <cardType>{cardTypeCombo.selectedItem.data}</cardType>
            <cardNumber>{creditCardInput.text}</cardNumber>
        </card>
    </mx:Model>

     <mx:CreditCardValidator id="ccV"
          cardTypeSource="{creditcard}"
          cardTypeProperty="cardType"
          cardNumberSource="{creditcard}"
          cardNumberProperty="cardNumber"
          cardTypeListener="{cardTypeCombo}"
          cardNumberListener="{creditCardInput}"
          valid="Alert.show('Credit card number is valid')" />

     <mx:Panel title="Data Validation"
         paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
        <mx:ComboBox id="cardTypeCombo">
               <mx:dataProvider>
                <mx:Object label="American Express" data="American Express"/>
                <mx:Object label="Diners Club" data="Diners Club"/>
                <mx:Object label="Discover" data="Discover"/>
                <mx:Object label="MasterCard" data="MasterCard"/>
                <mx:Object label="Visa" data="Visa"/>
            </mx:dataProvider>
        </mx:ComboBox>
         <mx:TextInput id="creditCardInput" restrict="1234567890" />
         <mx:Button label="Validate" click="ccV.validate()" />
     </mx:Panel>

</mx:Application>

Figure 5-3 shows the application rendered in a Web browser. As you can see, a border around the TextInput control is visible and a tooltip is displayed to inform the user that the validation has failed. If the validation is successful, an Alert control is displayed to inform the user that the credit card number is valid.

Image from book
Figure 5-3: Data validation application
Tip

Chapter 9 provides more information about validating data.

Data Formatting

Formatter components are used to convert raw data into a formatted string. Each formatter implements a format method that takes in an Object and returns a formatted string depending on the value of the formatString property. A DateFormatter component, for example, may have a formatString of DD/MM/YYYY and, when passed into the format method, the result would be 29/08/2006.

To create a custom formatter, you must extend the Formatter class in the package mx.formatters and override the format method with your own functionality.

The following example uses a DateFormatter component to format the date from the DateField control and display it in the TextInput control. The formatString in this case is "EEEE, MMM. D, YYYY at H:NN A", which determines what the output of the format will look like.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

 <mx:DateFormatter id="dateFormatter" formatString="EEEE, MMM. D, YYYY at
H:NN A" />

     <mx:Panel title="Data Formatting">
          <mx:DateField id="dateField" change="formattedInput.text =
dateFormatter.format(dateField.selectedDate)" />
          <mx:TextInput id="formattedInput" width="220" />
     </mx:Panel>

</mx:Application>

Figure 5-4 shows the application rendered in a Web browser.

Image from book
Figure 5-4: Data formatting application
Tip

Chapter 9 provides more information about formatting data.

Cascading Style Sheet (CSS)

A Cascading Style Sheet (CSS) allows you to style your Flex application in a similar manner to an HTML Web page. You can either declare your styles within the inline MXML <mx:Style> tag, or reference an external file that contains the styles.

To use the <mx:Style> tag, it is must be a second-level child tag of the root tag in the MXML file and it can be used only in MXML applications and not MXML components. There are two different types of selectors when applying styles to components. The first is the class selector, which can be applied to an individual component. The second is the type selector, which is applied to all components of a certain type.

The following example shows a class selector and a type selector using the inline method within an MXML file. Both styles are applied to the same control.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

 <mx:Style>
          .myLabel /* class selector */
          {
               fontSize: 20;
          }
          Label /* type selector */
          {
               color: #0000FF;
          }
     </mx:Style>

     <mx:Panel title="Cascading Style Sheets">
          <mx:Label text="Cascading Style Sheets" styleName="myLabel" />
     </mx:Panel>

</mx:Application>

Figure 5-5 shows the application rendered in a Web browser.

Image from book
Figure 5-5: CSS application

Skins

Skinning is the process of changing the appearance of a component by modifying or replacing its visual elements. These elements can be made up of images, SWF files, or class files that contain drawing API methods. Flex components can be reskinned without changing their functionality.

Skins can be applied to components with various states (for example, the Button control, which has many skins for various states). Skins are defined using the downSkin, upSkin, and overSkin style properties to represent the way the Button control appears when it is down, up, and when the mouse is over the control. Refer to the Flex 2 documentation for all skins regarding the Button control.

You can define style properties in a few ways: either inline using the <mx:Style> tag, the setStyle() method, or Cascading Style Sheets (CSS).

You can add skins to Flex components either graphically or programmatically.

Graphical Skins

You need to embed image files into your Flex application to use graphical skins. The graphical skins replace the existing skins when you define the files as style properties.

The main advantage of graphical skinning is that designers can use tools such as Adobe Photoshop to create the skins as images with no knowledge of ActionScript.

However, graphical skins may take up more memory and increase the file size because the external images or SWF files are embedded within the Flex application. Another disadvantage when using graphical skins is that they may distort if you resize the component. The solution to this problem would be to use a technique called Scale-9 to create your skins. This will allow your components to resize without distorting skins.

The following code example shows the styles defined inline between the <mx:Script> tag. The overSkin, upSkin, and downSkin style properties point to the image files.

<mx:Style>

          Button
          {
               overSkin: Embed("assets/images/over_skin.png");
               upSkin: Embed("assets/images/up_skin.png");
               downSkin: Embed("assets/images/down_skin.png");
          }

</mx:Style>

Programmatic Skins

Programmatic skins are drawn using ActionScript and are declared in class files. Knowledge of the Flash drawing API is needed to successfully apply skins to your Flex controls. This is a disadvantage because developers are required to create the skins, and not the designers. This means that the developer must translate the designer’s designs into code.

One advantage of using programmatic skins is that you have much more control over your styles. If you wanted to control the radius of the Button control’s corners, this is possible using programmatic skins. They also use less memory because they are compiled without any reference to external files, such as images or SWF files.

The following code example is a typical outline of a programmatic skin class that could be used to skin a Button control:

package
{
    // Import necessary classes here.
    import flash.display.Graphics;
    import mx.skins.Border;
    import mx.skins.ProgrammaticSkin;
    import mx.styles.StyleManager;

    public class MySkin extends ProgrammaticSkin
    {
          public function MySkin()
          {
               // Set default values here.
          }

          override protected function updateDisplayList(w:Number, h:Number):void
          {
               // Add styleable properties here.
               // Add logic to detect component's state and set properties here.
               // Add drawing methods here.
          }
        }
}

Adding Effects

An effect is a change to a component that occurs over a specified period of time. Examples include fading, resizing, and moving a component. Effects are initialized using a trigger (such as a mouse click), receiving focus on a component, or a component becoming visible. All these triggers are used to form behaviors.

Behaviors let you animate, add motion, and add sound to your application in response to some user or programmatic action. For example, if you move your mouse cursor over a Button control, it may inform you by resizing slightly.

To create a behavior, you define an effect with an id property and bind it to the trigger (mouseUpEffect). The following example has two <mx:Zoom> effects defined, each with their own id property to distinguish them from each other. The one effect enlarges the component, while the other effect reverts it back to ts original size. These effects are assigned using their id property to the mouseDownEffect and mouseUpEffect triggers of the Button control.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

 <!-- Efects -->
    <mx:Zoom id="grow" duration="100" zoomHeightTo="1.5" zoomWidthTo="1.5" />
    <mx:Zoom id="revert" duration="50" zoomHeightTo="1" zoomWidthTo="1" />

    <mx:Panel title="Effects" width="120" height="100" paddingTop="10"
paddingBottom="10"
          paddingLeft="10" paddingRight="10">

        <!-- Assign effects -->
        <mx:Button label="Click" mouseDownEffect="{grow}" mouseUpEffect="{revert}" />

    </mx:Panel>

</mx:Application>

Custom MXML Components

In Flex, the ideal way to build your applications is using multiple MXML and ActionScript files. The reason for this is that the architecture promotes modular design and code reuse, and lets multiple developers work on the same project without much hassle.

MXML components are MXML files that you create and use as custom MXML tags within other MXML files. The name of the MXML file becomes the class name, which you can reference in another MXML file. You will find the main use of MXML components is to extend the current functionality found in existing Flex components.

A simple example of using a custom MXML component would be to have a ComboBox control with a list of states. It would be a pain to create and initialize a ComboBox component with the list of states every time you needed one in your application. The solution would be to create a custom MXML component that extends the ComboBox control and have the list of states defined in there. So anytime you need a state selector in your application, you could use the custom MXML component.

The name of this example file is StateSelector.mxml, which extends the ComboBox control and adds an array of objects containing the list of states:

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:dataProvider>
          <mx:Array>
               <mx:Object label="Alaska" data="AL" />
               <mx:Object label="Texas" data="TX" />
               <mx:Object label="Florida" data="FL" />
               <mx:Object label="New York" data="NY" />
          </mx:Array>
     </mx:dataProvider>

</mx:ComboBox>

The following MXML code shows you how to use the StateSelector.mxml in your Flex application:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

 <mx:Panel title="Custom MXML Components">

        <StateSelector />

    </mx:Panel>

</mx:Application>

The StateSelector.mxml is in the same subdirectory as the main application MXML file. So no namespace is required when defining the custom MXML component.


MXML

This section describes the basics of the MXML syntax, which, as you may know, is used to build your user interfaces.

Basic MXML Syntax

You will find that most MXML tags correspond to ActionScript 3.0 classes or properties of those classes. The Flex compiler parses the MXML tags and compiles them into one SWF file that contains the SWF byte code.

You have already seen many examples so far using MXML syntax. Let’s start off with an easy example, such as defining a Button control:

<mx:Button id="myButton" label="Click me!" />

As you can see, the id property of the Button control has been set to myButton, which needs to be unique for each control in the MXML file. The label property sets the text that is shown inside the Button control.

The following example shows a complete Flex application with one Button control defined:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    horizontalAlign="center" verticalAlign="center">

    <mx:Button id="myButton" label="Click me!" />

</mx:Application>

MXML Naming Conventions

When you create new MXML files, there are naming conventions you must adhere to:

  • Filenames can only start with a letter or an underscore (_), and they can only contain alphanumeric and underscore characters after that.

  • Filenames cannot be the same name as ActionScript class names, component id values, or the word “application.“ Also, do not use filenames that match MXML tags in the mx namespace.

  • All filenames are required to end with the lowercase .mxml file extension.

A lot of MXML tags correspond to ActionScript classes. When defining the tags, you use the same naming conventions as the ActionScript class. In other words, the class begins with a capital letter, and each capital letter separates the words in the class name. Also, the properties and events also correspond to the ActionScript class.


ActionScript

ActionScript is the reason Flex developers exist. Without it, your application would have no logic, and all it would be is a useless user interface. Flex developers need ActionScript to be able to extend the functionality of their applications. The language provides control and object manipulation that is not available in MXML.

Flex Components

As a Flex developer, you will find that ActionScript’s primary use will be working with visual controls and containers in your application. In this section, you learn how to reference a Flex control and manipulate the properties in ActionScript.

Referring to a Control in ActionScript

Before you write any ActionScript, you must define a control in MXML and assign an id property to it. This allows you to reference the Flex control in ActionScript.

<mx:TextInput id="myTextInput" text="Refer to me via the id property" />

The id property is optional and is only required when referencing the component. The MXML compiler creates a variable called myTextInput that contains a reference to the TextInput object. You can access all the public methods and properties using the dot notation in ActionScript.

To access the control in ActionScript, you must reference the id property. The following example shows you how this is done:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

 <mx:Script>
          <![CDATA[

               public function getText():String
               {
                    return myTextInput.text;
               }

          ]]>
     </mx:Script>

 <mx:TextInput id="myTextInput" text="Refer to me via the id property" />

</mx:Application>

The getText() method returns a string, refers to the TextInput control’s id property (myTextInput) and accesses the text property of the object.

One thing to note is that the ids for all tags in an MXML component, even deeply nested, generate public variables in the component being defined. In other words, all id properties must be unique within the document.

If the id property of a Flex component is not defined, you can use the methods of the component’s container, namely, getChildAt() and getChildByName():

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center">

     <mx:Script>
          <![CDATA[

               import mx.controls.Alert;
               import mx.controls.TextInput;

               public function getText():String
               {
                    var name:String = TextInput(getChildAt(0)).name;
                    var text:String = TextInput(getChildByName(name)).text;
                    return text;
               }
          ]]>
     </mx:Script>

 <mx:TextInput text="Hello World!" />
 <mx:Button label="Get Text" click="Alert.show(getText())" />
</mx:Application>

This example casts the getChildAt(0) to type TextInput to access the name property and assigns the value to the variable name. The variable name is passed into the childChildByName(name) method and cast to type TextInput to allow access to the text property, which is assigned to variable text.

The this keyword is another way to reference components in a document using ActionScript. To access the object, you use the keyword, followed by the square brackets, passing in a string between them.

The following code example has the same functionality as the previous one, except it uses the this keyword to reference the TextInput control:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center">

     <mx:Script>
          <![CDATA[

               import mx.controls.Alert;
               import mx.controls.TextInput;

               public function getText():String
               {
                    return this["myTextInput"].text;
               }

          ]]>
     </mx:Script>

 <mx:TextInput id="myTextInput" text="Hello World!" />
 <mx:Button label="Get Text" click="Alert.show(getText())" />

</mx:Application>

Component Method Invocation

In ActionScript, you can invoke a method on a component using the standard dot-notation syntax, as shown here:

myTextInput.setSelection(0, 5);

The myTextInput is the id property of the TextInput control, which, as you know, is a variable. Using the dot notation, the setSelection() method is called with the required parameters.

If you need to invoke a method from a child document (such as an MXML component), you can use the parentApplication, parentDocument, or Application.application properties. With these methods, you can access parent document public methods and properties. An example of where this may come in useful is when you need to call a method on the parent document from a popup window.

Using ActionScript to Create Visual Components

To create visual components at run-time, you must use the new operator. This is the same way you create instances of an ActionScript class. When the component is instantiated, all its default properties are available, but it does not have a parent or any children. Also, you will not be able to see the component, because it is not yet in the display list of the Flash Player. This is the most appropriate time to set any properties on the component before it is added to the display list.

Once you have all the necessary properties set, you must add the new component to a container by using the container’s addChild() or addChildAt() method. This will put the component into the Flash Player’s display list, and the component’s children are then created. The children are created late so that you can set the properties that affect the children as they are created.

The following piece of code creates a TextInput control using the container’s addChild() method. If you want to add a control to a specific index in the display list, you can use the addChildAt() method.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[

               import mx.controls.TextInput;

               public function createComponent():void
               {
                    var t:TextInput = new TextInput();
                    t.text = "This component was created at runtime";
                    this.addChild(t);
               }

          ]]>
     </mx:Script>

     <mx:Button label="Create Component" click="createComponent()" />

</mx:Application>

To remove a control at run-time, you can use the removeChild() method or removeChildAt() method. There is also a method called removeAllChildren() that will remove all the children from the container. One thing to remember when using these methods is they do not actually delete the objects from memory. Some time in the future of the application cycle, the Flash Player will include the objects in the garbage collector, unless you have a reference to the child on some other object.

The addChild() method can only take a parameter of type DisplayObject. If you create a new object that is not a subclass of flash.display.DisplayObject, you must wrap it in a DisplayObject before attaching it to a container.

Separating ActionScript from MXML

This section shows you several different methods of separating ActionScript from MXML. The first method is having one MXML file with the event-handling logic in the event attribute:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Label id="myLabel" />
     <mx:Button label="Set Label" click="myLabel.text = 'First method'" />

</mx:Application>

The second method is another MXML document, but instead putting the event-handling code in the <mx:Script> block:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[

               public function setLabel():void
               {
                    myLabel.text = "Second method";
               }

          ]]>
     </mx:Script>

     <mx:Label id="myLabel" />
     <mx:Button label="Set Label" click="setLabel()" />

</mx:Application>

Lastly, the third method is an MXML document again, but with the event-handling code in a separate ActionScipt file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script source="thirdsample.as" />

     <mx:Label id="myLabel" />
     <mx:Button label="Set Label" click="setLabel()" />

</mx:Application>

The thirdsample.as file contains the following code:

public function setLabel():void
{
     myLabel.text = "Third method";
}

Developing ActionScript Components

In ActionScript, you can create reusable components and reference them in MXML as tags. You can create your own components from scratch, or extend existing components within the Flex Framework.

Developing your own components in ActionScript allows you to modularize the application and maintain your code separately. This is great when you have many developers working on the same application. Each Flex developer can write a component (or a separate part of a component), and from there, you will eventually have a full suite that can be reused between applications.

When developing components, you may consider basing them off the current Flex components because there will most likely be logic you can reuse within your own custom components. For example, you may want to create a masked TextInput control and, instead of starting from the beginning, you can extend the existing Flex TextInput control.

The following piece of code is a custom component called MaskedTextInput derived from the TextInput control and the package name is com.mycompany.components:

package com.mycompany.components
{
     import mx.controls.TextInput;

     public class MaskedTextInput extends TextInput
     {
          public function MaskedTextInput()
          {
               super();
          }
     }
}

To reference your custom component in your application, you must define a namespace components (this can be any name) that points to the directory of the MaskedTextInput.as file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*"
     xmlns:components="com.mycompany.components.*">

     <components:MaskedTextInput />

</mx:Application>

Types of Components

In ActionScript, you can create the following types of custom components:

  • User-interface (UI) components are Button, TextInput, and ComboBox controls plus VBox, HBox, and Canvas containers that a user can interact with using the mouse and keyboard. A typical custom visual component extends the UIComponent class or other Flex visual components.

  • Non-visual components are Flex components that have no visual elements, such as the HTTPService, Web service, and DateFormatter components. These components do not extend the UIComponent class and provide greater efficiency at run-time.

Performing Reflection

Reflection is the process by which an application can be modified in the process of being executed, in a manner that depends on abstract features of its code and its run-time behavior. In other words, the program has the ability to “observe” and possibly modify its own structure and behavior.

The following is an example in Java using the java.lang.reflect package. If you are familiar with Java, and have used the java.lang.reflect package, this should be easy to understand.

// Java code to illustrate how reflection works

// Without reflection
Person person = new Person();
person.walk();

// With reflection
Class cl = Class.forName("Person");
Method method = cl.getMethod("walk", null);
method.invoke(cl.newInstance(), null);

Both code fragments create an instance of a class Person and call its walk() method. The difference is, in the first fragment, the names of the class and method are hard-coded. It is not possible to use a class of another name. In the second fragment, the names of the class and method can easily be made to vary at run-time.

In ActionScript, the introspection API (discussed shortly) is not as advanced as the Java equivalent, but does allow you to read the methods and properties, and invoke methods of an object at run-time.

Reflection is an activity that allows an object to have information about the structure. The programming paradigm driven by reflection is called reflective programming. In ActionScript 3, reflection is referred to as object introspection.

There are two ways to do introspection in ActionScript:

  • Using the for…in loops

  • Using the introspection API

For…in Loops

The for…in loop does not enumerate over declared variables and methods of classes but only dynamically added properties. So, in other words, most of the ActionScript API classes would not display any properties.

The following code example creates an instance of the Object class and adds properties to that instance. The Object class is dynamic, which means you can add or change properties at run-time.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[

               public function enumerateObject():void
               {
                    var o:Object = new Object();
                    o.firstname = "Simon";
                    o.lastname = "Barber";
                    o.emailaddress = "simon.barber@thoughtfaqtory.com";

                    for (var p:String in o)
                    {
                         trace(p + ": " + o[p]);
                    }
               }

           ]]>
     </mx:Script>

     <mx:Button label="Enumerate Object" click="enumerateObject()" />

</mx:Application>

The output of the trace statement would look like this:

firstname: Simon
emailaddress: simon.barber@thoughtfaqtory.com
lastname: Barber

There is a toString() method in the mx.utils.ObjectUtil class that will print all the dynamically added properties of an object:

public function dump(o:Object)
{
    trace(ObjectUtil.toString(o));
}

Introspection API

In the previous section, you were shown how to use the for…in loop and ObjectUtil class’s toString() method to print out dynamic properties of an object. The introspection API in ActionScript allows you to list all the public properties and methods of a non-dynamic (sealed) class or class instance using the describeType() method.

The method is in the flash.utils package and returns an E4X XML object that contains an XML description of the object’s type. To return information about the non-static members of a class, use describeType(this), with this meaning any object instance or ActionScript primitive types. If you want to return information about the static members of a class, use describeType(getDefinitionByName("MyClass")).

The following examples traces out the variables of the TextInput control instance textInput:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[
               import mx.utils.ObjectUtil;
               import flash.utils.describeType;

               public function describeInstance():void
               {
                    var classInfo:XML = describeType(textInput);
                    //trace(ObjectUtil.toString(classInfo.toString()));

                    // List the object's variables, their values, and their types.
                 for each (var v:XML in classInfo..variable)
                 {
                     trace("Variable " + v.@name + " = " + textInput[v.@name] + "
(" + v.@type + ")\n");
                 }
               }

          ]]>
     </mx:Script>

     <mx:Button id="btn1" label="Describe Instance" click="describeInstance()" />
     <mx:TextInput id="textInput" />

</mx:Application>

The output displays the variables of the TextInput control:

Variable isPopUp = false (Boolean)
Variable states = (Array)
Variable transitions = (Array)

One more other useful method for introspection is the ObjectUtil’s getClassInfo() method, which returns an Object with the name and properties of the object. The following example traces the object out using the toString() method of the ObjectUtil’s class:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     verticalAlign="middle"
     horizontalAlign="center"
     xmlns="*">

     <mx:Script>
          <![CDATA[

               import mx.utils.ObjectUtil;

               public function showProperties():void
               {
                    var o:Object = ObjectUtil.getClassInfo(textInput);
                    trace(ObjectUtil.toString(o));
               }

          ]]>
     </mx:Script>

     <mx:Button id="btn1" label="Show Properties" click="showProperties()" />
     <mx:TextInput id="textInput" />

</mx:Application>


Handling Events

Being able to handle events in Flex is very important because you will most likely need to use them to interact with Flex controls, custom controls, and components. This section provides you with basic information about the event model in Flex 2, and describes the Event object, its subclasses, and the event dispatching model.

Events inform a developer that something has happened within a Flex application. They can be generated when the visual appearance of a component changes, when the component is created and destroyed, and by using user devices such as the mouse and keyboard. In other words, any user interaction will most likely trigger an event, or even data that is returned from the server may trigger an event. This happens without any user interaction.

The developer can listen for these events by adding event listeners, which are functions used to respond to the triggered events. They are commonly referred to as event handlers. To give you an example, a user clicks a button that downloads data from the server. An event handler listens for an event to be triggered once the data has been fully downloaded. The event is fired, which, in turn, calls the event-handler function and parses the data into some meaningful information to be used in a DataGrid control, for example.

All or most components in Flex have built-in events that can be handled in ActionScript in your MXML applications.

Event Flow

The event model allows developers to listen for any events being dispatched by another control. The flow of an event starts when the Event object is dispatched. It then makes a journey from the root of the display list to the target node, checking for registered listeners. The target node is the node where the event originated from (for example, a user clicks a Button control named Button1). The Event object’s target node holds a reference to Button1.

There are three parts to the way event flow works:

  • Capturing phase - This phase comprises of all the nodes from the root node to the parent of the target node. Once this phase is in execution, the Flash Player starting at the root examines each node to see if there is a listener registered to handle the event. If it finds registered listeners, it will set the values of the Event object and then call the listener function. The Flash Player stops after it has reached the target node’s parent and called the registered event listeners.

  • Targeting phase - This phase consists only of the target node. The Flash Player sets the values on the Event object, looks at the target node for any registered event listeners, and then calls those listeners.

  • Bubbling phase - This phase consists of all the nodes from the target node’s parent to the root node. It begins at the target node’s parent where the Flash Player sets the values on the Event object and then calls the event listeners on each of these nodes. The Flash Player will stop after any listeners on the root node are called.

These phases are examined in more detail later in this chapter.

Event Class

The flash.events.Event class is the base class for all events in your application. Any time an event occurs in Flex, this class is implicitly created when it is dispatched. It contains properties with information about the event that occurred.

The event listeners can access the details that were passed with the event’s properties, such as the event type and the target that dispatched the event. However, passing an Event object to the event listener is optional.

The Event object is created only once on every dispatch. During the bubbling and capturing phases, the values on the Event object change as it moves up or down the display list. This is much more efficient than creating a new Event object for each node.

Subclassing Events

There are two packages that house all the major event classes that extend the flash.events.Event class. They are mx.events and flash.events. The mx.events.* packages contains all the events that are specific to the Flex controls, such as the DropDownEvent and ItemClickEvent classes. The other package, flash.events, contains all the events that are defined by the Flash Player, such as the TextEvent and MouseEvent classes.

When developing Flex applications, you must create your own events that extend the Event class. These custom events will contain additional unique properties that hold vital information that the Event class does not contain. For example, the TextEvent class extends the Event class and has a text property that contains a character or sequence of characters entered by the user.

EventDispatcher Class

The EventDispatcher class allows any object that inherits from it to participate in the Flex event model. All objects in the Flash Player’s display list inherit the functionality of the EventDispatcher class. The reason for this is that all objects in the display list inherit from the DisplayObject class, which, in turn, extends the EventDispatcher class.

Although you may think the EventDispatcher only allows you to dispatch or send events, you would be mistaken. This class gives you the functionality to register for events, check for event listeners, and remove event listeners. The most common method used in the EventDispatcher is the addEventListener() method, which you use to register an event listener.

More advanced programmers and component developers will use the dispatchEvent() method to manually dispatch or send events a custom Event object into the event flow. One other method to mention is the hasEventListener() method, which checks for an event listener of a specific event type on a particular display object and returns true if it is found.

Event Usage

To use events in Flex, you must first define an event listener or event handler. This is a function or class method that responds to an event when it is dispatched. The signature of the function can optionally include an argument that specifies the event type.

The following example is a basic event listener function that traces a string to the console:

<mx:Script>
     <![CDATA[

     public function eventListenerFunction(event:Event):void
     {
          trace("Event sent into the event flow");
     }

     ]]>
</mx:Script>

Secondly, you must register the event listener or function with a display list object by using the EventDispatcher class addEventListener() method:

btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction);

There is a simpler method to listener registration for Flex controls in MXML. You define the click event, which references the listener function on the Button control using an attribute:

<mx:Button label="Dispatch Event" click="eventListenerFunction()" />

This is the same as using the addEventListener() method to register the listener in the previous code example. However, it is better practice to use the addEventListener() method because it gives you greater control and you can configure the priority and capture settings, and use event constants. With event constants, you can ensure that the event type is valid at compile time.

Any time an event is dispatched, Flex creates an Event object containing information about the event, such as the type and a reference to the control that fired it. To have access to the Event object, it must be passed into the event listener function, as this following code example shows:

public function eventListenerFunction(event:Event):void
{
     trace("Event type: " + event.type);
}

To do the same within MXML using an inline event, you must explicitly pass the event into the listener:

<mx:Button label="Dispatch Event" click="eventListenerFunction(event)" />

The event model allows you to register multiple event listeners with a single event. This may be useful when you want two things to happen when a user clicks a Button control. The following example shows multiple event listeners registered to a single instance of a button in MXML and ActionScript:

// MXML
<mx:Button id="btn1" label="Dispatch Event" click="eventListenerFunction1(event);
eventListenerFunction2(event)" />

// ActionScript
public function initUI():void
{
     btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction1);
     btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction2);
}

To set the order in which the event listeners are called, you must specify the priority parameter of the addeEventListener() method. This obviously cannot be done using the inline method in MXML.

The opposite also works by registering a single event listener with multiple components. The following example again shows the registration of a single event listener with multiple components in MXML and ActionScript:

//MXML
<mx:Button id="btn1" label="Dispatch Event" click="eventListenerFunction(event);" />
     <mx:Button id="btn2" label="Dispatch Event" click="eventListenerFunction(event)" />

//ActionScript
public function initUI():void
{
     btn1.addEventListener(MouseEvent.CLICK, eventListenerFunction);
     btn2.addEventListener(MouseEvent.CLICK, eventListenerFunction);
}

The Target Property of the Event Class

As mentioned earlier, the Event object contains a reference to the object dispatching the event. In essence, you can access all the public methods and properties of the instance within the event listener.

The following example accesses the currentTarget.name property of the UIComponent:

public function eventListenerFunction(event:Event):void
{
     trace("The button instances name is " + event.currentTarget.name);
}

To call methods and access properties on the current target within the event listener, you must cast the currentTarget property to a DisplayObject. If you need to access the properties of a specific control (such as the Button control), the currentTarget property must be cast to type Button.

The following example sets the label of the Button control to “Label Changed”:

import mx.controls.Button;

public function eventListenerFunction(event:Event):void
{
     Button(event.currentTarget).label = "Label Changed";
}

Propagation

There are three phases during which Flex looks for event listeners when events are triggered. The phases occur in the following order:

  1. Capturing phase

  2. Targeting phase

  3. Bubbling phase

In this section, you learn more about how event propagation is handled in Flex, and learn more about each phase.

Difference Between the Target and currentTarget Properties

All Event objects have a target and currentTarget property, which keeps track of where it is in the propagation process. The target property references the dispatcher of the event, and the currentTarget property references the current node that is being examined for event listeners.

When a user clicks a control, the target property often refers to a subcomponent such as a UITextField (which renders the label) in a Button control. In other words, when the Flash Player dispatches the event, it might be triggered from the internal subcomponent and not the Button control. Most likely, you will have the Button control listen for the event, and the target property of the event listener might refer to the UITextField or subcomponent of the control.

The MouseEvent will bubble up the chain within the control, but the target property (which might be the UITextField) will stay the same. The currentTarget property will be set to each level as it moves up the chain, and eventually reference the Button instance. So, for this reason, you should use the event.currentTarget property rather than the event.target property.

Capturing Phase

As mentioned, the capturing phase is when Flex examines an event’s ancestors in the hierarchy for registered event listeners. It starts at the root ancestor, and carries on down the display list until it reaches the parent’s target.

Figure 5-6 shows the structure of a basic application. The capturing phase starts at the Application object and moves through to the Panel (parent of the target).

Image from book
Figure 5-6: Capturing phase

The currentTarget property will change on the Event object to the node of the listener being called during the capturing phase. The target property will remain the same, referring to the dispatcher of the event. The useCapture property of the addEventListener() method defaults to false and has to be explicitly set to true. Adding an event listener using MXML will result in the argument being set to false, and there is no way to override it.

Targeting Phase

The targeting phase is when Flex invokes only the event dispatcher’s listeners. So, no other nodes in the display list are looked at during this phase, and the currentTarget and target properties remain.

Bubbling Phase

The bubbling phase is very similar to the capturing phase, except it looks for event listeners in reverse. In other words, it starts at the dispatcher’s parent and carries on up the display list to the root application.

Figure 5-7 shows the same structure of a basic application as the capturing phase. The bubbling phase starts at the parent of the dispatcher and moves through to the root of the application.

Image from book
Figure 5-7: Bubbling phase

The events will only bubble and process the event bubbling phase if the bubbles property is set to true. Keyboard and mouse events bubble by default, but it can be dangerous to set all your events to bubble by default. The reason for this is that if you are listening for different events, but the event type is the same, all those listeners will trigger. This can be difficult to debug, and it is recommended not to bubble your events unless it’s really necessary.

There is one more thing to remember. If you set the useCapture property to true, the bubbling phase will not process. If you want both phases to be processed, you have to call the addEventListener() method twice, once with useCapture set to true and the other with useCapture set to false.

Priorities

Event priority is really used when there are many event listeners registered with a single event. The event listeners are called depending on the order in which the addEventListener() methods are defined. Using MXML to register the events results in an unpredictable order.

To change the order in which the event listeners are called, you specify the priority property parameter in the addEventListener() method. The priority works from highest to lowest. The listener2() method will be called first because it has the highest priority of 2, and the listener1() method will be called next.

public function initUI():void
{
     btn1.addEventListener(MouseEvent.CLICK, listener1, false, 1);
     btn1.addEventListener(MouseEvent.CLICK, listener2, false, 2);
}

If all the event listeners have the same priority, they will be executed in the order they are defined. The priority can be either positive or negative, and the default value is 0. To change the priority of the event listener, the removeEventListener() method must be called to remove the event listener. You will then need to register the event listener again with a different priority.

An important point to remember is that there is no guarantee that the listener will finish executing before the next one in the priority list is called. In other words, you should ensure that listeners do not rely on other listeners to complete before calling the next one. The Flash Player does not necessarily wait for the first handler to finish executing before proceeding to the next one.

Subclassing Events

In Flex, there are many subclasses that are based off the Event class. They contain specific information about the event that is not available in the Event class, such as the DragEvent class. Flex controls generate an Event object that is a specific event type (for example, when you drag a row from one List control to another).

If you specify the event type as a parameter in the event listener functions, you can access all the subclass’s properties. The following is an event listener that listens for the dragComplete event to be dispatched. You can define the event parameter as a basic Event class, but you will have to cast it in the event listener to access the properties specific to the subclassed event. This way it can use less memory, but it is best practice to declare the type.

private function doDragComplete(event:DragEvent):void
{
     trace("dragComplete triggered: " + event.type);
}

While developing Flex applications, you will need to create custom events that carry specific information not found on the Event class. To accomplish this, create a custom class that extends the Event class, as the following example shows:

package com.mycompany.events
{
     import flash.events.Event;
     import com.mycompany.vo.UserVO;

     public class LoginEvent extends Event
     {
          public function LoginEvent(type:String, userVO:UserVO,
bubbles:Boolean=false, cancelable:Boolean=false)
          {
          super(type, bubbles, cancelable);
          this.userVO = userVO;
     }

     public var userVO:UserVO;
     }
}

The LoginEvent class extends the Event class and adds an extra property called userVO. This contains a reference to another custom class called UserVO, which has all the properties associated with a user of the application. The userVO property is set in the constructor of the LoginEvent class. This can be set as optional by specifying the property to be equaled null.

public function CustomEvent(type:String, userVO:UserVO=null, bubbles:Boolean=false,
cancelable:Boolean=false)
{
     super(type, bubbles, cancelable);
     this.userVO = userVO;
}

Keyboard Events

As you may already know, or may have gathered, the Flash Player supports all the basic functionality using keyboard combinations from the operating system. You can also trap or override any key or combination of keys to perform an action.

You may find that you want to trap keys globally so that wherever a user is in the application, the keystrokes are identified and the necessary action is performed. No matter where the mouse is in an application, Flex recognizes the global keyboard events.

The most common way to handle keyboard events is to create an event listener. If you want to trap any key when it is pressed, you can add an event listener to the stage object, as the following example shows:

private function addKeyboardListeners():void
{
     stage.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys);
}

As you can see, every time a user presses a key, the trapKeys() method is called to process any logic that the developer has defined. The following example shows what the trapKeys() method looks like for this basic example. The function traces out the event.charCode and event.keyCode to the console.

private function trapKeys(event:KeyboardEvent):void
{
     trace("charCode: " + String(event.charCode) + " | keyCode: " +
String(event.keyCode));
}

To accomplish the same task in MXML using the inline method, you can define the keyDown event of a UIComponent and reference the trapKeys() method:

<mx:TextArea id="text_area" keyDown="trapKeys(event)" />

Keys can only be trapped on components that can have focus. You should avoid trying to trap keys on containers that cannot have focus, such as the Box containers. Instead, if a container has children that accept focus and keyboard input from the user, you can set the event handler on the container and assume it will bubble up.

Precedence on KeyboardEvent

Registering event listeners for keyboard events with regard to order does not work the same way as explained earlier in the chapter. Defining the keyUp and keyDown event listeners for the parent and control will result in each component dispatching the same event twice, because the event bubbles. This will result in the target property changing.

In the following example, the keyDown event is registered in the application, Panel container, and the TextArea control:

private function addKeyboardListeners():void
{
     application.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys);
     panel1.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys);
     textarea1.addEventListener(KeyboardEvent.KEY_DOWN, trapKeys);
}

The order in which the keyboard events are dispatched is the child controls are first before any of their parents. In this example, the TextArea control event is dispatched first, then the Panel control, followed by the Application.

MouseEvents

The MouseEvent class and all its subclasses have extra properties that determine if a specific key was held down when clicking the mouse button:

  • altKey - Set to true if the Alt key is held down when the user pressed the mouse button.

  • ctrlKey - Set to true if the Ctrl key is held down when the user pressed the mouse button.

  • shiftKey - Set to true if the Shift key is held down when the user pressed the mouse button.

You may want the user to be able to open a popup window by holding down the Alt key and Shift key together while pressing the mouse button anywhere within application.


Summary

This chapter provided the insight and knowledge to build your first Flex application. You learned about the MXML syntax and using ActionScript to provide flow control and object manipulation that is not available in MXML. Lastly, you learned about one of the most important features in Flex - handling events within your applications.

Chapter 6 describes how to improve the user experience by adding functionality to your application and customizing the user interface. You learn about styles, fonts, skins, and item renderers, and how to localize your applications.


Chapter 6: Building User Interfaces

This chapter describes how to use Flex 2 components to build user interfaces for your applications. Flex 2, as you know, has many built-in components that make life a lot easier when it comes to building the interface. You are introduced to Flex controls, data providers, and collections, and how to lay out controls using containers. Flex makes it very easy to lay out your user interfaces using MXML.

Visual Components

The component-based development model Flex provides allows you to develop applications that are architecturally sound, achieving great scalability and reliability. The pre-built visual components in Flex allow you to build interfaces faster without having to create your own components. That said, Flex includes a well-thought-out component architecture that allows you (as the developer) to build your own components, either by extending existing ones, or creating your own.

You have a lot of power at your fingertips when using visual components in Flex. They are extremely flexible and provide a great deal of control over their appearance (the font and size of the text in any component, the sizing of components), as well as their response to user interactions.

This section provides an overview of the characteristics of visual components such as size, events, styles, behaviors, and skins.

Class Hierarchy

All visual components in Flex generally extend the UIComponent class. This is the base class for all visual components in Flex, both interactive and non-interactive. When creating custom components, you should extend the UIComponent class because it contains functionality for width, height, handling double-clicks, id property, style names, and x and y properties.

Figure 6-1 shows the class hierarchy from the Object class through to all visual components in Flex.

Image from book
Figure 6-1: Class hierarchy from the Object class through to all visual components in Flex

UIComponent Class

The UIComponent class has many properties and methods that are accessible when extending the class. The most commonly used properties are listed in the following table.

Open table as spreadsheet
Property | Type | Description
doubleClickEnabled | Boolean | Specifies whether the UIComponent object receives doubleClick events
enabled | Boolean | Whether the component can accept user interaction
height | Number | Number that specifies the height of the component, in pixels, in the parent’s coordinates
id | String | ID of the component so that you can refer to it using ActionScript
percentageWidth | Number | Number that specifies the height of a component as a percentage of its parent’s size
percentageHeight | Number | Number that specifies the width of a component as a percentage of its parent’s size
styleName | String | The class style used by this component. Very similar to the way CSS works in HTML
toolTip | String | Text to display in the tooltip
visible | Boolean | Controls the visibility of the UIComponent
width | Number | Number that specifies the width of the component, in pixels, in the parent’s coordinates
x | Number | Number that specifies the component’s horizontal position, in pixels, within its parent container
y | Number | Number that specifies the component’s vertical position, in pixels, within its parent container

Component Sizing

The Flex SDK has layout and sizing functionality that allows you to control the size of your visual components.

You can determine the size of your components (explicit sizing), or let Flex do it for you (default sizing). To use default sizing, you do not specify the width and height of the component. Explicit sizing, on the other hand, requires you to specify the width and height of the visual component, as the following example shows:

<mx:List id="prodList" dataProvider="{listDP}" width="200" height="300" labelField=
"@name"/>

You may find explicit sizing to be too precise. You can, instead, define the size of the component as a percentage. In Flex, this is called percentage-based sizing. The following example shows percentage-based sizing on a Panel control:

<mx:Panel id="panel1" width="100%" height="100%">
     <mx:Label text="Percentage-based sizing" />
</mx:Panel>

To specify the percentage-based sizing in ActionScript, you must access the percentageWidth and percentageHeight properties of the control. The following example will reset the Panel control’s width to 50 percent of the parent container:

panel1.percentageWidth = 50;

The layout of your components is very important. Flex has a mechanism called constraint-based layout that allows you to control the size and position by anchoring the sides, or centering the components within their containers by specifying the top, bottom, left, right, verticalCenter, and horizontalCenter properties. The following example shows a VBox container defining constraint-based layouts:

<mx:VBox width="200" height="500" left="50" top="30" y="100">
     <mx:Label text="Percentage-based sizing" />
</mx:VBox>

You can mix the sizing and layout properties as long as they are done appropriately. You must not specify the width and percentageWidth of a control, because you can use only one or the other.

Event Handling

A user interacts with a component such as clicking a button that, in turn, fires an event. You can write code to process the click event that may pop up an Alert control, informing the user that something important has occurred.

As you may know, Flex applications are event-driven, and this makes it a very powerful platform to develop your Rich Internet Applications (RIA). The basic cycle of event handling starts when events are dispatched. The objects that have registered listeners are notified for that event. Event handlers (or event listeners) are defined to process the event in ActionScript. You register event listeners in either ActionScript or the MXML declaration of the component.

The following example registers an event listener in MXML that is processed when the Button control is clicked:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
     <![CDATA[

          import mx.controls.Alert;

          private function handleClickEvent(event:Event):void
          {
               Alert.show("click event fired");
          }

     ]]>
     </mx:Script>

     <mx:Button label="Click" click="handleClickEvent(event)" />

</mx:Application>

This example passes in the event object when declaring the click event handler handleClickEvent(event). The event handler in this example does not make use of the event, but you will need to do so in many of the applications you build. You do not have to pass in the event object, as long as it is not defined as a parameter in the event handler.

The following example shows the event object being accessed within the event handler. The List control contains the names of the three authors. The event handler is registered to the change event. Any time a user selects an item in the List control, the Alert control pops up and shows the name of the selected author through the selectedItem property.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

    <mx:Script>
    <![CDATA[
         import mx.controls.List;

         import mx.controls.Alert;

         private function handleChangeEvent(event:Event):void
         {
              Alert.show("You selected the name: " + List(event.currentTarget)
.selectedItem.label);
         }

    ]]>
    </mx:Script>

    <mx:List change="handleChangeEvent(event)">
         <mx:dataProvider>
              <mx:Array>
                   <mx:Object label="Simon Barber" />
                   <mx:Object label="Rich Tretola" />
                   <mx:Object label="John Bennet" />
              </mx:Array>
         </mx:dataProvider>
    </mx:List>

</mx:Application>

Component Instantiation

Component instantiation works as a sequence of steps that occur when you create a component instance from an ActionScript component class.

The easiest way to create an instance of a component is declaring it in MXML. On the other hand, you can do the same process in ActionScript. The following example creates a Button control in ActionScript and adds it to the display list of the Flash Player:

import mx.effects.easing.Back;
import mx.controls.Button;
import mx.containers.VBox;
import mx.core.Container;

private function initUI():void
{
     var vboxContainer:VBox = new VBox();
     addChild(vboxContainer);

     var buttonControl:Button = new Button();
     buttonControl.label = "Click";
     vboxContainer.addChild(buttonControl);
}

The following steps occur when this code is executed:

  1. The constructor of the vboxContainer instance is called.

  2. The addChild() method is called to add the vboxContainer instance to the display list.

  3. The constructor of the buttonControl instance is called.

  4. The buttonControl instance label property is set to the string “Click”.

  5. The vboxContainer instance addChild() method is called to add the buttonControl instance to the display list or stage.

    The following actions are performed internally when the button instance is added to the stage:

    1. The parent property of the component is set to reference its parent container.

    2. The style settings of the component are processed.

    3. The add event for the button is dispatched.

    4. The childAdd event for the parent container is dispatched.

    5. The preinitialize event of the component is dispatched. The component is currently in a very raw state, and the control creates internal child components. For example, the Button control creates the UITextField to show the label text.

    6. The component’s children are created and initialized, including the internal children.

    7. The initialize event is dispatched on the component, of which, at this stage, all children have been initialized, but the component is not fully processed. No sizing or layout has been executed yet.

  6. A render event is dispatched to display the application, and Flex does the following:

    1. All the processing is completed to display the component, including layout of the component.

    2. The visible property is set to true to show the component.

    3. The creationComplete event is dispatched and the component’s size and layout has been processed, including all the properties.

    4. The updateComplete event is dispatched. This event is dispatched whenever the position, size, or other visual characteristics of the component changes.

If you were to remove the component using the removeChild() method, the child’s parent property would be set to null. The Flash Player will delete the component from memory using the garbage collector if there are no references to the component. This happens at an undetermined time when the Flash Player does a sweep to remove objects from memory.

Figure 6-2 shows the following major events that are dispatched in a component’s creation life cycle:

  • The preinitialize event occurs very early in the life cycle of a component to do any initialization. In rare situations, it may come in handy when you must set the properties on a parent before the children are created.

  • The initialize event is useful to configure a component before Flex has determined the visual appearance. So, in other words, use this to set properties that affect its appearance (such as width and height).

  • The creationComplete event should be used to set accurate values on the component (such as the size or position). Using this event to perform actions that change the visual appearance will require Flex to recalculate its layout, which creates unnecessary processing overhead.

  • The updateComplete event should be used to perform actions each time the characteristics of the component change.

Image from book
Figure 6-2: Major events that are dispatched in a component’s creation life cycle

Styling Components

Styling in Flex is defined using Cascading Style Sheets (CSS), which allow you to set the characteristics of components (such as fonts, padding, and alignment). All visual components can define their own styles, but, by default, they are inherited from its superclass. You may notice that some styles are inherited not by the subclass but from the superclass. To find out more about which styles are supported in the visual component, refer to the Adobe Flex 2 documentation.

Styles can be defined in MXML as tag attributes, such as setting the padding between borders of a container or defining the font weight of a TextInput control.

The following example shows a Label control with the fontWeight and fontSize style attributes defined in MXML:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:Label text="Component Styles" fontWeight="bold" fontSize="20" />
</mx:Application>

Styles can also be defined using the <mx:Style> tag in MXML or ActionScript using the setStyle() method. The setStyle() method takes two parameters: the style name (as a String) and the value.

This example uses the ActionScript setStyle() method to set the Label control’s fontWeight and fontSize styles:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns="*"
 creationComplete="initStyles()">

     <mx:Script>
     <![CDATA[

          private function initStyles():void
          {
               myLabel.setStyle("fontWeight", "bold");
               myLabel.setStyle("fontSize", 20);
          }

     ]]>
     </mx:Script>

     <mx:Label id="myLabel" text="Component Styles" />

</mx:Application>

This example uses MXML and the <mx:Script> tag. The styles are set using CSS syntax inline, or using an external file that contains style declarations. The style declaration is referenced in MXML using the styleName tag attribute on the visual component:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Style>

          .myLabelStyle
          {
               font-weight: bold;
               font-size: 20;
          }

     </mx:Style>

     <mx:Label styleName="myLabelStyle" text="Component Styles" />

</mx:Application>

The .myLabelStyle is a CSS class selector style definition that applies only to visual components that have referenced it using the styleName attribute. A type selector applies to all instances of the component type, such as shown in the following example:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:Style>

          Label
          {
               font-weight: bold;
               font-size: 20;
          }

     </mx:Style>

     <mx:Label text="Component Styles" />

</mx:Application>

Adding Behaviors

In Flex, a trigger combined with an effect is called a behavior. A trigger is an action similar to an event, and an effect is a visible change to a component of a specified period of time in milliseconds. Effects are fading, resizing, zooming, or moving a component around the stage. Multiple effects can be defined for a single trigger either in parallel or in sequence.

Triggers are implemented as CSS styles, which means that you can set them as tag attributes in MXML using the <mx:Style> tag or in ActionScript using the setStyle() method.

Behaviors allow you to add animation, sound, and/or motion to your application in response to user or programmatic action.

To create a behavior, you declare a specific effect with a unique id and bind it to the trigger. The following example declares a Fade effect with an id of fadeInstance, which is bound to the creationComplete Effect trigger of the Button control. The Fade effect has an alphaFrom property, which is the initial transparency level between 0.0 and 1.0, where 0.0 means transparent and 1.0 means fully opaque. The alphaTo property is the final transparency level, and also takes a value between 0.0 and 1.0. The duration property is how long the effect takes to finish in milliseconds.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns="*">

     <mx:Fade id="fadeInstance" alphaFrom="0" alphaTo="1" duration="1000" />
     <mx:Button label="Fade Button" creationCompleteEffect="{fadeInstance}" />

</mx:Application>

Applying Skins

Chapter 7 provides more details about skinning in Flex, but for now, this discussion will serve as an introduction. Skins are graphical style elements that dictate the look of visual components. Many components have many skins. For example, the Button control has eight, one for each button state (such as Up, Down, Disabled, Selected, Focus, Over, and so on).

All these elements can be made up of images, SWF files, or class files that use the drawing API methods to achieve the effect. There are two ways to add skins to a Flex component: graphically and programmatically.

Figure 6-3 shows three Button controls: one with the upSkin, another with the overSkin, and, lastly, one with the downSkin.

Image from book
Figure 6-3: Three Button controls

Modifying Components at Run-time

In most languages such as Java or .NET, you can modify the look, size, or position of a component at run-time. Flex also allows you to do the same. You achieve this by using the component properties, styles, or ActionScript methods, including the x and y properties, and width and height properties, and by using the setStyle(stylename:String, value:Object) method.

To use the x and y properties of a component, the parent container of the child must make use of absolute positioning. The Canvas container allows for absolute positioning by default, but the Application, Box, and Panel containers must set the layout property to absolute.

With the x and y properties, you could reposition a TextInput control 10 pixels to the right and 10 pixels down when a user clicks a Button control. The following example shows how this is achieved:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns="*"
 layout="absolute">

     <mx:Script>
          <![CDATA[

               public function moveTextInput():void
               {
                    textInput.x += 10;
                    textInput.y += 10;
               }

          ]]>
     </mx:Script>

     <mx:TextInput id="textInput" x="100" y="10" />
     <mx:Button label="Move" click="moveTextInput()" x="10" y="10" />

</mx:Application>

The width and height properties are useful if you want to resize a component at run-time. In Flex, each component is set to a standard width and height if none are explicitly provided. The following example resizes a TextInput control by 10 pixels using the width and height properties:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns="*"
 layout="absolute">

     <mx:Script>
          <![CDATA[

               public function resizeTextInput():void
               {
                    textInput.width += 10;
                    textInput.height += 10;
               }

          ]]>
     </mx:Script>

     <mx:TextInput id="textInput" x="100" y="10" />
     <mx:Button label="Resize" click="resizeTextInput()" x="10" y="10" />

</mx:Application>

One thing to remember about the width and height properties is that they are always set in pixels, regardless of whether they were originally fixed values, percentages, or not set at all.

Extending Components

In Flex 2, you can create custom components that extend existing or custom components. When you extend existing components, you inherit all the functionality of the base component, plus you can add new properties and methods to it.

The following example is a custom MXML component with a DateField control and TextInput control inside an HBox container. The TextInput control’s text property is bound to the DateField control’s selectedDate property. The filename for this component is MyCustomComponent.mxm, and it is located in a same directory as the application file.

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:DateField id="myDate" />
     <mx:TextInput text="{myDate.selectedDate.toDateString()}" />
</mx:HBox>

To use the custom MXML component in your application, you must specify its filename as an MXML tag, as shown in the following example:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:components="*">
     <components:MyCustomComponent />
</mx:Application>

In this example, the custom component is in the same directory as the application file, which maps to the local namespace indicated by the asterisk.

There are two ways to create custom components in Flex. The method you take depends on your application requirements of the component.

  • Create custom components as MXML files that provide an easy way to extend existing components, modify the behavior, or add basic features to an existing component.

  • Create custom components as ActionScript files by extending the UIComponent class or any of is subclasses. Using ActionScript to create custom components provides greater customization for visual or non-visual components.

For more information regarding creating MXML and ActionScript components, see Chapter 12, “Creating MXML Components,” and Chapter 13, “Flex Component Properties.”


Data Providers and Collections

Many Flex controls use a data provider such as an array or ArrayCollection (for example, the ComboBox control, which reads in a data provider to define the options in the drop-down list). Collection classes are used to represent data providers in Flex, which is a group of objects with a set of methods to access, sort, filter, and modify items in the collection.

This section describes data providers and collection classes, including an introduction to using data providers in controls. Also, you learn how to use collection classes to access and manipulate data.

Data Providers

All List-based controls represent data using a data provider that is an object required by the control to make it function correctly. For example, the DataGrid control requires a data provider to determine the row of items to display to the user.

The following are all the components that use data providers:

  • Tree control

  • DataGrid control

  • ComboBox control

  • List control

  • TileList control

  • Menu control

  • MenuBar control

  • ButtonBar control

  • LinkBar control

  • TabBar control

  • ToggleButtonBar control

  • LineChart control

  • ColorPicker control

  • PopUpMenuButton control

  • HorizontalList control

  • Repeater component

  • DateField control

The easiest way to use a data provider with a control is declare an Array of strings or objects, which is then bound to the control’s dataProvider property. Using a raw data object has its limitations as a data provider, and you should use the collection classes if you have data that changes.

Raw objects do not have the functionality to notify the control when changes to the base object occur. Therefore, the control does not get updated, unless it is redrawn or the data provider is reassigned. Another downside to using raw objects is that they do not provide functionality for accessing, sorting, or filtering data.

The following example shows the difference between using an Array (raw object) and an Array Collection, with both of them bound to separate List controls. There are two Button controls: one calls the addCountryToArray()method, and the other one calls the addCountryToCollection() method. These two methods take the value from the TextInput control and add them to the relevant data providers.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.collections.ArrayCollection;

               [Bindable]
               public var myArray:Array = ["United States", "South Africa", "United
Kingdom"];

               [Bindable]
               public var myCollection:ArrayCollection = new ArrayCollection
(["United States", "South Africa", "United Kingdom"]);

               public function addCountryToArray(country:String):void
               {
                    myArray.push(country);
               }

               public function addCountryToCollection(country:String):void
               {
                    myCollection.addItem(country);
               }

          ]]>
     </mx:Script>

     <mx:TextInput id="countryTextInput" text="Argentina" />
     <mx:Label text="Bound to Array (raw object)" />
     <mx:Button click="addCountryToArray(countryTextInput.text)" label="Add Country
to Array" />
     <mx:List dataProvider="{myArray}" width="200" />

     <mx:Label text="Bound to Collection" />
     <mx:Button click="addCountryToCollection(countryTextInput.text)" label="Add
Country to Collection" />
     <mx:List dataProvider="{myCollection}" width="200" />

</mx:Application>

You will see that the first List control does not reflect the changes when the Button control labeled Add Country to Array is clicked. However, when the Button control labeled Add Country to Collection is clicked, the List control below reflects the changes. The reason for this is that collections notify the control when changes are made to its data.

Collections in Flex provide functionality to ensure data synchronization, simple and yet very sophisticated data access, and manipulation tools. They provide a consistent interface for managing and accessing data of many different types.

Flex supports two basic types of data providers:

  • Linear or listed-based data providers are one-dimensional, and are sometimes referred to as flat data consisting of a number of objects.

  • Hierarchical data providers consist of tree-like structures, with the data source usually being an XML object. Controls that support hierarchical data are the Tree, Menu, MenuBar, and PopUpMenuButton.

The structure defined in hierarchical data providers matches the layout of a tree or cascading menu. A tree usually contains a root node with one or more branches or child nodes, which, in turn, contain branch nodes or children with an ending leaf node.

Controls that support hierarchical data use the data descriptor interfaces to access and manipulate the data providers. You can write your own custom data descriptor if your hierarchical data does not support the format described by the DefaultDataDescriptor class. Once you have successfully implemented all the interfaces in your custom data descriptor, you can specify them in the hierarchical control’s dataDescriptor property.

The ArrayCollection or XMLListCollection class and the ICollectionView or IList interface can be used to access or manipulate hierarchical data dynamically.

Collections

Collections are more robust than plain Arrays because they provide functionality that includes adding and removing objects, as well as sorting and filtering the data. They also support change notification, which keeps data synchronized across an application.

Collection interfaces provide the following features:

  • They ensure that the control is updated properly when underlying data changes.

  • They provide handling of paged data coming from remote data providers that may not initially be available.

  • They contain a set of operations for handling data that is independent of those found in raw data providers such as an Array.

  • The collections that implement the ICollectionView interface provide a view of the data that can be sorted or filtered by a custom method. These features affect the collection’s view and not the underlying data.

  • Multiple components can use the same collection as their data provider.

  • Collections can be modified so that changes are reflected by all the components that use the data provider.

The following example shows you how to define a collection in MXML:

<mx:ArrayCollection id="myArrayCollection">
     <mx:source>
          <mx:Array>
               <mx:String>United States</mx:String>
               <mx:String>South Africa</mx:String>
               <mx:String>United Kingdom</mx:String>
          </mx:Array>
     </mx:source>
</mx:ArrayCollection>

You can do the same in ActionScript as long as you import the mx.collections.ArrayCollection class. To initialize the ArrayCollection with data, you must pass an Array into the constructor, as shown in the following example:

import mx.collections.ArrayCollection;

[Bindable]
public var myCollection:ArrayCollection = new ArrayCollection(["United States",
"South Africa", "United Kingdom"]);

If an instance of the ArrayCollection is created without passing in an Array to the constructor, you can set it to the source property at a later stage.

var myArray:Array = ["United States", "South Africa", "United Kingdom"];
myCollection.source = myArray;

ArrayCollections can be bound to a chart control and updated in real time because collections support notification changes. The following example does exactly this. A timer is set to run every 1000 milliseconds, which, in turn, adds a new object to the ArrayCollection, which reflects in the ColumnChart control. The object’s number property is set to a random number between 0 and 100.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 initialize="initTimer()">

     <mx:Script>

     import mx.utils.UIDUtil;
     import flash.utils.Timer;
     import flash.events.TimerEvent;
     import mx.collections.ArrayCollection;

     [Bindable]
     public var myCollection:ArrayCollection = new ArrayCollection();

     public function initTimer():void
     {
          var myTimer:Timer = new Timer(1000, 0);
          myTimer.addEventListener("timer", timerHandler);
          myTimer.start();
     }

     public function timerHandler(event:TimerEvent):void
     {
          var o:Object = new Object();
          //o.uid = UIDUtil.createUID();
          o.number = Math.random() * 400;
          myCollection.addItem(o);
     }

     </mx:Script>
     <mx:SeriesInterpolate id="interpolateIn" duration="500" />

     <mx:ColumnChart id="column" height="100%" width="100%"
          paddingLeft="5" paddingRight="5"
          showDataTips="true" dataProvider="{myCollection}">

          <mx:horizontalAxis>
               <mx:CategoryAxis categoryField="number" />
          </mx:horizontalAxis>

          <mx:horizontalAxisRenderer>
               <mx:AxisRenderer showLabels="false" />
          </mx:horizontalAxisRenderer>

         <mx:series>
              <mx:ColumnSeries yField="number" showDataEffect="{interpolateIn}" />
         </mx:series>
     </mx:ColumnChart>

</mx:Application>

Collection Interfaces

In the Flex Framework, the collection model uses the following interfaces to define how collections represent data, provide access to it, and manipulate them:

  • IList - A collection of items organized in an ordinal fashion. Provides access and manipulation methods based on the index. The interface does not provide sorting, filtering, or cursor functionality.

  • ICollectionView - A view onto a collection of data. It can be modified to show the data sorted according to certain criteria, or be reduced by filters without modifying the underlying data. The interface provides access to an IViewCursor object to access the items.

  • IViewCursor - The interface for enumerating over a collection view bidirectionally. The cursor provides find, seek, and bookmarking functionality.

IList and ICollectionView interfaces allow developers access to two alternative methods for accessing and manipulating data. The IList interface is a simple interface that provides adding, setting, getting, and removing operations on linear data.

The ICollectionView interface, however, provides more complex functionality than the IList interface, and is appropriate if the underlying data is organized in a non-linear fashion. The collection that implements the ICollectionView interface can represent a subset of data by using the sort or filtering operations.

The ArrayCollection and XMLListCollections classes implement both the IList and ICollectionView interfaces.

IList Interface

The IList interface contains simple methods for linear data access using an index. Anything you change in the collection changes the data provider. For example, inserting an item at an index of two will also reflect as the second item in the underlying data source. The following can be achieved with the IList interface:

  • Get, set, add, or remove an item at a specific index from the collection.

  • Add an item at the end of the collection.

  • Get an index of an item in the collection.

  • Get the amount of items in the collection.

  • Remove all the items from the collection.

ICollectionView

The ICollectionView is a view of the underlying data source that represents a collection of items. The interface is more complex than that of the IList interface. The following can be achieved with the ICollectionView interface:

  • Modify the view to show data in a sorted order, or show only a subset of the items using the filtering capabilities without changing the underlying data.

  • Move through the collection, use bookmarks to save locations in the collection, and add and remove items by accessing the data using a cursor.

  • Represent remote data that might not initially be available yet, or the dataset that may become available at different times.

Sorting Collections

The Sort class allows you to sort on data in collections. Multiple fields are supported when sorting data, and require that the entries be unique. A custom comparison function can be used to order the sorted output, and the Sort class can also search for item in the collection. If you apply a sort instance to the collection, you are required to call the refresh() method of the collection to apply the changes.

The SortField class is used to specify the fields to use in the sort. You create an instance of the SortField class and add it to the fields array property of the Sort class instance. All the SortField instances of the collection must be unique.

The following example sorts an ArrayCollection in descending order. The primary sort is on the label field of the collection, case-sensitive, and in descending order.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>

          import mx.collections.SortField;
          import mx.collections.Sort;
          import mx.collections.ArrayCollection;

          [Bindable]
          public var myCollection:ArrayCollection = new ArrayCollection([{label:
"A"}, {label: "B"}, {label: "C"}, {label: "D"}, {label: "E"}]);

          public function sortCollection():void
          {
               var sort:Sort = new Sort();
               sort.fields = [new SortField("label", true, true)];
               myCollection.sort = sort;
               myCollection.refresh();
          }

     </mx:Script>

     <mx:List dataProvider="{myCollection}" width="200" />
     <mx:Button label="Sort Collection" click="sortCollection()" />

</mx:Application>

Filtering Collections

Filtering limits the ICollectionView to a subset of the data provider’s underlying data. You define a function that takes a single Object parameter and returns a Boolean value to specify whether to include the item in the view. The same step applies with sorting as it does with filtering. You must call the refresh() method of the collection when you set the filter function.

The following example uses both filtering and sorting of an ArrayCollection. There are two Button controls to apply the sort and filtering, respectively, and one to reset the view to its original state.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

          import mx.collections.SortField;
          import mx.collections.Sort;
          import mx.collections.ArrayCollection;

          public function sortCollection():void
          {
               var sort:Sort = new Sort();
               sort.fields = [new SortField("label", true, true)];
               myCollection.sort = sort;
               myCollection.refresh();
          }

          public function filterCollection():void
          {
               myCollection.filterFunction = stateFilterFunc;
               myCollection.refresh();
          }

          private function stateFilterFunc(item:Object):Boolean
          {
               return item.label >= "A" && item.label < "N";
          }

          public function resetCollection():void
          {
               myCollection.filterFunction = null;
               myCollection.sort = null;
               myCollection.refresh();
          }

          ]]>
     </mx:Script>

     <mx:ArrayCollection id="myCollection">
          <mx:Array>
               <mx:Object label="LA" data="Baton Rouge"/>
               <mx:Object label="NH" data="Concord"/>
               <mx:Object label="TX" data="Austin"/>
               <mx:Object label="MA" data="Boston"/>
               <mx:Object label="AZ" data="Phoenix"/>
               <mx:Object label="OR" data="Salem"/>
               <mx:Object label="FL" data="Tallahassee"/>
               <mx:Object label="MN" data="Saint Paul"/>
               <mx:Object label="NY" data="Albany"/>
          </mx:Array>
     </mx:ArrayCollection>

     <mx:List dataProvider="{myCollection}" width="200" />
     <mx:Button label="Sort Collection" click="sortCollection()" />
     <mx:Button label="Filter Collection" click="filterCollection()" />
     <mx:Button label="Reset" click="resetCollection()" />

</mx:Application>

IViewCursor Interface

The IViewCursor interface defines the functionality to enumerate over a collection view. The ICollectionView interface contains a createCursor() method that returns an IViewCursor object referred to as a cursor. The cursor is used to transverse the items in the view, as well as to access and manipulate data. It is a position indicator that points to a particular item in the collection.

The IViewCursor interface has the following methods and properties to perform the following operations:

  • Move the cursor backward and forward.

  • Move it to specific items.

  • Get the item at a cursor location.

  • Add, remove, and change items.

  • Save the cursor as a bookmark so that you can return to it at a later stage.

To use the ICollectionView interface, you must access it by calling the method of a collection instance, as shown in the following code snippet:

public var myArrayCollection:IViewCursor;
public var myCursor:IViewCursor;

public function getCursor():void
{
     myCursor = myArrayCollection.createCursor();
}

The moveNext() and movePrevious() methods are used to move the cursor forward and backward by one item at a time. To check whether you have reached the bounds of the collection, use the beforeFirst and afterLast properties.

To search within the collection, you can use the findAny(), findFirst(), and findLast() methods that match the parameter, but you must apply a Sort to the ICollectionView instance. It is important to note that if you do not need to find the first or last occurrence of an item in the collection, the findAny() method is more efficient than the findFirst() and findLast() methods.

To find the last occurrence of an item in the collection, you must apply a Sort, as the following example shows:

var sort:Sort = new Sort();

// the null parameter on the SortField constructor specifies a collection of simple
objects (String, Boolean or numeric)
sort.fields = [new SortField(null, true)];
myCollection.sort = sort;
myCollection.refresh();
myCursor.firstLast("NY");

You can search for a complex object using the findLast() method on multiple sort fields. However, you cannot skip fields in any of the find methods. If the object has three fields, you can specify the combinations 1 or 1, 2 or 1, 2, 3 as a parameter, but not 1, 3. The following code will find the last object with a label field "NY" and a data field “New York”:

myCursor.firstLast({label: "NY", data: "New York"});

The seek() method moves the cursor to a location at an offset from the specified bookmark. You can move to the first and last element in the collection, or to the last bookmark you saved.

The IViewCursor interface has methods and properties to access and manipulate data. The current property is a reference to the item at the current cursor location. The insert() method adds an item before the cursor’s current position, and the remove() method removes the current item and returns a reference to it. When inserting an item using the insert() method of the IViewCursor interface and the collection view is sorted, the inserted item will move to the sorted location and not the cursor location.

Collection Change Events

Collections have a mechanism that provides feedback to the developer whenever changes occur to the data within the collection. Any class that implements the IList or ICollectionView interface dispatches a CollectionEvent class event whenever the collection changes.

The CollectionEvent class contains a kind property that indicates the way in which the collection has changed. To determine this, you compare the kind property to the value of the CollectionEventKind class constants, such as CollectionEventKind.ADD.

The CollectionEvent class contains another useful property, items, which is an Array of objects whose type varies depending on the event kind property. If it is the ADD and REMOVE event, the array contains the added or removed items. If it is the UPDATE event, the items property contains an Array of PropertyChangeEvent event objects. This object contains the type of change and the property value before and after the change.

The PropertyChangeEvent class kind property indicates the way in which the property changed. This is determined by the comparing the kind property value with the PropertyChangeEventKind constants. The constants can either be UPDATE or DELETE.

The collection events are used to monitor changes to the collection, which, in turn, is used to update the display. If you have a custom control that uses a collection as its data provider, you can listen for the change events on the collection and update the custom control accordingly.

The following example lets you add, remove, and replace items in a list control. An event handler is registered to the collectionChange event of the ArrayCollection instance. Any time an item is added, removed, or replaced, a message is logged in the TextArea control.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:local="*">

    <mx:Script>
         <![CDATA[

              import mx.events.CollectionEventKind;
              import mx.events.CollectionEvent;

              public var index:Number = 0;

              public function collectionChange(event:CollectionEvent):void
              {
                   switch(event.kind)
                   {
                        case CollectionEventKind.ADD:
                             myTextArea.text += "Item Added\n";
                             break;
                        case CollectionEventKind.REPLACE:
                             myTextArea.text += "Item Replaced\n";
                             break;
                        case CollectionEventKind.REMOVE:
                             myTextArea.text += "Item Removed\n";
                             break;
                   }
              }

              public function addItem():void
              {
                   myCollection.addItem({label: myTextInput.text, data: index});
                   index++;
              }

              public function updateItem():void
              {
                   if (myList.selectedItem != null)
                        myCollection.setItemAt({label: myTextInput.text, data:
index}, myList.selectedIndex);
              }

              public function removeItem():void
              {
                   if (myList.selectedItem != null)
                        myCollection.removeItemAt(myList.selectedIndex);
              }

         ]]>
    </mx:Script>

    <mx:ArrayCollection id="myCollection" collectionChange=
"collectionChange(event)" />

    <mx:TextInput id="myTextInput" />
    <mx:List id="myList" dataProvider="{myCollection}" width="200" height="300" />
    <mx:Button label="ADD" click="addItem()" />
    <mx:Button label="UPDATE" click="updateItem()" />
    <mx:Button label="REMOVE" click="removeItem()" />
    <mx:TextArea id="myTextArea" width="200" height="300" />

</mx:Application>

Hierarchical Data Providers

The structure of hierarchical data providers is more advanced than your typical linear data providers (such as an Array). They display data in a nested hierarchy of nodes and subnodes like a tree with branches and leaves. In Flex, there are a few controls that accept hierarchical data providers, including the Menu, MenuBar, PopUpMenuButton, and Tree controls.

Your typical hierarchical data sources are XML, which can be Strings containing well-formed XML, or XML, XMLList, or XMLCollection objects. Objects that have nested objects (including Arrays or ArrayCollection objects) are also considered hierarchical data sources. The structure must have the children in the children field of the data source. Otherwise, you must create your own custom data descriptor class. This will allow you to support other hierarchical data provider structures with custom field names other than the children field.

Data Descriptors

A data descriptor class is used to parse the hierarchical data used in Tree- and Menu-based controls. It provides an interface between the hierarchical control and the data provider object. Flex has two types of data descriptor interfaces for hierarchical controls. The ITreeDataDescriptor is used by the Tree controls, and the IMenuDataDescriptor is used for the Menu, MenuBar, and PopUpMenuButton controls.

Flex provides a DefaultDataDescriptor class that implements both of the interfaces just mentioned. You can specify a custom data descriptor by assigning a new one to the dataDescriptor property of the hierarchical controls. The only reason you would want to define a custom data descriptor is if your data models do not conform to the default descriptor structure.

XML Data Provider

In most cases, the data for a Tree control is retrieved from a server in the form of XML, but can also be defined within the <mx:Tree> tag. The <mx:XML> or <mx:XMLList> tag can be used to define an XML or XMLList object in MXML, and lets you use binding expressions in the XML nodes.

The following example shows MXML binding in an <mx:XMLList> tag:

<mx:XMLList id="myXMLList">
     <node label="{myTextInput.text}" />
     <node label="{myTextArea.text}" />
</mx:XMLList>

If your data provider for a hierarchical control is going to be dynamic, you should use the XMLList Collection object instead of the XML or XMLList object. This ensures that your component will represent any changes made to the data provider. The XMLListCollection class supports the IList and ICollectionView interface methods for manipulating data at run-time.

The following example uses two Tree controls, two XMLListCollection objects, and a Button control to copy an object in the one XMLListCollection object to the other:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:local="*">

    <mx:Script>
         <![CDATA[

              private function addItem():void
               {
                    if (myTree.selectedItem)
                         myXMLListCollection2.addItem(myTree.selectedItem);
               }

         ]]>
    </mx:Script>

    <mx:XMLListCollection id="myXMLListCollection1">
          <mx:XMLList>
               <node name="SubFolder1" icon="folder">
                   <node name="Personal.xls" icon="spreadsheet" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Spreadsheet" />
                   <node name="Marketing.ppt" icon="presentation" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="PowerPoint" />
                   <node name="Product Management.doc" icon="document" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Document" />
                   <node name="Personal.xls" icon="spreadsheet" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Spreadsheet" />
              </node>
              <node name="SubFolder1" icon="folder">
                   <node name="Marketing.ppt" icon="presentation" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="PowerPoint" />
                   <node name="Product Management.doc" icon="document" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Document" />
                   <node name="Personal.xls" icon="spreadsheet" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Spreadsheet" />
                   <node name="Marketing.ppt" icon="presentation" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="PowerPoint" />
                   <node name="Product Management.doc" icon="document" size="1024"
modified="Fri Sep 29 16:47:59 GMT+0200 2006" type="Document" />
              </node>
          </mx:XMLList>
    </mx:XMLListCollection>

    <mx:XMLListCollection id="myXMLListCollection2" />

    <mx:Tree id="myTree" dataProvider="{myXMLListCollection1}" width="200"
height="300" showRoot="false" labelField="@name" />
    <mx:Button label="Add" click="addItem()" />
    <mx:Tree dataProvider="{myXMLListCollection2}" width="200" height="300"
labelField="@name" />

</mx:Application>

Remote Data Providers

The Remote Procedure Call (RPC) components provide Flex with the functionality to call remote servers to retrieve data for use in your application. The components that are provided with Flex are the HTTPService, WebService, and RemoteObject components.

The following example is a basic application that uses the HTTPService component to download the list of featured videos from the video-sharing site, YouTube:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:local="*"
     creationComplete="srv.send()">

    <mx:Script>
         <![CDATA[

              import mx.rpc.events.ResultEvent;
              import mx.utils.ArrayUtil;
              import mx.collections.ArrayCollection;
              import mx.utils.ObjectUtil;

              [Bindable]
              public var videos:ArrayCollection;

              public function handleResult(event:ResultEvent):void
              {
                   videos = event.result.ut_response.video_list.video;
              }

         ]]>
    </mx:Script>

    <mx:HTTPService id="srv" url="http://www.youtube.com/api2_rest?method=
youtube.videos.list_featured&amp;dev_id=x01oc-ASJRM"
         useProxy="false"
         result="handleResult(event)" />

    <mx:List width="500" height="100%" dataProvider="{videos}">
         <mx:itemRenderer>
              <mx:Component>
                   <mx:HBox height="105" verticalAlign="middle"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
                        <mx:Image source="{data.thumbnail_url}" />
                        <mx:VBox width="100%" height="100%" verticalScrollPolicy=
"off" horizontalScrollPolicy="off">
                             <mx:Label text="{data.title}" fontFamily="Arial"
fontSize="12" fontWeight="bold" />
                             <mx:Text text="{data.description}" width="100%" />
                        </mx:VBox>
                   </mx:HBox>
              </mx:Component>
         </mx:itemRenderer>
    </mx:List>

</mx:Application>


Positioning and Sizing Components

In Flex, the controls are laid out using a set of rules that are a combination of sizing rules for individual components, and sizing and positioning rules for containers. Automatic layout is supported in Flex, which lets you concentrate on building the logic for your application; if need be, you can always adjust the dimensions at a later stage.

Many controls and containers have default layout rules, but you can use the component’s properties and methods to customize it yourself. Every Flex component has several properties (such as width and height) to adjust the size of the component. Containers also have properties and styles that you can use to configure their layout, including the verticalAlign and horizontalAlign properties to set the alignment of their children. Flex also allows you to position children using the x and y properties of the container. Only containers that support absolute positioning (including the Canvas container) allow for this.

Layout of Components

The Layout Manager has the job of controlling the layout in Flex. The manager has a three-step process in which it sizes and lays out components in the application:

  1. Commitment pass - Determines the properties of the application components. During this pass, the Layout Manager causes each component to execute its commitProperties() method, which determines the property values.

  2. Measurement pass - Calculates the default size of every component in the application. This starts from the most deeply nested components and works its way out toward the Application container. During this pass, the Layout Manager causes each component to execute its measureSizes() method, which calls the measure() method to determine its default size.

  3. Layout pass - This pass lays out your application, including resizing and moving of any components. This starts from the outermost container and moves to the innermost container, determining the actual size and placement of each component. During this pass, the Layout Manager causes each component to execute its updateDisplayList() method to lay out the component’s children.

Component Sizing

The layout phase and measurement determine a component’s width and height, and you can retrieve these dimensions by using the width and height properties. The following properties (and others not listed here) are used to control the sizing of components:

  • Default sizing - The size of the controls and containers are determined automatically.

  • Explicit sizing - You set the width and height properties to an absolute value.

  • Percentage-based sizing - You specify the component size as a percentage of its container size.

  • Constraint-based layout - You control the size and position by anchoring the component sides to the container.

There are several ways to control the size of components. This section describes the basic sizing properties, how to determine component sizes, how to use automatic, explicit, and percentage-based sizing, and various techniques for controlling component size.

Sizing Properties

You will find that there are several properties affecting the size of components in Flex. The general rule is that you only need to use a few properties for most applications, but a knowledge of these properties can help you understand how the underlying sizing mechanism works in Flex.

If you are not creating custom components, you would use the following basic properties to specify how a component is sized:

  • The width, height, percentWidth, and percentHeight properties specify the width and height of a component. Using the MXML tags, you can use the width and height properties to specify the dimensions in pixels and as a percentage of the parent container. When using ActionScript, you use the width and height properties to specify the dimensions in pixels, and use the percentWidth and percentHeight properties to specify the dimensions as a percentage of the parent container.

  • The minWidth, minHeight, maxWidth, and maxHeight properties specify the minimum and maximum dimensions that a component can have in Flex. If you explicitly set the width and height properties, these properties have no effect.

Default Sizing

As a rule of thumb, you should determine whether a component’s default size is appropriate for your application. If you decide that default sizing is sufficient, you do not have to specify an explicit or percentage-based size.

The following example uses default sizing for the Button control:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:VBox width="400" height="300">
          <mx:Button label="Button 1" />
     </mx:VBox>

</mx:Application>

Explicit Sizing

To use explicit sizing, you specify the width and height properties of a component to set its size:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:VBox width="100" height="100">
          <mx:Button label="Button 1" width="150" />
     </mx:VBox>

</mx:Application>

You may notice that the VBox container is smaller than the Button control. Flex will clip the Button control to the container’s boundary and display a scroll bar so that you can scroll the container to view the clipped content. The scroll bars will not be visible if you specify the verticalScrollPolicy and horizontalScrollPolicy properties of the container to off.

Component Positioning and Layout

During the initialization phase, Flex will position the components appropriately, and also perform a layout pass to position or reposition components in the application.

Flex provides two mechanisms regarding the positioning and layout of controls:

  • Automatic positioning - Flex automatically positions the children within the container according to a set of container- and component-specific rules.

  • Absolute positioning - The children’s x and y properties are set by the developer, or you can use a constraint-based layout that specifies the gap between each child in the container. This type of positioning is occasionally referred to as absolute layout.

There are three containers that support absolute layout or positioning. The Application and Panel containers use automatic positioning by default, but you can set the layout property to absolute. The third one is the Canvas container, which always uses absolute positioning.

Layout Rules

Flex has a set of rules that are used to perform the layout of components. You should be able to understand the details of Flex layout if you can remember these rules. These rules will give you an understanding of why Flex lays out your application the way it does. This will help you when you need to modify the appearance of your application.

  • Flex first determines all components’ measured or explicitly set sizes, up from the innermost child controls to the outermost Application control. This is all done in the measurement pass.

  • After the measurement pass, Flex determines all percentage-based sizes and lays out components down from the outermost container to the innermost controls. This is done in the layout pass.

  • Sizes that you set to a pixel value are mandatory and fixed, and override any maximum or minimum size specifications that you set for the component.

  • The default sizes determined in the measurement pass specify the sizes of components that do not have explicit or percentage-based sizes (or use constraint-based layout), and are fixed.

  • Percentage-based size specifications are advisory. The layout algorithms satisfy the request if possible, and use the percentage values to determine proportional sizes. However, the actual sizes can be less than the requested sizes. Percentage-based sizes are always within the component’s maximum and minimum sizes, and, subject to those bounds, don’t cause a container’s children to exceed the container size.

Forcing Layout Manually

In rare instances, you may need to programmatically force Flex to lay out components again. Usually, Flex will delay processing of properties that require substantial computation until the scripts that caused them to be set finish executing. For example, if you set the width property of a component or container, it will be delayed because Flex prevents it from happening multiple times.

Sometimes you may want to force the layout before the script has completed. To force the layout, you need to call the validateNow() method of the component. This will cause Flex to validate the properties, sizes, and layout of the object and all of its children. This method is processor-intensive and should be used cautiously if it is needed.

Constraint-based Layout

Constraint-based layout allows you to anchor sides or the center of the component to a position relative to the viewable region of the component’s container.

With constraint-based layout, you can anchor one or more corners of a component at a specific pixel offset from the container’s corresponding edge. The anchored child stays at the specific pixel offset even if the container is resized. If the anchor is set to top and bottom, then when the container resizes, the component will resize with it.

To use constraint-based layout in your application, you must adhere to the following rules:

  • Place the component inside a container that supports absolute layout (such as a Canvas container) or inside an Application or Panel container with the layout property set to absolute.

  • Any component that extends the UIComponent class also supports constraint-based layout.

  • Specify the top, bottom, left, right, verticalCenter, or horizontalCenter styles.

  • Do not specify a top or bottom style with a verticalCenter style, because the verticalCenter style overrides the other properties. The same applies to the left or right styles with a horizontalCenter style.

  • Using constraint-based layout will override an explicit or percentage-based sizing. Specifying the top and bottom constraints will override any height or percentHeight properties.

The following basic example shows a Button control anchored 10 pixels from the bottom of the VBox container:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Canvas width="200" height="100" borderStyle="solid">
          <mx:Button label="Button 1" bottom="10" />
     </mx:Canvas>

</mx:Application>


Getting Familiar with Flex Controls

In Flex, controls are referred to as user interface (UI) components such as Button, TextInput, and ComboBox controls. There are two types of controls in Flex:

  • Basic controls (such as a Button)

  • Data provider–based controls (such as a List)

Controls are typically placed into containers, which are components that provide a hierarchical structure for controls. The <mx:Application> tag is the root of your Flex application. This represents a base container that covers the entire Flash Player drawing area. You can place controls or containers directly onto this area.

Controls have the following characteristics.

  • Declare the control in MXML and specify its properties and events.

  • Use the ActionScript API to call the control’s methods and set its properties at run-time.

  • Customize the visual appearance by using the styles, skins, and fonts of the controls.

The easiest way to add a control to your Flex application is using the MXML API. To achieve this, you must specify the control’s MXML tag, as the following example shows:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Button label="Button 1" />

</mx:Application>


Summary

In this chapter, you learned about the most important elements in creating rich user interfaces for your Flex applications. The most interesting topics were visual components, data providers and collections, sizing and positioning of components, and constraint-based layout. These topics will stand you in good stead on the road to developing Rich Internet Applications using Flex 2.

Chapter 7 discusses improving the user experience by adding functionality to your applications. The topics covered are behaviors, styles, fonts, skinning, item renderers and editors, tooltips, and the Cursor Manager.


Chapter 7: Customizing the User Interface

This chapter discusses how to improve the user experience by adding functionality to your application and, more importantly, the user interface (UI). You are introduced to effects and behaviors, styles and themes, fonts, skins, item renderers and editors, tooltips, and cursor management.

Applying Behaviors

A combination of a trigger paired with an effect is called a behavior. A trigger is an action such as a mouse click on a button, or a component receiving focus or becoming visible. An effect is a visible change to a component that occurs within a specific duration measured in milliseconds. Fading, moving, or zooming a component are examples of various effects.

Behaviors allow you to add animation and motion to your application in response to user or programmatic action. For example, you could create a menu similar to the Apple Mac OS X Dock, which grows in size if your mouse gets close to the icons.

You can define multiple effects to play in response to a single user or programmatic action. A good example of this would be the Apple Mac OS X Dock in hide mode. When you move your mouse close to the Dock, it appears and the icons grow depending on your mouse position. Flex components do not play an effect when a trigger occurs, but some components do indirectly, as when the ComboBox control’s drop-down list slides down when you click it.

Note that triggers are not the same as events, because if you look at the properties of a Button control, for example, it contains a mouseUp event and a mouseUpEffect trigger. The mouseUpEffect trigger is associated with an effect, so that when the mouseUp event occurs, an effect is run.

Using Behaviors

In MXML, you use the name of the effect to assign it to the trigger property of the component:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Fade id="myFadeOut" alphaFrom="1" alphaTo="0" />
     <mx:Fade id="myFadeIn" alphaFrom="0" alphaTo="1" />

     <mx:Button label="Button 1" mouseDownEffect="{myFadeOut}" mouseUpEffect=
"{myFadeIn}" />

</mx:Application>

This code example declares two effects, one fading from fully opaque to fully transparent, and the other effect in reverse. So, when a user clicks the button, it disappears and reappears when the mouse button is released.

In MXML, all properties that are effect triggers are implemented in Cascading Style Sheets (CSS) styles. Therefore, you can apply the effect using the <mx:Style> tag. The following code example is the same as the preceding example, but it uses CSS styles, instead:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Style>

          Button
          {
               mouseDownEffect: myFadeOut;
               mouseUpEffect: myFadeIn;
          }

     </mx:Style>

     <mx:Fade id="myFadeOut" alphaFrom="1" alphaTo="0" />
     <mx:Fade id="myFadeIn" alphaFrom="0" alphaTo="1" />

     <mx:Button label="Button 1" />

</mx:Application>

You could also use the setStyle() and getStyle() methods to manipulate triggers and their associated effects.

In ActionScript, you can declare play effects often as part of an event listener. To invoke the effect, you call the play() method. The following example resizes a Panel container:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.effects.Resize;

               public function resizePanel():void
               {
                    var myResize:Resize = new Resize();
                    myResize.target = myPanel;
                    myResize.widthBy = 100;
                    myResize.heightBy = 100;
                    myResize.play();
               }

          ]]>
     </mx:Script>

     <mx:Panel id="myPanel" />

     <mx:Button label="Resize" click="resizePanel()" />

</mx:Application>

Instead of specifying the target property of the Resize effect, you could pass in the myPanel instance as an array into the play() method of the resize effect instance:

myResize.play([myPanel]);

Embedded Fonts with Effects

The Fade, Dissolve, and Rotate effects work only with text that is rendered using embedded fonts. Nothing will happen to the text if system fonts are used.

Tip

Embedded fonts are discussed in more detail later in this chapter.

When applying a Zoom effect to text rendered with system fonts, Flex will scale the text between whole point sizes. In essence, you do not have to use embedded fonts with the Zoom effect, but it will appear smoother if you do.

Composite Effects

You can combine or composite effects either by using the Parallel or Sequence effect. The Parallel effect plays the child effects at the same time, and the Sequence effect plays them sequentially.

The following example defines Parallel and Sequence effects with the same child effects. The Parallel effect resizes the Panel container and blurs it at the same time, whereas the Sequence effect resizes the Panel container and, once that is finished, removes the blur.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Parallel id="parallelEffect" target="{myPanel}">
          <mx:Resize widthBy="150" heightBy="150" />
          <mx:Blur blurXTo="5" blurYTo="5" />
     </mx:Parallel>

     <mx:Sequence id="sequenceEffect" target="{myPanel}">
          <mx:Resize widthBy="-150" heightBy="-150" />
          <mx:Blur blurXTo="0" blurYTo="0" />
     </mx:Sequence>

     <mx:Panel title="Panel" id="myPanel" width="100" height="100" />

     <mx:Button label="Parallel Effect" click="parallelEffect.play()" />
     <mx:Button label="Sequence Effect" click="sequenceEffect.play()" />

</mx:Application>

Easing Functions

In Flex, you can change the speed of an animation by defining an easing function for an effect. This allows you to create a more realistic rate of acceleration and deceleration. The easing function also includes the functionality to make objects look like they are bouncing.

The following code shows the basic format of an easing function:

function myEasingFunction(t:Number, b:Number, c:Number, d:Number):Number {}

Note the following:

  • The t specifies time.

  • The b specifies the initial position of a component.

  • The c specifies the total change in position of the component.

  • The d specifies the duration of the effect in milliseconds.

Easing functions can be found in the mx.effects.easing.* package.

The following example is the same as the last code example regarding composite effects, except an easing function has been applied to the Resize effect by setting the easingFunction property:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[
               import mx.effects.easing.Exponential;
          ]]>
     </mx:Script>

     <mx:Parallel id="parallelEffect" target="{myPanel}">
          <mx:Resize widthBy="150" heightBy="150" easingFunction=
"{Exponential.easeOut}" />
          <mx:Blur blurXTo="5" blurYTo="5" />
     </mx:Parallel>

     <mx:Sequence id="sequenceEffect" target="{myPanel}">
          <mx:Resize widthBy="-150" heightBy="-150" easingFunction=
"{Exponential.easeInOut}" />
          <mx:Blur blurXTo="0" blurYTo="0" />
     </mx:Sequence>

     <mx:Panel title="Panel" id="myPanel" width="100" height="100" />

     <mx:Button label="Parallel Effect" click="parallelEffect.play()" />
     <mx:Button label="Sequence Effect" click="sequenceEffect.play()" />

</mx:Application>

You can also apply easing functions to controls such as the ComboBox control by specifying the openEasingFunction and/or closingEasingFunction. The following example shows how this is done:

<mx:ComboBox openEasingFunction="{Exponential.easeOut}" closeEasingFunction=
"{Exponential.easeInOut}">
          <mx:dataProvider>
               <mx:ArrayCollection>
                    <mx:Array>
                         <mx:Object label="Simon Barber" />
                         <mx:Object label="Rich Tretola" />
                         <mx:Object label="Renaun Eriksson" />
                    </mx:Array>
               </mx:ArrayCollection>
          </mx:dataProvider>
     </mx:ComboBox>


Applying Styles

Styles are useful for defining the look and feel of your Flex application. You use them to change the appearance of a single component, or across all components by using Cascading Style Sheets (CSS).

To modify the appearance of components, you use style properties similar to those in CSS. These properties define the size of a font, background color, or the size of the border in a Panel container. Some styles are inherited from parent containers to their children, and across style types and classes. This allows you to define a style once that then applies to all controls of a single type or set of controls. Also, you can override individual properties for each control at a local, component, or a global level, leaving you with greater flexibility in the appearance of your application.

Flex does not allow you to control all aspects of your component layout with CSS. Properties such as width, height, x, and y are not styles of the UIComponent class. As you may remember, the UIComponent class is the base class for all visual components in Flex.

Using Styles

You use CSS to apply styles to a document or across an entire application. The one way to apply styles is by referring to an external style sheet, or including them inline within the MXML document.

The following example applies an external style sheet myStyleSheet.css to the current document:

<mx:Style source="myStyleSheet.css" />

If you prefer to use styles inside the document or inline, use the <mx:Style> tag. This will apply the styles to your current document and its children. The following example defines a new style and applies it only to that instance of a Label control:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Style>

          .myLabel
          {
               font-size: 16;
               font-family: Arial;
               font-weight: bold;
               color: #FFCC00;
          }

     </mx:Style>

     <mx:Label text="Styled Label" styleName="myLabel" />

</mx:Application>

This example defines a new style that applies to all instances of a Label control:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Style>

          Label
          {
               font-size: 16;
               font-family: Arial;
               font-weight: bold;
               color: #FFCC00;
          }

     </mx:Style>

     <mx:Label text="Styled Label" />

</mx:Application>

You can use the setStyle() and getStyle() methods of a control to manipulate style properties. Using these methods does require more processing power on the client than using style sheets, but it provides greater control over how you apply styles.

myLabel.setStyle("fontWeight", "bold");

Lastly, you can use attributes of MXML tags to apply styles inline and apply only to the instance of the control. This is the most efficient method of applying instance properties because no ActionScript code blocks or method calls are required.

The following example sets the fontWeight style of the myLabel instance to bold:

<mx:Label id="myLable" text="Styled Label" fontWeight="bold" />

Note that you must use the camel-case version of the style property in an MXML tag. For example, you must use fontSize and not font-size. You can also bind inline style properties to values.

Using Local, Application, and Global Selectors

The <mx:Style> tag contains style sheet definitions that adhere to the CSS 2.0 syntax and apply to the current document and all of its children in the current document. To define a local style, you would use the class selector. Any component that wants to use the style must refer to it in its styleName property.

The following example defines a type and class selector in the <mx:Style> tag:

<mx:Style>

          .myClass /* class selector */
          {
               font-size: 16;
               font-family: Verdana;
               font-weight: bold;
               color: #FFCC00;
          }

          Label /* type selector */
          {
               font-size: 16;
               font-family: Verdana;
               font-weight: bold;
               color: #FFCC00;
          }

</mx:Style>

Application Type Selector

The Application container is the root of your Flex application and is the top-most document. Any styles defined in the Application type selector are inherited by all the container’s children, as well as the container’s subclasses. Styles that are not inheritable are applied only to the Application container and not its children.

Styles applied in the Application type selector that are not inherited by the Application object’s children are not inheritable. Use the global type selector to apply a non-inheritable style globally.

Defining styles in the Application type selector are not required to declare a style for each component, because the components are children of these classes and inherit the Application type selector styles.

The following example defines various styles in the Application type selector:

<mx:Style>

          Application
          {
               background-color: #FFFFFF;
               padding-top: 10;
          }

</mx:Style>

Global Type Selector

Flex provides a global type selector that you can use to apply styles to all controls. Any properties defined by a global type selector apply to all controls, unless that control explicitly overrides it. The global selector is like a type selector, and so you do not have to preface it with a period in CSS.

The following example defines the fontFamily and fontSize property to the global selector:

<mx:Style>

          global
          {
               font-family: Verdana;
               font-size: 10;
          }

</mx:Style>


Applying Fonts

Flex has two types of fonts: device fonts and embedded fonts. Embedded fonts are smoother, and you can apply special effects to text-based controls such as rotating and fading. There are many ways to embed fonts in your application, such as using CSS syntax to embed FlashType fonts into the SWF files.

The application stores the names of the fonts that you used to create the text. The Flash Player uses the font names to locate identical or similar fonts on the user’s system when the application runs. Using embedded fonts means that they are used regardless of whether the client system contains the fonts because they are embedded within the SWF file.

Device Fonts

Device fonts do not export their outline information and are not embedded in the SWF or application. The Flash Player uses whatever fonts it can find on the client computer that closely resemble the device fonts.

The following example specifies three device fonts. The Flash Player looks for the first font, the second font, and so on.

<mx:Style>

          Application
          {
               font-family: Arial, Helvetica, Verdana;
               font-size: 10;
               color: Blue;
               font-weight: bold;
          }

</mx:Style>

The Flash Player supports the following three device fonts:

  • _sans - The _sans device font is a sans-serif typeface (for example, Arial).

  • _serif - The _serif device font is a serif typeface (for example, Times Roman).

  • _typewriter - The _typewriter device font is a monospace font (for example, Courier).

When using device fonts, the size of the SWF does not increase. However, using device fonts can impact performance of the application because it requires the Flash Player to interact with the local operating system. If you are using device fonts, you are limited to three fonts.

Embedded Fonts

You can embed TrueType Font (TTF) families in your Flex application rather than relying on a client machine to have the specific fonts. The font will always be the same when running your application, and you do not have to worry about missing fonts.

Embedded fonts have the following benefits:

  • The font does not need to be installed on the system.

  • Embedded fonts are anti-aliased, meaning their edges are smoothed for easier readability (especially when the text size is larger).

  • Embedded fonts can be partially or fully transparent and be rotated.

  • Embedded fonts provide smoother playback when zooming.

  • Text appears as you would expect when using embedded fonts.

The following are downsides to using embedded fonts:

  • You can only embed TrueType fonts.

  • Embedded fonts increase the size of your application because it must contain the outlines for the text.

  • Embedded fonts decrease readability of text at sizes smaller than 10 points.

To use embedded fonts in your application, you would typically use CSS syntax. The @font-face declaration specifies the source of the embedded font, and then defines the name of the font by using the fontFamily property. Each font face from the same family must be specified using the @font-face declaration.

Important

Note the font licenses before attempting to embed fonts into your Flex application. Some fonts might have licensing restrictions that do not allow them to be stored as vector information.

Embedded fonts can be TTF files on your file system or an SWF file that is created in Adobe Flash. Fonts embedded using Flash take advantage of the FlashType technology, which makes them more readable at smaller sizes.

The following example embeds the font Verdana located at c:\Windows\Fonts\Verdana.ttf:

<mx:Style>

          @font-face
          {
               src:url("c:\\Windows\\Fonts\\Verdana.ttf");
               fontFamily: myFontFace;
          }

</mx:Style>

After you have embedded the font, you can use the fontFamily name or alias in a type or class selector. The following example uses the myFontFace as a type selector for all Button controls:

Button
{
     fontFamily: myFontFace;
}

FlashType Fonts

FlashType is a new rendering engine included in Flash Player 8 and above that provides clear, high-quality text rendering in SWF files. It greatly improves the readability of text, especially when rendered at smaller font sizes.

To use FlashType fonts in Flex, you create an SWF file in Adobe Flash 8 that contains the fonts you require in your application. You then reference that SWF file’s font contents so that it gets embedded into your application.

Using FlashType fonts in your application may cause a slight delay when loading the application. The more you use, the slower the startup time of your application. It can also increase the memory usage by quite a bit.

Embedding FlashType fonts in your application is the same as other embedded fonts. They are anti-aliased, and you can rotate them or make them fully or partially transparent.

A good practice is to include the four primary typefaces for each font that you want to embed (that is, plain, bold, italic, and bold italic). The reason for this is that some Flex controls use one of the non-plain typefaces. An example of this would be a label on the Button control that uses a bold typeface of the font. Embedding a plain typeface to use on a Button will likely not work, because it requires a bold typeface.

Creating an SWF to Embed FlashType Fonts

The first step in embedding FlashType fonts in your application is to create an SWF using Adobe Flash 8 that contains those fonts. Once you have completed this part, you must embed them into your Flex application.

  1. Open Adobe Flash 8 and create a new document.

  2. Select the Text Tool and create a text field on the Stage.

  3. Enter at least one character of text into the text field. If it is easier, you may want to type out the name of each typeface, as shown in Figure 7-1.

    Image from book
    Figure 7-1: Entering text into the text field

  4. In the Properties panel, select Dynamic Text from the drop-down list.

  5. In the Properties panel, click the Embed button, and the Character Embedding dialog box shown in Figure 7-2 will appear.

    Image from book
    Figure 7-2: Character Embedding dialog box

  6. Then, select the ranges of glyphs you would like to embed. Only select all if you feel it is absolutely necessary. Selecting all the glyphs will make the file size fairly large, so rather, select only what you really need.

  7. Create three more text fields, one for each typeface, such as bold, italic, and bold italic (Figure 7-3).

    Image from book
    Figure 7-3: Three more text fields for each typeface

  8. Export your movie by pressing Ctrl+Enter to create an SWF file for use within your Flex application.

Embedding FlashType Fonts

After you have created your SWF file with the appropriate fonts, it is time to embed them into your Flex application using CSS.

  1. Embed each typeface with a @font-face declaration:

@font-face
{
     src:url(myfonts.swf);
     fontFamily: Verdana;
     fontStyle: italic;
     fontWeight: bold;
}

  2. Now, define a style for each embedded typeface. This can be done in an external style sheet or in the <mx:Style> tag.

.myStyle1
{
     fontFamily: Verdana;
     fontSize: 11;
}

    You must specify the fontFamily property and it must match the fontFamily property set in the @font-face declaration. The value of the fontFamily property stays the same, regardless of which typeface you are defining (in other words, if the typeface is bold, you do not specify Verdana Bold, but just Verdana).

    Remember that you must specify all the typeface properties like you did in the @font-face declaration. If the typeface is bold italic, define the fontWeight and fontStyle properties to match it.

.myStyle2
{
     fontFamily: Verdana;
     fontSize: 11;
     fontStyle: italic;
     fontWeight: bold;
}

  3. Apply the new style to your Flex controls:

<mx:Label text="Label" styleName="myStyle2" />

    You can also specify the styles inline instead of defining them in a style sheet. The only problem with this approach is that if you need to edit the styles, it will not be in one central place.

There is one more way to embed FlashType fonts without using the @font-face declaration: by using the [Embed] metadata keyword. The following example embeds a Verdana font’s italic typeface:

[Embed(source="verdana_fonts.swf", fontName="Verdana", fontWeight="italic")]
public static var italicFont:Class;

Ensure that you are using the latest SWF file that contains your fonts. Otherwise, recompile the SWF file, if necessary.


Skinning the Application

The process of changing the appearance of a component by modifying or replacing its visual elements is called skinning. The elements can be made up of images, SWF files, or a class that implements the drawing API methods.

Graphical Skins

Image files embedded into your application that represent a state of a component are called graphical skins. Each image may be a different state of a component, such as the downSkin of a Button control.

The following example shows the upSkin, overSkin, and downSkin style properties defined as new graphical skins. These style properties point to the different images for each state of the control. Figure 7-4 shows the graphical skins used in the following code example:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Style>

          Button
          {
               upSkin: Embed("/skins/upSkin.png");
               overSkin: Embed("/skins/overSkin.png");
               downSkin: Embed("/skins/downSkin.png");
          }

     </mx:Style>

     <mx:Button />

</mx:Application>
Image from book
Figure 7-4: Graphical skins

Skins are actually a class, and when you are changing the reference from a current skin to a new one, it is just a new class. Flex wraps each embedded asset as a class within the current document’s class.

Note that if you change any graphical skins, you must recompile the application because they are embedded into the SWF file. You can define skin properties either using CSS, inline, or by using the setStyle() method of the control you are skinning.

The one downside to using graphical skins or images is that resizing the component will create distortion. You can use a technique called Scale-9 to create skins that do not become distorted. The technique lets you define nine sections of an image that scale independently.

Programmatic Skins

In Flex you can write programmatic skins as ActionScript classes that use the Drawing API of the Flash Player. The methods for drawing at run-time are in the flash.display.Graphics package.

The best way to learn how to create programmatic skins is to look at the ones that come with Flex and then either extend them or create your own. The programmatic skin recipe is a basic template that you can use to implement a skin for a component.

The following code example is a programmatic skin class. You can use this class as a template to create new skins.

package
{
     import flash.display.Graphics;
     import mx.skins.Border;
     import mx.skins.ProgrammaticSkin;
     import mx.styles.StyleManager;

     public class MyCustomSkin extends ProgrammaticSkin
     {
          // Constructor.
        public function MyCustomSkin()
        {
            // Set default values here.
        }

        override protected function updateDisplayList(w:Number, h:Number):void
        {
            // Add styleable properties here.
            // Add logic to detect component's state and set properties here.
            // Add drawing methods here.
        }
     }
}

Programmatic skins define the appearance of a skin in multiple states of a control, such as the upSkin, downSkin, and overSkin of a Button control. These states refer to the default state, when the button is pressed, and when the mouse is over the button but has not been pressed.

Choosing a Superclass

The first step in creating a programmatic skin is to select a superclass for the skin. You can extend the abstract base classes in the mx.skins package or the mx.skins.halo package, but the former gives you more control over the look and feel of your skins. The latter is fine if you use the default behavior of the Flex controls but want to add extra styling.

Most skins extend the mx.skins.ProgrammaticSkin class, but any of the following classes can be used:

  • The ProgrammaticSkin class implements all the necessary interfaces to make it easier for you to define skins for your components. It is also the most common superclass to use.

  • The Border class extends the ProgrammaticSkin class and adds a property called borderMetrics that allows you to get the thickness of the border.

  • The RectangularBorder class extends the Border class and adds a style property called backgroundImage so that you can set the background image of the component.

Note that a programmatic skin must implement the IFlexDisplayObject, IInvalidating, and ILayoutManagerClient interfaces. It must also implement the ISimpleStyleClient interface if it depends on the values of CSS styles.

The superclass of a skin can be a subclass of the DisplayObject class as long as you implement all of those interfaces.

The updateDisplayList() method is used to define the look of your skin. It is called after the skin’s constructor is called and then every time the skin is resized, restyled, moved, or interacted with in some way.

In the updateDisplayList() method, you use the drawing methods to draw the programmatic skin. When implementing the updateDisplayList() method, remember to use the override keyword to override the superclass’s implementation, set the return type to void, and declare the method as protected. The method also takes the width and height of the component as arguments.

The following code example draws a square with a border:

override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void

               graphics.clear();
               graphics.lineStyle(2, 0x000000, 1.0, true, LineScaleMode.NORMAL,
CapsStyle.SQUARE, JointStyle.MITER);
               graphics.beginFill(0xFFFFFF, 0);
               graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
               graphics.endFill();
}

The following example applies a programmatic skin to a specific state of the control:

Button
{
     upSkin:ClassReference('MyCustomSkin');
}

Note that if you subclass the RectangularBorder class, you must also call the super.updateDisplayList() inside of your implementation of the updateDisplayList().


Item Renderers

In Flex, there are several controls that represent a list of items. You can scroll through the list of items and select one or more from the list. They are all derived from the ListBase class, and the following controls are included: List, TileList, Menu, Tree, DataGrid, and HorizontalList.

A list control uses a data provider for its data, which is a collection of objects. The data provider creates a layer of abstraction between the Flex list controls and the data that populates them. You can think of the data provider as the model and the Flex list control as the view onto the data.

Every list control has a default view to display the data, and Flex lets you override this mechanism. To do this, you must create an item renderer. The simplest item renderer is the DataGridItemRenderer, which is the default item renderer for the DataGrid control. It contains the functionality to display text.

The following example is a List control using the default item renderer to display a list of three different fruits:

<mx:List id="myList">
          <mx:dataProvider>
               <mx:Array>
                    <mx:String>Apples</mx:String>
                    <mx:String>Oranges</mx:String>
                    <mx:String>Pears</mx:String>
               </mx:Array>
          </mx:dataProvider>
     </mx:List>

If you wanted to display more than just text for each item in the list control, you must create your own custom item renderer. Custom item renderers and item editors provide you with the following benefits:

  • Replace the display of text with a richer appearance.

  • Combine multiple elements in a single list item such as an image and a label.

  • Allow you to control the display of the item programmatically.

Figure 7-5 is a list control with a custom item renderer containing an Image control and a Label control inside of an HBox container.

Image from book
Figure 7-5: List control with a custom item renderer

Building Custom Item Renderers and Item Editors

There are several ways to use item renderers in your application, such as using the drop-in method or using the inline method or as reusable components.

  • The drop-in method inserts a single component as an item renderer by defining it in the list control’s itemRenderer property.

  • The inline method defines the item renderer as one or more components using the child tags of the list control.

  • Using a custom component as an item renderer is more efficient and promotes reuse. This means that you can reuse it in more than one place or application.

The Drop-in Method

If you only need to drop in single components (such as a DateField or Numerical Stepper control), the drop-in item renderer is perfect. In other words, you define an existing Flex component as an item renderer for the list control.

The following example has a DataGrid control with a CheckBox control as the item renderer of the second column:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
        <![CDATA[

            [Bindable]
            public var myDP:Array = [
                {label:"Customer 1", selected:true},
                {label:"Customer 2", selected:false}
               ]

        ]]>
    </mx:Script>

     <mx:DataGrid dataProvider="{myDP}">
          <mx:columns>
                  <mx:DataGridColumn dataField="label" headerText="Customers" />
                  <mx:DataGridColumn dataField="selected" headerText=""
itemRenderer="mx.controls.CheckBox" />
             </mx:columns>
     </mx:DataGrid>

</mx:Application>

Flex automatically uses the data property to populate the CheckBox control with the current value of the column because the dataField of that column is set to the selected object property.

The Inline Method

The drop-in method shows you how easy it is to use an item renderer in a list control. The only problem is that you cannot configure them the way you might want to. For more flexibility, you create an item renderer as an inline component.

The following example is from the drop-in example, but instead uses the inline method:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:filters=
"flash.filters.*">

     <mx:Script>
        <![CDATA[

            [Bindable]
            public var myDP:Array = [
                {label:"Customer 1", selected:true},
                {label:"Customer 2", selected:false}
               ]

        ]]>
    </mx:Script>

     <mx:DataGrid dataProvider="{myDP}">
          <mx:columns>
                  <mx:DataGridColumn dataField="label" headerText="Customers" />
                  <mx:DataGridColumn dataField="selected" headerText="">
                       <mx:itemRenderer>
                            <mx:Component>
                                 <mx:VBox verticalAlign="middle"
horizontalAlign="center">
                                      <mx:CheckBox />
                                 </mx:VBox>
                            </mx:Component>
                       </mx:itemRenderer>
                  </mx:DataGridColumn>
             </mx:columns>
     </mx:DataGrid>

</mx:Application>

In this example, an inline item renderer was used that allows you to center the CheckBox control vertically and horizontally within the cell.

A Component as an Item Renderer

The advantage of using a component as an item renderer is that you can reuse it all over the application and in different applications, too. Using this method, you can create more complex item renderers because you will create a separate document or class for them.

The following example is a custom item renderer called MyCustomItemRenderer.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:HBox>
          <mx:TextInput text="{data.label}" />
          <mx:DateField selectedDate="{data.date}" />
          <mx:Button label="Button" click="Alert.show('Selected Item - Fruit: ' +
data.label + '\n' + 'Date: ' + data.date)" />
     </mx:HBox>
     <mx:Script>
          <![CDATA[
               import mx.controls.Alert;
          ]]>
     </mx:Script>

</mx:VBox>

To show you the power of item renderers, this custom reusable component has three Flex controls contained inside an HBox container. If you click the button, an Alert control pops up with current selected fruit and date values. These are passed into the item renderer via the data property.

This example is the main application with the item renderer defined in the List control using the itemRenderer property:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:filters=
"flash.filters.*">

     <mx:Script>
        <![CDATA[

            [Bindable]
            public var myDP:Array = [
                {label:"Oranges", date: new Date()},
                {label:"Apples", date: new Date()},
                {label:"Pears", date: new Date()}
               ]

        ]]>
    </mx:Script>

     <mx:List dataProvider="{myDP}" itemRenderer="MyCustomItemRenderer" />

</mx:Application>

You may find several areas in your application where the MyCustomItemRenderer may come in handy. This exact example merely demonstrates how powerful item renderers are.

Information passed to an item renderer or item editor is done so through the data property of the item renderer or item editor. The ListData class defines the data type of the listData property implemented by drop-in item renderers or drop-in item editors for the List control.


Item Editors

Item editors let you modify the value of the cell in a list control. The List, DataGrid, and Tree controls support item editors. This allows the user of your application to be able to edit rows of data inline without having to pop up a dialog box or bind it to a form below.

Overview of Cell Editing Process

The specific process that occurs when a cell in a list control is edited is as follows:

  1. The user releases the mouse button over the cell, or tabs to a cell.

  2. The itemEditBeginning event is dispatched, which you can use to disable editing of a specific cell or cells.

  3. The itemEditBegin event is dispatched to open the item editor, and can be used to modify the data passed to the item editor.

  4. The user then edits the cell.

  5. The user then ends the editing session and the cell editing session quits when the user removes focus.

  6. The itemEditEnd event is dispatched to close the item editor and update the cell with new data. You can modify the data returned to the cell via the event, validate the new data, or return the data in a different format.

  7. The new data appears in the cell.

Editable Cell

The Flex list controls, such as the List, Tree, and DataGrid, include an editable property that can be set to true so that users can edit the contents of the control. The editable property is set to false by default. Setting the editable property to true on a DataGrid control means all columns are editable. If you do not want every column editable, set the DatagridColumn.editable property to false.

In the Flex list controls, you can use the default item editor (the TextInput control), a custom item editor, or a custom item renderer as an editor. If you want the item renderer to be the editor, set the rendererIsEditor property of the list control to true.

If you set the rendererIsEditor property to true, Flex will ignore the itemEditor property and use the item renderer as the item editor.

Returning Data from an Item Editor

By default, Flex expects an item editor to return a single value to the list control. The editorDataField property of the list control specifies the property of the item editor that contains the new data. The value is converted to the appropriate data type for the cell.

The default value of the editorDataField property is text that corresponds to the default item editor of a list control, the TextInput control. If you changed the default item editor to a DateField control, you must set the editorDataField property to the selectedDate property, as the following example shows:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:filters=
"flash.filters.*">

     <mx:Script>
        <![CDATA[

            [Bindable]
            public var myDP:Array = [
                {label:"Oranges", date: new Date()},
                {label:"Apples", date: new Date()},
                {label:"Pears", date: new Date()}
               ]

        ]]>
    </mx:Script>

     <mx:DataGrid dataProvider="{myDP}" editable="true" variableRowHeight="true">
          <mx:columns>
               <mx:DataGridColumn dataField="label" headerText="Fruits" />
               <mx:DataGridColumn dataField="date" headerText="Date Purchased"
                    itemEditor="mx.controls.DateField" editorDataField=
"selectedDate" />
          </mx:columns>
     </mx:DataGrid>

</mx:Application>

In the preceding example, a DateField control is the item editor and, therefore, the editorDataField property is set to selectedDate, the property of the DateField control that contains the new cell data.

Sizing and Positioning an Item Editor

You may notice that when you click in a cell, a popup control appears above the selected cell of the list control. The list control also hides the current value of the cell.

Four properties can be used to size and position item editors within list controls:

  • editorHeightOffset - Specifies the height of the item editor in pixels, relative to the size of the cell for a DataGridColumn control, or the text field of a Tree control

  • editorWidthOffset - Specifies the width of the item editor in pixels, relative to the size of the cell for a DataGridColumn control, or the text field of a Tree control

  • editorXOffset - Specifies the x location of the upper-left corner of the item editor in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or the upper-left corner of the text field of a Tree control

  • editorYOffset - Specifies the y location of the upper-left corner of the item editor in pixels, relative to the upper-left corner of the cell for a DataGridColumn control, or the upper-left corner of the text field of a Tree control

The following example sets the editorXOffset property of the DataGridColumn control to 10 pixels. This will offset the DateField control 10 pixels from the left.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:filters=
"flash.filters.*">

     <mx:Script>
        <![CDATA[

            [Bindable]
            public var myDP:Array = [
                {label:"Article 1", datePosted: new Date(2006, 10, 23)},
                {label:"Article 2", datePosted: new Date(2006, 7, 20)},
                {label:"Article 3", datePosted: new Date(2006, 5, 11)}
               ]

        ]]>
    </mx:Script>

     <mx:DataGrid dataProvider="{myDP}" editable="true" variableRowHeight="true"
width="50%">
          <mx:columns>
               <mx:DataGridColumn dataField="label" headerText="Articles" />
               <mx:DataGridColumn dataField="datePosted" headerText="Date Posted"
editorXOffset="10"
                    itemEditor="mx.controls.DateField"
editorDataField="selectedDate" />
          </mx:columns>
     </mx:DataGrid>

</mx:Application>

Cell Editing Events

The cell editing process of a list component dispatches three events: itemEditBeginning, itemEditBegin, and itemEditEnd. This was mentioned earlier in this chapter.

There are default event listeners defined for these three events, but you can implement your own event listeners that will execute before the default ones. In your implementations, you can modify the data passed to or returned from an item editor. If you modified the data in the event listener for the itemEditBeginning event, that code would execute first, then the default event listener would run to continue the editing process.

You can replace the default event listener with your own implementation. To prevent the default one from executing, call the event.preventDefault() method from anywhere in your event listener.

Each editable list control has a corresponding event class that defines the event object for the cell editing events. The DataGrid control uses the DataGridEvent class; the List and Tree controls use the ListEvent class.

The following example defines an event listener, but with no implementation for the List control:

public function myCellBeginEvent(event:ListEvent):void
{
     // implement the event listener.
}

Accessing Cell Data

When a user edits a cell, you can access the current value, the new value entered by the user, or the item editor used to edit the cell.

To access the current value of a cell, use the editedItemRenderer property of the list control. The data provider element is accessible in Tree and List controls, and the element for the whole row in a DataGrid control.

Use the itemEditorInstance property if you need to access the new cell value of the item editor. Note that the itemEditorInstance is not initialized until the cellBeginEvent has executed, and would typically only access it within the event listener of the itemEditEnd event.

The following example contains an event listener defined on a DataGrid control for the itemEditEnd event:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
        <![CDATA[

           import mx.collections.ArrayCollection;
           import mx.controls.TextInput;
           import mx.events.DataGridEvent;

            [Bindable]
               public var productsAC:ArrayCollection = new ArrayCollection([
                {Product:'iPod', Price:249},
                {Product:'iMac', Price:1299},
                {Product:'MacBook', Price:1099}
            ]);

               private function getCellInfo(event:DataGridEvent):void
               {
                // Get the item editor and cast it to TextInput.
                var myEditor:TextInput = TextInput(event.currentTarget
.itemEditorInstance);

                // Get the new value from the editor.
                var newVal:String = myEditor.text;

                // Get the old value.
                var oldVal:String = event.currentTarget.editedItemRenderer
.data[event.dataField];

                // Write out the cell coordinates, new value,
                // and old value to the TextArea control.
                cellInfo.text = "cell edited.\n";
                cellInfo.text += "Row, column: " + event.rowIndex + ", " + event
.columnIndex + "\n";
                cellInfo.text += "New value: " + newVal + "\n";
                cellInfo.text += "Old value: " + oldVal;
            }

        ]]>
    </mx:Script>

    <mx:TextArea id="cellInfo" width="300" height="150"/>

    <mx:DataGrid id="myGrid" dataProvider="{productsAC}" editable="true"
itemEditEnd="getCellInfo(event)">
        <mx:columns>
            <mx:DataGridColumn dataField="Product"/>
            <mx:DataGridColumn dataField="Price"/>
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

In the preceding example, you get the item editor (which is a TextInput control) by casting it to the relevant type. If it were a custom item editor, you would need to cast it to that type. Now that you have a reference to the item editor, you can access the old value and new value.

Preventing a Cell from Being Edited

To prevent a cell from being edited, you can call the event.preventDefault() method in the event listener of the itemEditBeginning event.

The following example calls the preventDefault() method of the event passed in for the itemEditBeginning event:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
        <![CDATA[

             import mx.collections.ArrayCollection;
            import mx.controls.TextInput;
            import mx.events.DataGridEvent;

            [Bindable]
               public var productsAC:ArrayCollection = new ArrayCollection([
                {Product:'iPod', Price:249},
                {Product:'iMac', Price:1299},
                {Product:'MacBook', Price:1099}
            ]);

               private function onEditBeginning(event:DataGridEvent):void
               {
                if (event.rowIndex == 2)
                     event.preventDefault();
            }

        ]]>
    </mx:Script>

    <mx:TextArea id="cellInfo" width="300" height="150"/>

    <mx:DataGrid id="myGrid" dataProvider="{productsAC}" editable="true"
itemEditBeginning="onEditBeginning(event)">
        <mx:columns>
            <mx:DataGridColumn dataField="Product"/>
            <mx:DataGridColumn dataField="Price"/>
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

The preceding example uses the rowIndex property of the event, but, in essence, you can use any property of the DataGrid to stop a cell being edited. If you try to edit the three rows of the DataGrid, it will not work.


Tooltips

Tooltips, as you may already know, are a method of providing useful information to the user. When a user moves the mouse over a specific area, a tooltip pops up with the relevant information. Tooltips can be used to help your users work through your application, or you can use them to add extra functionality.

You will find that tooltips are in many desktop applications written for Windows or Linux. They add extra information when a user moves the mouse pointer over an onscreen element.

Figure 7-6 shows a tooltip that appears when the user’s mouse pointer hovers over the TextInput control.

Image from book
Figure 7-6: Tooltip for TextInput control

The tooltip will eventually disappear, even though the user’s mouse pointer remains over the component. You can set the time it takes for the tooltip to appear and disappear.

Tooltips support style sheets and dynamic loading of the text, but do not support embedded HTML.

Tooltips are the basis for the accessibility implementation, and all controls that support accessibility do so by making their tooltip text readable by screen readers.

Creating Tooltips

All visual components that extend the UIComponent class support a toolTip property. You set the toolTip property to a text string and then, when a mouse pointer hovers over the component, the string appears in the tooltip.

The following example shows a TextInput control with the toolTip property defined:

<mx:TextInput toolTip="This is a TextInput control" />

To do the same in ActionScript, set the toolTip property of the component instance to text string, as the following example shows:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initApp()">

    <mx:Script>
         <![CDATA[

              import mx.controls.TextInput;

              public function initApp():void
              {
                   var myTextInput:TextInput = new TextInput();
                   myTextInput.toolTip = "This is a TextInput control";
                   addChild(myTextInput);
              }

         ]]>
    </mx:Script>

</mx:Application>

With regard to children in containers, if you do not define a tooltip on the child of a container, the tooltip of the parent container is displayed, instead. For example, if you add a TextInput control to a Panel container that has a tooltip, the user sees the Panel container’s tooltip text when the mouse pointer is over the Panel. To clear the child’s tooltip text, set the toolTip property to a blank string. So, in other words, the children inherit the tooltip from the parent container.

Using Styles with Tooltips

Tooltip text and tooltip box appearance can be changed using CSS syntax or the StyleManager class. Changes to the tooltip’s styles are reflected in the whole application.

To change the styles of a tooltip, use the <mx:Style> tag with a type selector to override the default one. The following example sets the styles of the tooltip using CSS:

<mx:Style>

          ToolTip
          {
               fontFamily: "Arial";
               fontSize: 20;
               fontStyle: "bold";
               color: #FFCC00;
               backgroundColor: #999999;
          }

</mx:Style>

To use the StyleManager class to apply styles to tooltips, use the setStyle() method on the tooltip type selector, as the following examples shows:

<mx:Script>
     <![CDATA[

     import mx.controls.TextInput;

     public function initApp():void
     {
          StyleManager.getStyleDeclaration("ToolTip").setStyle("fontSize", 20);
     }

     ]]>
</mx:Script>

Tooltip Events

Tooltips have many events that are dispatched during their life cycle. The types of events are contained in the ToolTipEvent class. The usual properties type and target are available, but there is also a property called toolTip that references the tooltip itself. With this reference, you can add the tooltip’s text property inside the event handler.

The following example gets a reference to the tooltip and sets its text to the myLabel instance text property:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initApp()">

    <mx:Script>
         <![CDATA[
              import mx.controls.ToolTip;

              import mx.core.IToolTip;
              import mx.events.ToolTipEvent;
              import mx.controls.TextInput;

              public function initApp():void
              {
                   myTextInput.addEventListener(ToolTipEvent.TOOL_TIP_SHOW,
onToolTipShow);
              }

              private function onToolTipShow(event:ToolTipEvent):void
              {
                   var toolTip:IToolTip = event.toolTip;
                   myLabel.text = toolTip.text;
              }

         ]]>
    </mx:Script>

    <mx:TextInput id="myTextInput" toolTip="ToolTip text goes here" />
    <mx:Label id="myLabel" />

</mx:Application>

ToolTipManager Class

The ToolTipManager class allows you to customize the tooltip functionality, such as enabling and disabling tooltips, or setting the display delay. The ToolTipManager class contains a reference to the current tooltip in the currentToolTip property.

Enabling and Disabling Tooltips

To enable or disable a tooltip, set the ToolTipManager.enabled or ToolTipManager.disabled properties.

The following example has two Button controls, one for enabling and one for disabling tooltips:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
         <![CDATA[
              import mx.managers.ToolTipManager;
         ]]>
    </mx:Script>

    <mx:Button label="Enable ToolTips" click="ToolTipManager.enabled = true"
toolTip="Enable ToolTips" />
    <mx:Button label="Disable ToolTips" click="ToolTipManager.enabled = false"
toolTip="Disable ToolTips" />

</mx:Application>

Delay Times for Tooltips

The delay time is the amount of time that passes before something happens. If you move your mouse pointer over a component and tooltips are enabled, there is a brief delay by default before the tooltip appears. This is great if a user is not looking for the tooltip to appear.

The ToolTipManager class allows you to set the length of time that passes before a tooltip appears, and how long the tooltip remains onscreen.

There are three properties the ToolTipManager class exposes regarding delay times of tooltips:

  • showDelay - The length of time (in milliseconds) that passes before Flex displays a tooltip

  • hideDelay - The length of time (in milliseconds) that passes before Flex hides the tooltip

  • scrubDelay - The length of time (in milliseconds) that a user can take when moving the mouse between components before Flex waits for the duration of the showDelay to display the tooltip

Tooltip Effects

Tooltips can use custom or standard Flex effects, by setting the showEffect or hideEffect property of the ToolTipManager class.

The following example uses Blur and Fade effects when the tooltip appears. This is achieved by using the Parallel effect.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initApp()">

     <mx:Script>
         <![CDATA[

              import mx.effects.*;
              import mx.managers.ToolTipManager;

              public function initApp():void
              {
                   var b:Blur = new Blur();

                   var f:Fade = new Fade();
                   f.alphaFrom = 0;
                   f.alphaTo = 1;

                   var p:Parallel = new Parallel();
                   p.addChild(b);
                   p.addChild(f);

                   ToolTipManager.showEffect = p;
              }

         ]]>
    </mx:Script>

    <mx:Button label="Enable ToolTips" toolTip="Enable ToolTips" />

</mx:Application>

Fonts used in this example do not fade, because you must use embedded fonts to achieve this effect.


Cursor Manager

The Cursor Manager allows you to customize the cursor in your Flex application. You can use this to provide visual feedback to the user, such as waiting for processing to complete. The cursor image can be a JPEG, PNG, GIF, or SVG file, or a Sprite object or an SWF file.

The default cursor in Flex is the system cursor used in your operating system. The Cursor Manager lets your control the functionality and appearance of the cursor. You may want different cursors, depending on the context of your application.

The Cursor Manager contains a list of cursors with priorities. The one with the highest priority is currently visible. You might have two cursors with the same priority, and Flex will use the most recent one.

Adding and Removing Cursors

To create a new cursor, use the setCursor() static method of the CursorManager class. The new cursor will be added to the list. There is an optional priority property that can be specified so that the Cursor Manager knows what the priority of the new cursor is. If the priority is higher than any of the others in the list, that cursor is shown immediately; otherwise, the one with the highest priority must be removed to show another cursor.

To remove the cursor, use the removeCursor() static method of the CursorManager class. If the cursor is removed that is currently being displayed, the cursor with the next-highest priority is shown immediately.

The following example loads an external image. While it loads, the cursor is set to busy.jpg, and reverts back once the image has fully loaded into the Flash Player.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.managers.CursorManager;
               import flash.events.*;

               private var cursorID:Number = 0;

               [Embed(source="busy.jpg")]
               private var busyCursorSymbol:Class;

               private function initImage(event:MouseEvent):void
               {
                    cursorID = CursorManager.setCursor(busyCursorSymbol);
                    myImage.load("image.jpg");
               }

               private function loadComplete(event:Event):void
               {
                    CursorManager.removeCursor(cursorID);
               }

          ]]>
     </mx:Script>

     <mx:Image id="myImage" complete="loadComplete(event)"/>
     <mx:Button id="myButton" label="Show" click="initImage(event)"/>

</mx:Application>

Busy Cursor

Flex defines a busy cursor that is used to indicate to the user that your application is processing, such as calling a remote server and waiting for a response. The default busy cursor is an animated clock.

The CursorManager has two static methods that can be used to control the busy cursor. The setBusy Cursor() method obviously displays the busy cursor, and the removeBusyCursor() method removes it from the cursor list.

The following example contains two Button controls; one shows the busy cursor and the other hides it:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.managers.CursorManager;

          ]]>
     </mx:Script>

     <mx:Button label="Show Busy Cursor" click="CursorManager.setBusyCursor()"/>
     <mx:Button label="Hide Busy Cursor" click="CursorManager.removeBusyCursor()"/>

</mx:Application>

When the busy cursor is shown, you can still interact with the entire application, unless you have disabled something such as a Panel and all its children. If you do not want the user to interact with your application when the busy cursor is showing, set the Application.application.enabled property to false.


Summary

Being able to customize a Flex application’s user interface is very important when building a successful product. Flex allows your designers to customize the look and feel of the application to fit the user’s needs. At the end of the day, your imagination is your only limit.

Chapter 8 carries on from here to show you more advanced topics, such as view states, transitions, drag and drop, embedding assets, Flex printing, talking to JavaScript, and using shared objects.


Chapter 8: Flex UI Topics

This chapter examines a variety of topics, including dynamic layout controls, states and transitions, embedded assets, local data storage using shared objects, communication with the browser, history management, and accessibility.

Repeaters and Containers

The Repeater control is a layout control that allows the interface to be drawn dynamically by looping through its dataProvider. Each object in the dataProvider can be accessed within the repeater by binding to "repeater id".currentItem.

Using the Repeater Component

The basic example in Listing 8-1 shows a simple Repeater with a horizontal layout accessing the label property of the objects within ArrayCollection dp.

Listing 8-1: Basic Repeater
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">
  <mx:Script>
  <![CDATA[
  import mx.controls.Alert;
  // handle button click and show the object's data property
  private function clickHandler(item:Object):void {
    Alert.show(item.data, "ClickHandler");
  }
  ]]>
  </mx:Script>
  <mx:ArrayCollection id="dp">
    <mx:Object label="Button 1" data="Data 1" />
    <mx:Object label="Button 2" data="Data 2" />
    <mx:Object label="Button 3" data="Data 3" />
    <mx:Object label="Button 4" data="Data 4" />
  </mx:ArrayCollection>
  <mx:Panel title="Basic Repeater" layout="horizontal">
    <mx:Repeater id="myRepeater" dataProvider="{dp}" >
      <mx:Button label="{myRepeater.currentItem.label}"
       click="clickHandler(event.currentTarget.getRepeaterItem());" />
    </mx:Repeater>
  </mx:Panel>
</mx:Application>
Image from book

When the application is initialized, the repeater will execute and loop through its dataProvider four times (the length of the ArrayCollection), drawing four buttons horizontally. Figure 8-1 shows the results, and Figure 8-2 shows the results after setting the repeater’s layout property to vertical.

Image from book
Figure 8-1: Using the Repeater control
Image from book
Figure 8-2: Vertical Repeater control

Repeater Component Execution Process

The Repeater component will execute initially when it is created, and then it will re-execute whenever there is a change to its dataProvider, startingIndex, or count. If any of these properties change, the Repeater will re-execute, destroy all of its children, then re-create the children, and automatically redraw the screen. This allows the developer a great deal of flexibility because the user interface can be drawn and redrawn by simply changing the dataProvider.

The advanced Repeater example shown in Listing 8-2 uses a custom component and Tile control to show a real-world example of how a Repeater control could be used to represent multiple categories in a sample e-commerce application.

Listing 8-2: Advanced Repeater
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comps="*"
  backgroundColor="#FFFFFF">
  <mx:ArrayCollection id="category1">
    <mx:Object productName="Product 1" productPrice="1.99" />
    <mx:Object productName="Product 2" productPrice="2.99" />
    <mx:Object productName="Product 3" productPrice="3.99" />
    <mx:Object productName="Product 4" productPrice="4.99" />
    <mx:Object productName="Product 5" productPrice="5.99" />
    <mx:Object productName="Product 6" productPrice="6.99" />
  </mx:ArrayCollection>
  <mx:ArrayCollection id="category2">
    <mx:Object productName="Product 1" productPrice="1.99" />
    <mx:Object productName="Product 2" productPrice="2.99" />
    <mx:Object productName="Product 3" productPrice="3.99" />
    <mx:Object productName="Product 4" productPrice="4.99" />
  </mx:ArrayCollection>
  <mx:HBox width="100%">
    <mx:Spacer width="100%" />
    <mx:Button label="Category 1" click="productsRepeater.dataProvider=
this.category1" />
    <mx:Button label="Category 2" click="productsRepeater.dataProvider=
this.category2" />
    <mx:Spacer width="100%" />
  </mx:HBox>
  <mx:Tile direction="horizontal" borderStyle="inset"
    horizontalGap="10" verticalGap="15"
    paddingTop="10" paddingBottom="10"
    paddingLeft="10" paddingRight="10">
    <mx:Repeater id="productsRepeater" dataProvider="{this.category1}" >
      <comps:Product productName="{productsRepeater.currentItem.productName}"
              productPrice="{productsRepeater.currentItem.productPrice}" />
    </mx:Repeater>
  </mx:Tile>
</mx:Application>
Image from book

Figure 8-3 shows how the code shown in Listing 8-2 will execute when the application initializes. The Repeater will loop through the category1 ArrayCollection creating the six product custom components. (For more information on custom components, see Chapter 13.) Figure 8-4 shows how the Repeater re-executes after the dataProvider changes when the Category 2 button is clicked.

Image from book
Figure 8-3: Code execution when application initializes
Image from book
Figure 8-4: Re-execution of the Repeater control when the Category 2 button is selected

Following is the custom component Product.mxml used in Listing 8-2:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
  borderStyle="outset" height="120" width="120">
  <mx:Script>
  <![CDATA[
  import mx.controls.Alert;
  [Bindable]
  public var productName:String;
  [Bindable]
  public var productPrice:Number;
  private function clickHandler():void{
    Alert.show(this.qty.value + " " + this.productName + "(s) added to cart");
  }
  ]]>
  </mx:Script>

  <mx:CurrencyFormatter id="usdFormatter" precision="2"
    currencySymbol="$" decimalSeparatorFrom="."
    decimalSeparatorTo="." useNegativeSign="true"
    useThousandsSeparator="true" alignSymbol="left"/>
  <mx:Label text="{this.productName}" horizontalCenter="1" verticalCenter="-49"/>
  <mx:Label text="{usdFormatter.format(this.productPrice)}" width="60" x="4" y=
"45"/>
  <mx:NumericStepper id="qty" minimum="1" maximum="10" stepSize="1" width="58" x=
"53" y="43"/>
  <mx:Button label="Add to Cart"  bottom="10" horizontalCenter="0" click=
"clickHandler();"/>
</mx:Canvas>


Using View States

View states enable developers to alter the appearance of the application view by simply adding code to add children, remove children, or change component properties. After defining the base state (all MXML files are created in the base state), the developer can create a new state using the Design view of Flex Builder, or by simply adding a <states> code block like this:

<mx:states>
  <mx:State name="newState">
    <mx:AddChild relativeTo="{hbox1}" position="before">
      <mx:Button label="New Button"/>
    </mx:AddChild>
  </mx:State>
</mx:states>

Using this code, when you change view state to "newState", the application will add a Button component to the view and position it before the hbox1 component. The Button would then show either to the left of hbox1 or above hbox1, depending on whether the application is a horizontal or vertical layout. To switch between states, you set the currentState property of the component or application. To go back to the base state, simply set the currentState property to an empty string.

Listing 8-3 shows a sample application with a two-state view of a simple product.

Listing 8-3: Two-State View
Image from book

<?xml version="1.0" ?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  backgroundColor="#FFFFFF">
  <mx:states>
    <mx:State name="Description">
      <mx:AddChild relativeTo="{hbox1}" position="before">
        <mx:TextArea width="200" height="180" id="prodDesc"
             borderStyle="none"
             text="Lorem Ipsum is simply dummy text ....."/>
      </mx:AddChild>
      <mx:RemoveChild target="{descButton}"/>
      <mx:AddChild relativeTo="{hbox1}" position="before">
        <mx:Button label="Close Description"
             click="this.currentState=''"/>
      </mx:AddChild>
    </mx:State>
  </mx:states>
  <mx:VBox id="vbox1" borderStyle="outset" paddingLeft="5" paddingBottom="5"
paddingRight="5" paddingTop="5">
    <mx:Label id="productNameTxt" text="Product Name" fontWeight="bold" />
    <mx:Button label="Open Description"
         click="this.currentState='Description'"
         id="descButton"/>
    <mx:HBox id="hbox1">
      <mx:Label text="$3.99"/>
      <mx:NumericStepper id="qty" minimum="1"
           maximum="10" stepSize="1"/>
         <mx:Button label="Add to Cart" id="addBtn"/>
    </mx:HBox>
  </mx:VBox>
</mx:Application>
Image from book

Figure 8-5 shows the application in its base state, and Figure 8-6 shows the application in the "Description" state, after the user has clicked the Open Description button.

Image from book
Figure 8-5: Application in base state
Image from book
Figure 8-6: Application after user clicks the Open Description button


Using Transitions

The preceding example accomplishes multiple states of a product view, but the application jumps from one state to the next rather abruptly. Luckily, Flex offers very simple ways to make the application change more gracefully. Flex calls these transitions.

Transitions Applied to View States

A transition is a way to make a smoother change between states. A transition can be a single effect, or a group of effects run in sequence or in parallel. Using the simple state example, you can add a Resize effect by simply adding the following code right after the mx:Application tag:

<mx:transitions>
  <mx:Transition  fromState="" toState="Description">
    <mx:Resize duration="500" target="{vbox1}"/>
  </mx:Transition>
  <mx:Transition  fromState="Description" toState="">
    <mx:Resize duration="500" target="{vbox1}"/>
  </mx:Transition>
</mx:transitions>

This code block adds a Resize effect that plays for a duration of 500 (half a second) when switching from the "" (base state) to the "Description" state, and then again when switching from the "Description" state back to the "" (base state).

Transitions allow you to apply more than one effect either in parallel or in sequence. The advanced transitions example shown in Listing 8-4 is a navigation system using state management to move between panels with a smooth transition. Each state sets the size and position of the three panels.

Listing 8-4: Advanced Transitions Example
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     width="400" height="400" layout="absolute"
     verticalScrollPolicy="off" horizontalScrollPolicy="off"
     backgroundColor="#FFFFFF">
     <mx:transitions>
    <mx:Transition fromState="*" toState="*">
      <mx:Sequence targets="{[panel1,panel2,panel3]}">
        <mx:Move duration="400"/>
        <mx:Rotate angleFrom="0" angleTo="360" />
        <mx:Resize duration="400"/>
      </mx:Sequence>
    </mx:Transition>
  </mx:transitions>
  <mx:states>
    <mx:State name="s1">
      <mx:SetProperty target="{panel1}" name="x" value="5"/>
      <mx:SetProperty target="{panel1}" name="y" value="60"/>
      <mx:SetProperty target="{panel1}" name="height" value="300"/>
      <mx:SetProperty target="{panel1}" name="width" value="390"/>
      <mx:SetProperty target="{panel2}" name="x" value="135"/>
      <mx:SetProperty target="{panel2}" name="y" value="10"/>
      <mx:SetProperty target="{panel2}" name="height" value="30"/>
      <mx:SetProperty target="{panel2}" name="width" value="125"/>
      <mx:SetProperty target="{panel3}" name="x" value="270"/>
      <mx:SetProperty target="{panel3}" name="y" value="10"/>
      <mx:SetProperty target="{panel3}" name="height" value="30"/>
      <mx:SetProperty target="{panel3}" name="width" value="125"/>
    </mx:State>
    <mx:State name="s2">
      <mx:SetProperty target="{panel1}" name="x" value="5"/>
      <mx:SetProperty target="{panel1}" name="y" value="10"/>
      <mx:SetProperty target="{panel1}" name="height" value="30"/>
      <mx:SetProperty target="{panel1}" name="width" value="125"/>
      <mx:SetProperty target="{panel2}" name="width" value="390"/>
      <mx:SetProperty target="{panel2}" name="height" value="300"/>
      <mx:SetProperty target="{panel2}" name="x" value="5"/>
      <mx:SetProperty target="{panel2}" name="y" value="60"/>
      <mx:SetProperty target="{panel3}" name="x" value="270"/>
      <mx:SetProperty target="{panel3}" name="y" value="10"/>
      <mx:SetProperty target="{panel3}" name="height" value="30"/>
      <mx:SetProperty target="{panel3}" name="width" value="125"/>
    </mx:State>
    <mx:State name="s3">
      <mx:SetProperty target="{panel1}" name="x" value="5"/>
      <mx:SetProperty target="{panel1}" name="y" value="10"/>
      <mx:SetProperty target="{panel1}" name="height" value="30"/>
      <mx:SetProperty target="{panel1}" name="width" value="125"/>
      <mx:SetProperty target="{panel2}" name="x" value="135"/>
      <mx:SetProperty target="{panel2}" name="y" value="10"/>
      <mx:SetProperty target="{panel2}" name="height" value="30"/>
      <mx:SetProperty target="{panel2}" name="width" value="125"/>
      <mx:SetProperty target="{panel3}" name="width" value="390"/>
      <mx:SetProperty target="{panel3}" name="height" value="300"/>
      <mx:SetProperty target="{panel3}" name="x" value="5"/>
      <mx:SetProperty target="{panel3}" name="y" value="60"/>
    </mx:State>
  </mx:states>
  <mx:Panel x="5" y="10" width="125" height="30" layout="absolute" title="Panel 1"
id="panel1" click="this.currentState='s1'"/>
  <mx:Panel x="135" y="10" width="125" height="30" layout="absolute" title="Panel
2" id="panel2" click="this.currentState='s2'"/>
  <mx:Panel x="270" y="10" width="125" height="30" layout="absolute" id="panel3"
title="Panel 3" click="this.currentState='s3'"/>
  <mx:Button x="167" y="368" label="Reset" click="this.currentState=''"/>
</mx:Application>
Image from book

The transition is accomplished by using a sequence of a Move, followed by Rotate of 360 degrees, and finally a Resize. Because the transition is set to run when changing fromState * (all) to State *, it will run all state changes. The sequence is also set to target all panels, which means it will affect every panel on every state change, which is obvious when the Rotate effect plays (as shown in Figure 8-7). If you were to remove the Rotate effect, you would only see the effect on the panel that is growing and the panel (if any) that is shrinking.

Image from book
Figure 8-7: Effect of Rotate

Transition Event Handling

When Flex is changing states, there is a defined process order. There are two events dispatched along the way. The first event dispatch (currentStateChanging) occurs when the current state is changing, and the second occurs when the state has completed the change. The following seven steps (as defined in the Flex 2 documentation) show the official process Flex uses when changing from one state to another:

  1. You set the currentState property to the destination view state.

  2. Flex dispatches the currentStateChanging event.

  3. Flex examines the list of transitions to determine the one that matches the change of the view state.

  4. Flex examines the components to determine the one that matches the change of the view state.

  5. Flex applies the destination view state to the application.

  6. Flex dispatches the currentStateChange event.

  7. Flex plays the effect you defined in the transition.

It is important to know that if the currentState property is changed again, before Flex completes the current transition, Flex will skip to the end of the transition and start the cycle over again as listed in the previous steps.

Transition Action Effects

To control the order that Flex uses to apply transitions, you can apply action effects. Action effects can be applied to the view state properties to gain additional control over the each property. There are four action effects that correspond to four view state properties. The following table shows the four action effects and their corresponding view state properties.

Open table as spreadsheet
Action Effect | View State Property
SetPropertyAction | SetProperty
SetStyleAction | SetStyle
AddChildAction | AddChild
RemoveChildAction | RemoveChild

Each action effect will play when the corresponding view state property occurs.

Let’s go back to the basic state example in Listing 8-4 and change the transitions block to the following:

<mx:transitions>
    <mx:Transition  fromState="" toState="Description">
       <mx:Sequence target="{vbox1}">
         <mx:Resize duration="500"/>
         <mx:SetPropertyAction name="visible" target="{prodDesc}" value="true"
startDelay="500"/>
       </mx:Sequence>
    </mx:Transition>
    <mx:Transition  fromState="Description" toState="">
       <mx:Sequence target="{vbox1}">
         <mx:SetPropertyAction name="visible" target="{prodDesc}" value="false"
startDelay="500"/>
         <mx:Resize duration="500"/>
       </mx:Sequence>
    </mx:Transition>
  </mx:transitions>

When running the application, you will now notice that the product description text does not appear until after the resize has occurred. The visible property has been given a startDelay of 500 to exaggerate the point. Action effects can give you that fine touch you need to really refine your transitions to be exactly the way you want them to perform.

Effects and Filters

Transitions also support filters, which allow the developer to make sure certain effects run only on some of the targets in the Sequence, rather than all of the targets (which is the default behavior). Using the preceding code sample, simply add filter="move" to the Rotate effect, and you will now notice that only the panels that are moving will have the Rotate effect applied. Transitions and states are one of the coolest features of Flex 2. Experiment by changing from Sequence to Parallel, or by using other effects (Blur, Dissolve, Zoom, and so on).


Using the Drag-and-Drop Manager

The Flex DragManager class allows assets to be dragged and dropped for either purely visual reasons or for moving data between components.

List Control Drag-and-Drop Functions

List controls have drag-and-drop functionality built in and are very easy to set up and use. The example shown in Listing 8-5 uses three simple List components - one original List to drag from and two additional List components to accept the drag item. The setup is as simple as setting dragEnabled="true" on the List component that contains the drag data, and setting dropEnabled="true" on the List components that will accept the data. Figure 8-8 shows the rotation transition. Figure 8-9 and Figure 8-10 show Listing 8-5 in action.

Listing 8-5: List Control Drag and Drop
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="absolute"
  xmlns:mx="http://www.adobe.com/2006/mxml"
  width="450" height="350"
  creationComplete="initApp();"
  backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
    // setup 3 dataProviders, 2 empty
    private function initApp():void{
      words.dataProvider = ['Water', 'Agua', 'Car', 'Coche', 'House', 'Casa',
'Book', 'Libro', 'Music', 'Música', 'Sandwich', 'Bocadillo'];
      english.dataProvider = [];
      spanish.dataProvider = [];
    }
    ]]>
  </mx:Script>
  <mx:Panel title="Sort Words By Language" layout="absolute" x="0" y="0" width=
"450" height="350">
    <mx:Label text="Drag to the Correct Language" x="7" y="3"/>
    <mx:List id="words" width="200" height="275"
      allowMultipleSelection="true"
      dragEnabled="true" y="25" x="7"/>
    <mx:Label text="English" y="6" x="223"/>
    <mx:List id="english" width="200" height="120"
      dropEnabled="true" y="25" x="223"/>
    <mx:Label text="Spanish" x="223" y="150"/>
    <mx:List id="spanish" width="200" height="120"
      dropEnabled="true" y="177" x="223"/>
  </mx:Panel>
</mx:Application>
Image from book
Image from book
Figure 8-8: The rotation transition
Image from book
Figure 8-9: A valid drop when over a target
Image from book
Figure 8-10: An invalid drop when not over a target

Adding Drag-and-Drop Support to Other Components

Non–list-based controls (or containers) must explicitly add support by using a series of events and classes that must be implemented. The DragManager class and its doDrag() method manage the start of the drag.

The DragSource class holds the data that is being dragged. In Listing 8-6, the data would be the name and price of the baseball hats. The DragEvent class dispatches events when the drag is in operation.

Listing 8-6: Custom Drag-and-Drop Operation
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="250"
  backgroundColor="#FFFFFF" creationComplete="initApp()" layout="absolute">
  <mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.events.DragEvent;
    import mx.managers.DragManager;
    import mx.core.DragSource;
    [Bindable]
    public var total:Number = 0;
    [Bindable]
    public var cartContents:ArrayCollection;
    private function initApp():void{
     this.cartContents = new ArrayCollection();
    }
    private function dragIt(event:MouseEvent, name:String, price:Number):void {
      // The currentTarget specifies the component initiating the drag.
      var dragInitiator:Image = event.currentTarget as Image;
      // Create a new  DragSource object containing the data being dragged
      var dragSource:DragSource = new DragSource();
      // Add the data to the object.
      dragSource.addData(name, 'name');
      dragSource.addData(price, 'price');
      // Create a copy of the image to use as a drag proxy.
      var dragProxy:Image = new Image();
      dragProxy.source = event.currentTarget.source;
      // Call the DragManager doDrag() method to start the drag.
      DragManager.doDrag(dragInitiator, dragSource, event, dragProxy);
    }
    // Called if the user drags a drag proxy onto the drop target.
    private function dragEnterHandler(event:DragEvent):void {
      // Get the drop target component from the event object.
      var dropTarget:DataGrid=event.currentTarget as DataGrid;
      // Accept the drag only if the object contains the correct data
      if (event.dragSource.hasFormat('name') && event.dragSource.hasFormat('price')){
        // Accept the drop.
        DragManager.acceptDragDrop(dropTarget);
      }
    }
    // Called if used drops the object over the target and the target accepts the object
    private function dragDropHandler(event:DragEvent):void {
      // Set the data from the dragSource to local vars.
      var name:String  = String(event.dragSource.dataForFormat('name')) ;
      var price:Number  = Number(event.dragSource.dataForFormat('price')) ;
      this.cartContents.addItem({name:String(event.dragSource.dataForFormat('name')),
price:Number(event.dragSource.dataForFormat('price'))});
      // Add the price to the total
      total += price;
    }
    ]]>
  </mx:Script>
  <mx:ArrayCollection id="products">
    <mx:Object productName="Product 1" productPrice="1.99" productImage="book.gif" />
    <mx:Object productName="Product 2" productPrice="2.99" productImage="book.gif" />
    <mx:Object productName="Product 3" productPrice="3.99" productImage="book.gif" />
  </mx:ArrayCollection>
  <mx:Image source="yankee.jpg" mouseMove="dragIt(event, 'Yankee Hat', 19.99);"
x="23" y="35"/>
  <mx:Label text="$ 19.99"  x="53" y="215"/>
  <mx:Image source="mets.jpg" mouseMove="dragIt(event, 'Met Hat', 19.99);" x="23"
y="135"/>
  <mx:Label text="$ 19.99"  x="53" y="109"/>
  <mx:Label text="Shopping Cart"  x="226" y="28" fontWeight="bold"/>
  <mx:DataGrid id="cart" dataProvider="{cartContents}" dragEnter=
"dragEnterHandler(event);" dragDrop="dragDropHandler(event);" x="175" y="50"
height="165">
    <mx:columns>
      <mx:DataGridColumn dataField="name" headerText="Name" />
      <mx:DataGridColumn dataField="price" headerText="Price" />
    </mx:columns>
  </mx:DataGrid>
  <mx:Label text="Total: $ {total}"  x="215" y="222"/>
  <mx:Label x="93.5" y="2" text="Drag a product into the shopping cart"/>
  <mx:HRule x="5" y="20" width="390"/>
</mx:Application>
Image from book

Figure 8-11 shows the results of the custom drag-and-drop operation.

Image from book
Figure 8-11: The compiled results of Listing 8-6

Events that will be broadcast include dragEnter, dragOver, and dragComplete. Their definitions are described in the following table.

Open table as spreadsheet
Event | Description
dragEnter | The dragEnter event is dispatched when the drag item moves across the drop target. This allows you to alert the user that the item is over the target by programming a visual alert to the drop target. This could be a color change, a green border, and so on.
dragOver | The dragOver event is dispatched while the drag item is over the target and occurs after the dragEnter event. This would be a good time to validate that the item is going to be accepted by the target before it is dropped.
dragDrop | This is the dragDrop when the drag item is released over the target.
dragComplete | The dragComplete event broadcasts when the user releases the drag item, whether or not it is on the drop target.
dragExit | The dragExit event is broadcast when the drag item is dragged outside of the drop target, but is not dropped on the drop target.


Embedding Assets

Flex supports the embedding of images, movies, sound files, and fonts. Embedding the assets will compile the image or font into the generated SWF file. Although you can load assets at run-time using relative paths, embedding the assets means that they are available as soon as the application initializes. It also means that you can distribute your application as a single SWF file. Another reason to embed assets is that there are some areas such as icons where only embedded assets are allowed by Flex.

Images

There are several ways to embed an image asset. Here are two methods of embedding an image file to be used as a Button’s icon:

  • Embed inline:

<mx:Button label="My Button" icon="@Embed(source='myImage.gif')"/>

  • Bind with ActionScript:

<mx:Script>
    <![CDATA[
        [Embed(source="myImage.gif")]
        [Bindable]
        public var imgCls:Class;
    ]]>
</mx:Script>

<mx:Button label="My Button" icon="{imgCls}"/>

Fonts

There are multiple benefits to embedding a font as an asset. Embedded fonts can be rotated, which is often necessary when labeling chart data. Embedded fonts can also show transparency, and show better results when using a Zoom effect. Another key feature of embedded fonts is that the developer can be sure that the fonts will appear the same on all machines because there is no need to rely on the machines’ installed fonts.

Only fonts that are TrueType Font (TTF) files or fonts that have been embedded in an SWF file can be embedded.

There are several ways to embed and apply a font:

  • Embedding a font (Sample 1):

<mx:Style>
  @font-face {
    src:url("HELVETIB.TTF");
    fontWeight: bold;
    fontFamily: myHelveticaBold;
  }
</mx:Style>

  • Embedding a font (Sample 2):

<mx:Script>
  <![CDATA[
    [Embed(mimeType='application/x-font', source='HELVETIB.TTF', fontName='myFont',
fontWeight='bold')]
    private var myFontClass:Class;
  ]]>
</mx:Script>

  • Using an embedded font via a Cascading Style Sheet (CSS):

<mx:Style>
Label {
    fontFamily: myHelveticaBold;
    fontWeight: bold;
  }
</mx:Style>

  • Using an embedded font inline:

<mx:Label text="Hello World" fontFamily="myHelveticaBold" fontWeight="bold"/>

SWF and Sound Files

SWF and sound files can be embedded as classes in the same way as image files.

<mx:Script>
  <![CDATA[
    [Embed(source="mySound.mp3")]
    [Bindable]
    public var mySound:Class;

    [Embed(source="mySWF.swf")]
    [Bindable]
    public var mySWF:Class;
  ]]>
</mx:Script>


Using the History Manager

History management in Flex is achieved when the application is embedded within a Web page. The page will contain a hidden HTML frame that contains a history SWF, which stores and retrieves information on the application’s current state. This enables the user to use the browser’s Back and Forward buttons to navigate within the application.

Components with Built-in History Management

Components such as TabNavigator and Accordion have history management enabled by default. ViewStacks can also utilize history management, but it must be enabled by setting its historyManagementEnabled property to true. You can also turn off history management in the TabNavigator and Accordion by setting this property to false.

Adding History Management to Components

It is also possible to add history management to other components by implementing mx.managers.IHistoryManagerClient and supplying the saveState and loadState methods, which are required by the interface. The following sample code extends the ToggleButtonBar and adds history management:

<?xml version="1.0"?>
<mx:ToggleButtonBar xmlns:mx="http://www.adobe.com/2006/mxml" initialize=
"registerManager()" itemClick="buttonClicked()" implements=
"mx.managers.IHistoryManagerClient">
  <mx:Script>
    <![CDATA[
    import mx.managers.HistoryManager;
          // method to register with HistoryManager
    private function registerManager():void {
      HistoryManager.register(this);
    }
          // called when button is clicked
    private function buttonClicked():void {
      HistoryManager.save();
    }
    // Save the  selectedIndex.  ** Required Method **
    public function saveState():Object {
      return { selectedIndex: selectedIndex };
    }
    // Load the selectedIndex  ** Required Method **
    public function loadState(state:Object):void {
      var newIndex:int = state ? int(state.selectedIndex) : -1;
      if (newIndex != selectedIndex)
      selectedIndex = newIndex;
    }
    ]]>
  </mx:Script>
</mx:ToggleButtonBar>

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comps="*"
  width="375" height="75"
  backgroundColor="#FFFFFF">
  <mx:ArrayCollection id="buttons">
    <mx:Object label="Button 1" />
    <mx:Object label="Button 2" />
    <mx:Object label="Button 3" />
    <mx:Object label="Button 4" />
  </mx:ArrayCollection>
  <comps:ToggleHistoryButtonBar dataProvider="{buttons}" />
</mx:Application>

Note that history management will only work when all of the necessary JavaScript and SWF files are available in the application’s root folder, and the application’s HTML wrapper has the necessary code to include the needed files and create the hidden frame. Flex Builder 2 will generate the wrapper page and all necessary files within the project’s bin folder. You can also get these files from your SDK install. Listing 8-7 is a sample of the wrapper HTML page.

Listing 8-7: Sample Wrapper HTML Page
Image from book

<!-- saved from url=(0014)about:internet -->
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Advanced Transitions</title>
<script src="AC_OETags.js" language="javascript"></script>
<style>
body { margin: 0px; overflow:hidden }
</style>
<script language="JavaScript" type="text/javascript">
<!--
// -----------------------------------------------------------------------------
// Globals
// Major version of Flash required
var requiredMajorVersion = 9;
// Minor version of Flash required
var requiredMinorVersion = 0;
// Minor version of Flash required
var requiredRevision = 0;
// -----------------------------------------------------------------------------
// -->
</script>
</head>

<body scroll="no">
<script language="JavaScript" type="text/javascript" src="history.js"></script>
<script language="JavaScript" type="text/javascript">
<!--
// Version check for the Flash Player that has the ability to start Player Product
Install (6.0r65)
var hasProductInstall = DetectFlashVer(6, 0, 65);

// Version check based upon the values defined in globals
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion,
requiredMinorVersion, requiredRevision);

// Check to see if a player with Flash Product Install is available and the version
does not meet the requirements for playback
if ( hasProductInstall && !hasRequestedVersion ) {
  // MMdoctitle is the stored document.title value used by the installation process
to close the window that started the process
  // This is necessary in order to close browser windows that are still utilizing
the older version of the player after installation has completed
  // DO NOT MODIFY THE FOLLOWING FOUR LINES
  // Location visited after installation is complete if installation is required
  var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
  var MMredirectURL = window.location;
    document.title = document.title.slice(0, 47) + " - Flash Player Installation";
    var MMdoctitle = document.title;

  AC_FL_RunContent(
    "src", "playerProductInstall",
    "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+
'&MMdoctitle='+MMdoctitle+"",
    "width", "400",
    "height", "400",
    "align", "middle",
    "id", "AdvancedTransitions",
    "quality", "high",
    "bgcolor", "#ffffff",
    "name", "AdvancedTransitions",
    "allowScriptAccess","sameDomain",
    "type", "application/x-shockwave-flash",
    "pluginspage", "http://www.adobe.com/go/getflashplayer"
  );
} else if (hasRequestedVersion) {
  // if we've detected an acceptable version
  // embed the Flash Content SWF when all tests are passed
  AC_FL_RunContent(
      "src", "AdvancedTransitions",
      "width", "400",
      "height", "400",
      "align", "middle",
      "id", "AdvancedTransitions",
      "quality", "high",
      "bgcolor", "#ffffff",
      "name", "AdvancedTransitions",
      "flashvars",'historyUrl=history.htm%3F&lconid=' + lc_id + '',
      "allowScriptAccess","sameDomain",
      "type", "application/x-shockwave-flash",
      "pluginspage", "http://www.adobe.com/go/getflashplayer"
  );
  } else {  // flash is too old or we can't detect the plugin
    var alternateContent = 'Alternate HTML content should be placed here. '
    + 'This content requires the Adobe Flash Player. '
     + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
    document.write(alternateContent);  // insert non-flash content
  }
// -->
</script>
<noscript>
    <object classid="clsid:"
      id="AdvancedTransitions" width="400" height="400"
      codebase="http://fpdownload.macromedia.com/get/flashplayer/current/
swflash.cab">
      <param name="movie" value="AdvancedTransitions.swf" />
      <param name="quality" value="high" />
      <param name="bgcolor" value="#ffffff" />
      <param name="allowScriptAccess" value="sameDomain" />
      <embed src="AdvancedTransitions.swf" quality="high" bgcolor="#ffffff"
        width="400" height="400" name="AdvancedTransitions" align="middle"
        play="true"
        loop="false"
        quality="high"
        allowScriptAccess="sameDomain"
        type="application/x-shockwave-flash"
        pluginspage="http://www.adobe.com/go/getflashplayer">
      </embed>
  </object>
</noscript>
<iframe name="_history" src="history.htm" frameborder="0" scrolling="no" width="22"
height="0"></iframe>
</body>
</html>
Image from book


Flex Printing

Flex 2 has come a long way in its printing capabilities. It is now very simple to print simple components, as well as to print multiple pages of grid data.

All print jobs begin in the same way. The first thing to do is to create a new FlexPrintJob, followed by a call to start the print job. Then, simply add any object to the print job using the addObject method, and, finally, send it to the printer.

Basic Printing

Listing 8-8 is a very simple print job that adds a Label component to the print job.

Listing 8-8: A Simple Print Job
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
  <![CDATA[
  import mx.printing.FlexPrintJob;
  private function print():void {
    // create print job
    var printJob:FlexPrintJob = new FlexPrintJob();
    if(printJob.start()){
      // add page
      printJob.addObject(myLabel,"none");
      // send to printer
      printJob.send();
    }
  }
  ]]>
  </mx:Script>
  <mx:Label id="myLabel" text="Hello World" />
  <mx:Button click="print()" label="Print" />
</mx:Application>
Image from book

Printing Multiple Pages

Listing 8-8 prints the Label components’ text property "Hello World". However, you could just as easily have set the addObject target to be a VBox, which would print all child components. Try changing the line printJob.addObject(myLabel,"none"); to printJob.addObject(this,"none"); and Flex will now print both the Label and Button components.

By adding multiple objects to the print job, Listing 8-9 will print two pages: "Hello World page 1" and "Hello World page 2".

Listing 8-9: A Simple Multipage Print Job
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
      import mx.printing.FlexPrintJob;
     private function print():void {
       // create print job
       var printJob:FlexPrintJob = new FlexPrintJob();
       if(printJob.start()){
        // add 2 pages
         printJob.addObject(page1,"none");
          printJob.addObject(page2,"none");
          // send to printer
         printJob.send();
       }
     }
    ]]>
  </mx:Script>
  <mx:Label id="page1" text="Hello World page 1" />
  <mx:Label id="page2" text="Hello World page 2" />
  <mx:Button click="print()" label="Print" />
</mx:Application>
Image from book

Rather than hard-coding the objects to be added to the print job, you could also loop over an array to add pages dynamically.

Printing Grid Data

Another very common need is the ability to print grid data formatted properly. Flex 2 has made this a very easy thing to do. You can print multiple pages of data and Flex will handle all page breaks automatically. By simply advancing the print grid’s data using the nextPage() method, and then testing to see if the next page is valid within a while loop, you can add pages to the print job until there is a no additional data. At that point, simply break the loop and send the job to the printer. The other thing you will notice is that the visible property of the PrintDataGrid is set to false, but this doesn’t stop the job from printing correctly.

Listing 8-10 will display a regular DataGrid component, but will print a PrintDataGrid component across multiple pages.

Listing 8-10: PrintDataGrid Sample
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  creationComplete="initData()">
  <mx:Script>
    <![CDATA[
    import mx.collections.ArrayCollection;
    import mx.printing.FlexPrintJob;
    [Bindable]
    public var dp:ArrayCollection;
    // populate the dataProviders for the datagrids
    private function initData():void{
      this.dp = new ArrayCollection();
      for(var i:Number=0; i<60; i++){
        this.dp.addItem({row:i,data:"item " + i});
      }
    }
    public function print():void {
      // create print job
      var printJob:FlexPrintJob = new FlexPrintJob();
      // start print job
      if(printJob.start()){
        // add the print grid
        printJob.addObject(printGrid);
        while(true) {
          // loop through print grids data and add additonal pages if neccessary
          printGrid.nextPage();
          if(!printGrid.validNextPage){
            printJob.addObject(printGrid);
            break;
          }
        }
        // send to printer
        printJob.send();
      }
    }
    ]]>
  </mx:Script>
  <mx:DataGrid id="dataGrid" dataProvider="{dp}" height="200" width="200">
    <mx:columns>
      <mx:DataGridColumn dataField="row" headerText="Row Number" />
      <mx:DataGridColumn dataField="data" headerText="Row Data" />
    </mx:columns>
  </mx:DataGrid>
  <mx:Button click="print()" label="Print" />
  <mx:PrintDataGrid visible="false" id="printGrid" dataProvider="{dp}" height="700"
width="600">
    <mx:columns>
      <mx:DataGridColumn dataField="row" headerText="Row Number" />
      <mx:DataGridColumn dataField="data" headerText="Row Data" />
    </mx:columns>
  </mx:PrintDataGrid>
</mx:Application>
Image from book


Communicating with the Wrapper

The ExternalInterface API can communicate seamlessly from Flex to JavaScript, and from JavaScript to Flex. This gives the Flex application to access thousands of JavaScript methods and the browser access to all of the Flex methods. The ease of passing data from the browser to Flex and back opens up a whole new world of hybrid applications.

Setting up the calls between Flex and JavaScript is as simple as importing the ExternalInterface class and creating callbacks. Callbacks define the function names and handlers, and allow Flex methods to be called from JavaScript. On the JavaScript side, all that is needed is a method to determine the browser type (this is simply a way to get the correct document name) and then a call to the callback function name, which was defined within Flex.

Flex to JavaScript, JavaScript to Flex

Listing 8-11 will send messages from Flex to a JavaScript Alert, and also send messages from JavaScript to Flex.

Listing 8-11: Flex to JavaScript
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initApp()" backgroundColor="#FFFFFF"
     width="400" height="250">
  <mx:Script>
  import flash.external.ExternalInterface;
  import mx.controls.Alert;
  public function initApp():void {
    this.setupCallbacks();
  }
  // Called from JavaScript
  public function callFromJavascript(s:String):void {
    Alert.show(s,"Flex Alert");
  }
  // Call to JavaScript
  private function sendToJavaScript():void {
    ExternalInterface.call("getFromFlex",valueForJavascript.text);
  }
  // Set up callbacks
  private function setupCallbacks():void{
       ExternalInterface.addCallback("callFromJavascript",callFromJavascript);
  }
  </mx:Script>
  <mx:Panel title="ExternalInterface Sample" width="350" height="200">
    <mx:HBox>
      <mx:TextInput id="valueForJavascript" text="Hello From Flex" />
      <mx:Button click="this.sendToJavaScript()" label="Send to Javascript" />
    </mx:HBox>
  </mx:Panel>
</mx:Application>
Image from book

Listing 8-12 is the HTML file with the JavaScript to handle the calls to and from Flex.

Listing 8-12: HTML with JavaScript
Image from book

<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ExternalInterfaceSample</title>
<SCRIPT language='JavaScript' charset='utf-8'>
// get from Flex
function getFromFlex(s) {
  alert(s);
}
// send to Flex
function sendToFlex() {
 // Call a Flex function named callFromJavascript passing a string thisMovie
("ExternalInterfaceSample").callFromJavascript(document.form1.valueForFlex.value);
}
// Determine browser type
function thisMovie(movieName) {
  if (navigator.appName.indexOf("Microsoft") != -1) {
    return window[movieName];
  } else {
    return document[movieName];
  }
}
</SCRIPT>
</head>
<body scroll="no">
<br>
<div align="center">
<form name="form1">
  <input type="text" name="valueForFlex" value="Hello From JavaScript">
  <input type="button" onClick="sendToFlex()" value="Send to Flex">
</form>
<br>
  <object classid="clsid:"
    id="ExternalInterfaceSample" width="400" height="250"
    codebase="http://fpdownload.macromedia.com/get/flashplayer/current/
swflash.cab">
    <param name="movie" value="ExternalInterfaceSample.swf" />
    <param name="quality" value="high" />
    <param name="bgcolor" value="#ffffff" />
    <param name="allowScriptAccess" value="sameDomain" />
    <embed src="ExternalInterfaceSample.swf" quality="high" bgcolor="#ffffff"
      width="400" height="250" name="ExternalInterfaceSample" align="middle"
      play="true"
      loop="false"
      quality="high"
      allowScriptAccess="sameDomain"
      type="application/x-shockwave-flash"
      pluginspage="http://www.adobe.com/go/getflashplayer">
    </embed>
  </object>
</div>
</body>
</html>
Image from book

Verify that JavaScript Has Loaded

Listing 8-12 will work fine as long JavaScript is loaded before Flex has set up the callback methods. However, this is not something that can be assumed. There is a simple way to test to ensure that JavaScript has fully loaded and is ready before the callbacks are set up.

The first thing that is needed is a way for JavaScript to know whether it is ready. By setting a function call within the HTML body tags’ onload property, you can set a local Boolean variable storing the state of JavaScript’s readiness to true. This variable can then be returned to Flex when Flex calls to test JavaScript’s readiness.

The Flex side is a little more complicated. Once the Flex app is loaded, you call the method to get the JavaScript’s readiness state. If this returns true, you know JavaScript is ready, so you can set up the callbacks. If this variable returns false, a timer is created to poll JavaScript until it is ready. Once it is ready, the timer is stopped and the callbacks can be set up. Listing 8-13 and Listing 8-14 show how to test JavaScript’s readiness.

Listing 8-13: Flex Code to Test JavaScript
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     backgroundColor="#FFFFFF" creationComplete="initApp();"
     width="350" height="300">
  <mx:Script>
  import mx.controls.Alert;
  import flash.external.ExternalInterface;
  private function initApp():void{
    if(this.isJSReady()){
    // JavaScript ready so we can set up the callbacks from JavaScript
       this.setupCallbacks();
       } else {
       // create a timer to poll JavaScript until it is ready
       var readyTimer:Timer = new Timer(100);
      readyTimer.addEventListener(TimerEvent.TIMER, jsNotReady);
      readyTimer.start();
    }
  }
  private function isJSReady():Boolean {
    // Call to JavaScript to see if it is ready
    return ExternalInterface.call("isJSReady");;
  }
  private function jsNotReady(event:TimerEvent):void {
    // Check to see if JavaScript is ready and stop timer if it is
    if (this.isJSReady()) {
      Timer(event.target).stop();
      // JavaScript ready so we can set up the callbacks from JavaScript
      this.setupCallbacks();
    }
  }
  private function setupCallbacks():void{
    // Add callbacks here
    mx.controls.Alert.show("JavaScript is Ready");
  }
  </mx:Script>
</mx:Application>
Image from book
Listing 8-14: HTML Wrapper to Let Flex Know JavaScript Is Ready
Image from book

<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<SCRIPT language='JavaScript' charset='utf-8'>
function thisMovie(movieName) {
  if (navigator.appName.indexOf("Microsoft") != -1) {
    return window[movieName];
  } else {
    return document[movieName];
  }
}
var jsReady = false;
// called from Flex see if JavaScript is available
function isJSReady() {
  return jsReady;
}
// called when the body's onload fires
function init() {
  // JavaScript is now available
  jsReady = true;
}
</SCRIPT>
</head>
<body scroll="no" onload="init()">
<br>
<div align="center">
<br>
  <object classid="clsid:"
    id="ExternalInterfaceTest" width="350" height="300"
    codebase="http://fpdownload.macromedia.com/get/flashplayer/current/
swflash.cab">
    <param name="movie" value="ExternalInterfaceTest.swf" />
    <param name="quality" value="high" />
    <param name="bgcolor" value="#ffffff" />
    <param name="allowScriptAccess" value="sameDomain" />
    <embed src="ExternalInterfaceTest.swf" quality="high" bgcolor="#ffffff"
      width="350" height="300" name="ExternalInterfaceTest" align="middle"
      play="true"
      loop="false"
      quality="high"
      allowScriptAccess="sameDomain"
      type="application/x-shockwave-flash"
      pluginspage="http://www.adobe.com/go/getflashplayer">
    </embed>
  </object>
</div>
</body>
</html>
Image from book

The Flex/JavaScript communication bridge is accessible by default when the SWF is embedded in the same page as the JavaScript. This can be overridden by setting the allowScriptAccess property of the <object> and <embed> tags on the wrapper HTML page.


Working with Shared Objects

Shared objects are a very powerful tool in local data storage. It can be very useful for saving preference data to make the user experience a more personalized one. A good example would be a custom component layout in a portal-type application. You can also use the local shared object data storage to make an application perform correctly if the user is using the application offline. You can then write your own routines to sync back to the database server to store this information when a connection is established.

Saving and Reloading Data from Shared Objects

Listing 8-15 will save the user’s data to a SharedObject when the rememberMe CheckBox is selected. Upon selecting the CheckBox, the application will write the firstname and lastname properties to the SharedObjects data property and then call the flush method to save the data to the user’s hard drive. Reloading the application will fetch the SharedObject and show the first and last names as they are being bound to the text inputs.

Listing 8-15: Saving a Shared Object
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     backgroundColor="#FFFFFF" width="400" height="230">
  <mx:Script>
    <![CDATA[
    import mx.controls.Alert;
    [Bindable]
    public var user:SharedObject = SharedObject.getLocal("user");
    private function setSharedObject():void{
          // if checkbox is selected, create shared object data
      if(this.rememberMe.selected){
        user.data.firstname = this.firstname.text;
        user.data.lastname = this.lastname.text;
        user.flush();
        Alert.show("Your information has been saved, reload the application to see
your saved information.", "Alert");
      }
    }
    // clear all data from the shared object
    private function clearSharedObject():void{
      this.rememberMe.selected = false;
      user.clear();
      Alert.show("Your information has been cleared.", "Alert");
    }
    ]]>
  </mx:Script>
  <mx:Panel title="Shared Object Sample">
    <mx:Form>
      <mx:FormItem label="Firstname:">
        <mx:TextInput id="firstname" text="{user.data.firstname}" />
      </mx:FormItem>
      <mx:FormItem label="Lastname:">
        <mx:TextInput id="lastname" text="{user.data.lastname}" />
      </mx:FormItem>
      <mx:FormItem label="Remember Me" direction="horizontal">
        <mx:CheckBox id="rememberMe" change="setSharedObject()" />
      </mx:FormItem>
      <mx:FormItem direction="horizontal">
        <mx:Button label="Clear Shared Object" click="clearSharedObject()"/>
      </mx:FormItem>
    </mx:Form>
  </mx:Panel>
</mx:Application>
Image from book

Another option to saving the information would be to create an instance of a custom person class to store both the firstname and lastname properties, and then save the full object to the SharedObject.

Something to remember about SharedObjects is that users can determine the amount of disk space they are willing to give to storing these objects. Although the default is 100KB (which is a generous size for simple data), users can set it anywhere from none to unlimited within the Flash Player settings. If the application tries to store an object that pushes the storage total to be greater than the maximum allocated, users will get a dialog box asking them if they would like to increase the storage limit.


Designing Accessible Applications

The Flex Accessibility class allows for communication with screen readers for visually impaired users by providing the application’s content to the user as speech or by driving a Braille display.

Enabling Accessibility in Your Application

Flex does not have the accessibility features enabled by default. If you wish to enable accessibility for all applications under an FDS server, just make the following change to the flex-config.xml file:

<accessible>true</accessible>

You can also enable or disable (if the config file has been updated as mentioned previously) by adding accessible=true or accessible=true to the application’s URL. Here is a sample:

http://www.yourdomain.com/myapp/index.mxml?accessible=true

http://www.yourdomain.com/myapp/index.mxml?accessible=false

If you are using the SDK command-line compiler, you can add the following argument:

mxmlc -accessible c:/dev/myapps/mywar.war/app1.mxml

Components with Built-in Accessibility

Many of the Flex components have accessibility built in. For example, when a screen reader encounters a TabNavigator, it will indicate each tab by saying the word “tab” and then indicate the selected tab with the word “active.” The user can also navigate between tabs with the arrow keys and select a tab with the Enter key. For a complete description of the behaviors of all of the Flex-accessible components, please refer to the Flex documentation.

Customizing Your Components for Accessibility

Once your environment is set up for accessibility, you can add code to your application for defining custom names and descriptions of your components. The Accessibility class is static, and can be read or set on many Flex components by using the components’ accessibilityProperties property. To set accessibilityProperties, simply create an instance of the AccessibilityProperties class and assign properties. The properties you can assign include name, description, forceSimple (when set to true will hide any child components from a screen reader), silent (when set to true, will hide itself from the screen reader), and shortcut (where you can assign a keyboard shortcut).

You can do a run-time check to see if the user’s environment supports accessibility by using the Capabilities.hasAccessibility property. Accessibility.active will let you know if the user’s screen reader is present.

You must also include a call to Accessiblity.updateProperties() after you have assigned the new accessibilityProperties. This call should only be made one time after you have completed all of your updates to accessibilityProperties.

The following example checks the user’s machine and then creates and assigns AccessibilityProperties to a Button component:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete=
"initApp()">
  <mx:Script>
    <![CDATA[
    private function initApp():void{
      // Test user's environment for accessibility
      if(Capabilities.hasAccessibility){
           // Create and add AccessibilityProperties
        var accessProps:AccessibilityProperties = new AccessibilityProperties();
        accessProps.name = "Submit";
        accessProps.description = "Click this button to submit.";
        // assign accessibilityProperties to Button component
        submitBtn.accessibilityProperties = accessProps;
        // alert screen reader users of an update
        Accessiblity.updateProperties();
      }
    }
    ]]>
  </mx:Script>
  <mx:Button id="submitBtn" label="Submit"/>

</mx:Application>

Another important thing to remember about accessibility is that the application will be read from left to right, and from top to bottom, by default. To change the way the application is read, you can use the tabIndex property of every component to customize the read order of your application.


Summary

This chapter covered a wide range of user interface elements including repeaters, view states, transitions, drag-and-drop techniques, asset management, the History Manager, Flex printing, ExternalInterface, shared objects, and accessibility techniques. Although not very difficult to implement, many of the items covered in this chapter are used integrally to create a Flex application that has the look and feel of a “Web 2.0” application. By simply adding drag-and-drop or transitions, you can give your application something that is very complicated, or simply impossible, with standard HTML.

Chapter 9 demonstrates many ways to bind data using regular variables, Flex models, and external XML. It also shows you how to validate and format data.


Chapter 9: Flex Data

This chapter discusses a variety of topics concerning working with data within your Flex application. The discussion examines different ways to bind, store, validate, and format data. Flex makes handling data very easy. You will see several ways to accomplish each of these tasks.

Data Binding

When developing rich applications, you will encounter the need to reflect values from components, or data models to other components. MXML simplifies the process of syncing data values between components. This process is known as data binding.

Using <mx:Binding>

The mx:Binding tag is a very simple way to bind data between Flex components without the use of ActionScript. The usage is as simple as setting a source and a destination. Once you have done this, the destination component will automatically update whenever there is a change to the source property. The following example binds the text property for the TextInput component bindFrom to the text property of the destination component bindTo. This is a known as a one-way binding. To make the binding work in both directions, you can add a second binding tag right below the first, with the source and destination in reverse. An example would be <mx:Binding source="bindTo.text" destination="bindFrom.text" />, as shown here:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
      backgroundColor="#FFFFFF">
  <mx:Binding source="bindFrom.text" destination="bindTo.text" />
  <mx:Panel title="Simple Binding Example" width="300" height="150">
    <mx:Form>
     <mx:FormItem label="Bind From">
       <mx:TextInput id="bindFrom" />
     </mx:FormItem>
     <mx:FormItem label="Bind To">
       <mx:TextInput id="bindTo" />
      </mx:FormItem>
    </mx:Form>
  </mx:Panel>
</mx:Application>

The results of the code can be seen in Figure 9-1.

Image from book
Figure 9-1: Results of using <mx:Binding>

Binding to Variables with [Bindable]

Flex also allows data to be bound using ActionScript. By declaring a variable or a class with the [Bindable] metadata tag, you can then bind the variable to your components surrounding it with curly braces. Flex will then update the component whenever there is a change to the bound variable. If the class is declared as [Bindable], all public properties within the class will be bindable.

The following example declares a variable named myLabelName, sets it to be the String "Hello World", and binds it to a Label component. When the application initializes, “Hello World” will show as the text of the Label. The application also contains a TextInput component that is set to update the myLabelName variable on its change event. When the user types into the TextInput component, the myLabelName variable is updated and the change is also seen in the Label component that it is bound to.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">
   <mx:Script>
     <![CDATA[
       [Bindable]
       public var myLabelName:String = "Hello World";

     ]]>
   </mx:Script>
  <mx:Panel title="Binding With Curly Braces" width="350" height="150">
    <mx:Label text="{myLabelName}" />
    <mx:Label text="Type into the text field below to hange text above" />
    <mx:TextInput id="newText" change="myLabelName=newText.text" />
  </mx:Panel>
</mx:Application>

Figure 9-2 shows how the application looks after it initializes, and Figure 9-3 shows how the Label has been updated after typing in the TextInput.

Image from book
Figure 9-2: Application after it initializes
Image from book
Figure 9-3: Updating the Label

Binding Directly to Component Properties

You can also bind directly to component properties. This allows you to dynamically adjust the view. This is a great way to show and hide components when conditions make this desirable. The following example binds the HSlider’s value property to the width property of the Panel. Moving the slider automatically adjusts the width of the Panel.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">

  <mx:Panel title="Empty Panel" width="{mySlider.value}" height="150" />
  <mx:TextArea width="300" text="The width property of the Panel above is bound to
the value property of the HSlider below." />
  <mx:HSlider id="mySlider" snapInterval="5" minimum="100" maximum="350"
value="250"/>
</mx:Application>

Figure 9-4 shows how the application looks when the slider is set to 300, and Figure 9-5 shows how the application has changed when the slider is moved to 160.

Image from book
Figure 9-4: Slider set to 300
Image from book
Figure 9-5: Slider set to 160

Data Modeling with Flex

There are many ways to model data with Flex. The following examples show a few ways to model the same data. All of the examples will produce the exact same results, as shown in Figure 9-6.

Image from book
Figure 9-6: Data modeling

A Basic Data Model

Using the mx:Model tag and nested XML structures, it is very easy to create an object model that is automatically bindable. This allows for rapid generation of forms and other data-driven client interfaces.

The following example creates a simple mx:Model with an id of contactmodel. The individual properties of the contactmodel are then bound to the Label components.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">
  <mx:Model id="contactmodel">
    <contact>
      <fname>Rich</fname>
      <lname>Tretola</lname>
      <address>101 Skye St.</address>
      <city>Anytown</city>
      <state>NY</state>
      <zip>11111</zip>
      <phone>5165559999</phone>
      <email>proflex2@gmail.com</email>
    </contact>
  </mx:Model>
  <mx:Panel title="Contact Info" width="200" height="170">
    <mx:Label text="{contactmodel.fname} {contactmodel.lname}" />
    <mx:Label text="{contactmodel.address}" />
    <mx:Label text="{contactmodel.city} {contactmodel.state}, {contactmodel.zip}" />
    <mx:Label text="{contactmodel.phone}" />
    <mx:Label text="{contactmodel.email}" />
  </mx:Panel>
</mx:Application>

Using an External XML File

Listing 9-1 and Listing 9-2 both use the Contact.xml file to load external data by binding it to the source property on the mx:Model and mx:XML components. Their only difference is that one uses mx:Model and the other uses mx:XML. The examples are simply meant to show that you can use either of these mx tags to bind to an external XML file. The contactmodel properties are then bound to the Label components just as in the previous example. A benefit of using an external XML file over that of an mx:Model is that the XML can be updated, and the changes will be reflected the next time the data is loaded without the need to recompile the application. The results can be seen in Figure 9-6. The following is the Contact.xml file.

<?xml version="1.0"?>
<contact>
  <fname>Rich</fname>
  <lname>Tretola</lname>
  <address>101 Skye St.</address>
  <city>Anytown</city>
  <state>NY</state>
  <zip>11111</zip>
  <phone>5165559999</phone>
  <email>proflex2@gmail.com</email>
</contact>
Listing 9-1: Binding to Contact.xml File with <mx:Model>
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">
  <mx:Model source="Contact.xml" id="contactmodel"/>
  <mx:Panel title="Contact Info" width="200" height="170">
    <mx:Label text="{contactmodel.fname} {contactmodel.lname}" />
    <mx:Label text="{contactmodel.address}" />
    <mx:Label text="{contactmodel.city} {contactmodel.state}, {contactmodel.zip}" />
    <mx:Label text="{contactmodel.phone}" />
    <mx:Label text="{contactmodel.email}" />
  </mx:Panel>
</mx:Application>
Image from book
Listing 9-2: Binding to Contact.xml File with <mx:XML>
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">
  <mx:XML source="Contact.xml" id="contactmodel"/>
  <mx:Panel title="Contact Info" width="200" height="170">
    <mx:Label text="{contactmodel.fname} {contactmodel.lname}" />
    <mx:Label text="{contactmodel.address}" />
    <mx:Label text="{contactmodel.city} {contactmodel.state}, {contactmodel.zip}" />
    <mx:Label text="{contactmodel.phone}" />
    <mx:Label text="{contactmodel.email}" />
  </mx:Panel>
</mx:Application>
Image from book

Binding a Data Model to a Custom Component

To facilitate good code reuse habits, you can create a custom component to accomplish the same results shown in Listing 9-1 and Listing 9-2. The component shown in Listing 9-3 and Listing 9-4 is a simple VBox that has a public [Bindable] variable named contactmodel, which is of type Object. This component can then be used in multiple places within your application, and only requires that you pass in an object containing the properties that you are binding to. In this case, this would be a contactmodel. The example shown in these listings produces the same results as shown in Figure 9-6.

Listing 9-3: Custom Component Contact.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
     [Bindable]
     public var contactmodel:Object;
    ]]>
  </mx:Script>
  <mx:Label text="{contactmodel.fname} {contactmodel.lname}" />
  <mx:Label text="{contactmodel.address}" />
  <mx:Label text="{contactmodel.city} {contactmodel.state}, {contactmodel.zip}" />
  <mx:Label text="{contactmodel.phone}" />
  <mx:Label text="{contactmodel.email}" />
</mx:VBox>
Image from book
Listing 9-4: Binding to Contact.xml File with <mx:Model> and a Custom Component
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" xmlns:comps="*">
  <mx:Model source="Contact.xml" id="contactmodel"/>
  <mx:Panel title="Contact Info" width="200" height="170">
    <comps:Contact contactmodel="{this.contactmodel}" />
  </mx:Panel>
</mx:Application>
Image from book

It is simple to add a second instance of the Contact custom component to Listing 9-3 and Listing 9-4 to create two complete components. The power of this comes in when you bind the second component to a different model. The following code binds to Contact.xml, as was done earlier, but also binds to Contact2.xml, which is another XML file with the same structure as Contact.xml with different values.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" xmlns:comps="*">
  <mx:Model source="Contact.xml" id="contactmodel"/>
  <mx:Model source="Contact2.xml" id="vacationmodel"/>
  <mx:Panel title="Contact Info" width="300" height="170" layout="horizontal">
    <comps:Contact contactmodel="{this.contactmodel}" />
    <mx:Spacer width="20" />
    <comps:Contact contactmodel="{this.vacationmodel}" />
  </mx:Panel>
</mx:Application>

Figure 9-7 shows the results of this code.

Image from book
Figure 9-7: Adding a second instance of a component

Binding Data to a Data Model

So far, you have seen examples of binding data from a model to components. However, you can also bind from the component value to the model. Listing 9-5 will bind the text properties of the TextInput components to the model.

Listing 9-5: Binding from the Components to the Model
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="550" height="300">
   <mx:Script>
        <![CDATA[
          import mx.controls.Alert;
       private function modelToString():void{
         Alert.show(contactmodel.fname + " " + contactmodel.lname + "\n" +
contactmodel.address + "\n" +
                    contactmodel.city + " " + contactmodel.state + " " +
contactmodel.zip + "\n" +
                    contactmodel.phone + "\n" +contactmodel.email,"contactmodel");
       }
     ]]>
   </mx:Script>
  <mx:Model id="contactmodel">
    <contact>
      <fname>{fnametxt.text}</fname>
      <lname>{lnametxt.text}</lname>
      <address>{addresstxt.text}</address>
      <city>{citytxt.text}</city>
      <state>{statetxt.text}</state>
      <zip>{ziptxt.text}</zip>
      <phone>{phonetxt.text}</phone>
      <email>{emailtxt.text}</email>
    </contact>
  </mx:Model>
  <mx:Panel title="Contact Info" width="500" height="250">
  <mx:Form>
    <mx:FormItem label="Name" direction="horizontal">
      <mx:TextInput id="fnametxt" />
      <mx:TextInput id="lnametxt" />
    </mx:FormItem>
    <mx:FormItem label="Address">
      <mx:TextInput id="addresstxt"/>
    </mx:FormItem>
    <mx:FormItem label="City State, Zip" direction="horizontal">
      <mx:TextInput id="citytxt"/>
      <mx:TextInput id="statetxt" width="20"/>
      <mx:TextInput id="ziptxt" width="50"/>
    </mx:FormItem>
    <mx:FormItem label="Phone">
      <mx:TextInput id="phonetxt"/>
    </mx:FormItem>
    <mx:FormItem label="Email">
      <mx:TextInput id="emailtxt"/>
    </mx:FormItem>
    <mx:Button click="modelToString()" label="Show Model Data"/>
  </mx:Form>
  </mx:Panel>
</mx:Application>
Image from book

You can see the evidence of this when clicking the Show Model Data button. This will launch an Alert component showing the values of the data in the contactmodel, as shown in Figure 9-8.

Image from book
Figure 9-8: Binding from components to the model


Validating Data

Flex has many built-in validator classes and also allows its base validator classes to be extended to easily create custom validators for your own projects. Say your company has a very specific format in its product codes. You could easily write a custom validator that validates that the product code matches the specified pattern. The following examples show how to use the built-in validators, as well as how to create a custom validator.

Flex Built-in Validators

Listing 9-6 shows how to use the built-in validator classes and assign their properties. Each validator has a several properties defined as shown in the following table. The validators in the first example are bound to each TextInput’s text property. They are set to trigger when the Validate button is clicked, and the listener is the corresponding TextInput. The results of this example can be seen in Figure 9-9. Notice the usage of different types of validators contextual to the type of form field. For example, the ziptxt field uses the built-in ZipCodeValidator, which not only checks to see if the field has been filled in, but also checks to see if the value is a 5-digit number or a 5-digit + 4-digit number.

Open table as spreadsheet
Property | Description
source | Bound to the object containing the data.
property | Property of the source object containing the data.
trigger | Bound to the object that will trigger the validation.
triggerEvent | The event of the trigger object that causes the validation.
listener | The object that will get the validation response and error string.
enabled | Setting this value to false will stop the validator from performing validation.
required | If true, specifies that a missing or empty value causes a validation error. Default is true.
requiredFieldError | Error message when a value is missing and the required property is true.
Listing 9-6: Built-in Validator Classes
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="550" height="300">
  <mx:Validator required="true" source="{fnametxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{fnametxt}"/>
  <mx:Validator required="true" source="{lnametxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{lnametxt}"/>
  <mx:Validator required="true" source="{addresstxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{addresstxt}"/>
  <mx:Validator required="true" source="{citytxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{citytxt}"/>
  <mx:Validator required="true" source="{statetxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{statetxt}"/>
  <mx:ZipCodeValidator required="true" source="{ziptxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{ziptxt}"/>
  <mx:EmailValidator source="{emailtxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{emailtxt}"/>
  <mx:PhoneNumberValidator source="{phonetxt}" property="text"
    trigger="{validatebtn}" triggerEvent="click" listener="{phonetxt}"/>
  <mx:Panel title="Contact Info" width="500" height="250">
  <mx:Form>
    <mx:FormItem label="Name" direction="horizontal">
      <mx:TextInput id="fnametxt" />
      <mx:TextInput id="lnametxt" />
    </mx:FormItem>
    <mx:FormItem label="Address">
      <mx:TextInput id="addresstxt"/>
    </mx:FormItem>
    <mx:FormItem label="City State, Zip" direction="horizontal">
      <mx:TextInput id="citytxt"/>
      <mx:TextInput id="statetxt" width="20"/>
      <mx:TextInput id="ziptxt" width="50"/>
    </mx:FormItem>
    <mx:FormItem label="Phone">
      <mx:TextInput id="phonetxt"/>
    </mx:FormItem>
    <mx:FormItem label="Email">
      <mx:TextInput id="emailtxt"/>
    </mx:FormItem>
    <mx:Button id="validatebtn" label="Validate"/>
  </mx:Form>
  </mx:Panel>
</mx:Application>
Image from book
Image from book
Figure 9-9: Validating a data model

Validating a Data Model

Listing 9-6 validated the values entered into each TextInput separately. Listing 9-7 shows another way to validate the same data. This example binds all of the TextInput text properties to a data model. The data model is then set as the source for the validators, and the property is now set as the data model’s corresponding property. Each validator also has the listener property set to be the TextInput component so that the error string will be applied to the visual component and not the model.

Listing 9-7: Binding to a Data Model
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="550" height="300">
  <mx:Model id="contactmodel">
    <contact>
      <fname>{fnametxt.text}</fname>
      <lname>{lnametxt.text}</lname>
      <address>{addresstxt.text}</address>
      <city>{citytxt.text}</city>
      <state>{statetxt.text}</state>
      <zip>{ziptxt.text}</zip>
      <phone>{phonetxt.text}</phone>
      <email>{emailtxt.text}</email>
    </contact>
  </mx:Model>
  <mx:Validator required="true" source="{contactmodel}" property="fname"
    trigger="{validatebtn}" triggerEvent="click" listener="{fnametxt}"/>
  <mx:Validator required="true" source="{contactmodel}" property="lname"
    trigger="{validatebtn}" triggerEvent="click" listener="{lnametxt}"/>
  <mx:Validator required="true" source="{contactmodel}" property="address"
    trigger="{validatebtn}" triggerEvent="click" listener="{addresstxt}"/>
  <mx:Validator required="true" source="{contactmodel}" property="city"
    trigger="{validatebtn}" triggerEvent="click" listener="{citytxt}"/>
  <mx:Validator required="true" source="{contactmodel}" property="state"
    trigger="{validatebtn}" triggerEvent="click" listener="{statetxt}"/>
  <mx:ZipCodeValidator required="true" source="{contactmodel}" property="zip"
    trigger="{validatebtn}" triggerEvent="click" listener="{ziptxt}"/>
  <mx:EmailValidator source="{contactmodel}" property="email"
    trigger="{validatebtn}" triggerEvent="click" listener="{emailtxt}"/>
  <mx:PhoneNumberValidator source="{contactmodel}" property="phone"
    trigger="{validatebtn}" triggerEvent="click" listener="{phonetxt}"/>
  <mx:Panel title="Contact Info" width="500" height="250">
  <mx:Form>
    <mx:FormItem label="Name" direction="horizontal">
      <mx:TextInput id="fnametxt" />
      <mx:TextInput id="lnametxt" />
    </mx:FormItem>
    <mx:FormItem label="Address">
      <mx:TextInput id="addresstxt"/>
    </mx:FormItem>
    <mx:FormItem label="City State, Zip" direction="horizontal">
      <mx:TextInput id="citytxt"/>
      <mx:TextInput id="statetxt" width="20"/>
      <mx:TextInput id="ziptxt" width="50"/>
    </mx:FormItem>
    <mx:FormItem label="Phone">
      <mx:TextInput id="phonetxt"/>
    </mx:FormItem>
    <mx:FormItem label="Email">
      <mx:TextInput id="emailtxt"/>
    </mx:FormItem>
    <mx:Button id="validatebtn" label="Validate Data Model"/>
  </mx:Form>
  </mx:Panel>
</mx:Application>
Image from book

Figure 9-9 shows the results of Listing 9-6. However, because Listing 9-7 is simply a different way to validate the same data, the application will also look like Figure 9-9.

Simple Data Validation Using errorString

If the Flex Validation Components do not serve your needs, you can choose to write your own custom validation code in ActionScript and assign the errorString, which will show on the component as the default red border and error tooltip. Listing 9-8 does a simple check to see if the TextInput being validated has a length of 10 characters. If the length of the myText.text property is less than 10, an errorString is assigned. If the length is greater than 10, the errorString is set to null, which removes the red border and tooltip.

Listing 9-8: Simple Data Validation
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="300" height="150">
   <mx:Script>
        <![CDATA[
         private function validate():void{
       // check for length of 10
       if(myText.text.length < 10){
         // assign errorString to TextInput
         myText.errorString = "This field requires at least 10 characters";
       } else {
         // remove errorString
         myText.errorString = null;
       }
     }
     ]]>
   </mx:Script>
   <mx:Panel title="Simple AS Validate" width="210" height="75">
     <mx:HBox width="100%" height="100%" paddingLeft="3" paddingTop="3">
       <mx:TextInput id="myText" width="100"/>
       <mx:Button label="Validate" click="validate()" />
     </mx:HBox>
   </mx:Panel>
</mx:Application>
Image from book

The results of Listing 9-8 can be seen in Figure 9-10 and Figure 9-11.

Image from book
Figure 9-10: The errorString when validation fails
Image from book
Figure 9-11: The same example as Figure 9-10, but this time the data is valid

Testing Validation Events

To gain even more control over validation, validators can be triggered using ActionScript. The validate method of any Flex validator returns an object of type ValidationResultEvent. By testing the results object’s “type” property against the static INVALID property of a ValidationResultEvent, you can track the overall validation of the form. Because you are calling the validate method on validators that have their listeners defined, the red border and error string tooltips will be automatically applied. Once you are sure all of the validators have returned true, you can then submit the form data to whatever service is needed to handle the valid data. Listing 9-9 follows this method of validation and returns the results in an Alert popup after each validation attempt.

Listing 9-9: Testing Validation Events
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="550" height="300">
  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;
      import mx.events.ValidationResultEvent;
      private var validator:ValidationResultEvent;

                     // Handle validation of data model
      private function validate():void{
        var isValid:Boolean=true;
        if(!this.validateDataModel()){
          isValid=false;
        }
        Alert.show("Results = "+isValid,"Validation");
      }
      // Check each field that needs validation and return true|false
      private function validateDataModel():Boolean{
        var isValid:Boolean = true;
        validator = fNameValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = lNameValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = addressValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = cityValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = stateValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = zipValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = emailValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        validator = phoneValidator.validate();
        if(validator.type == ValidationResultEvent.INVALID){
          isValid = false;
        }
        return isValid;
      }
    ]]>
  </mx:Script>
  <mx:Model id="contactmodel">
    <contact>
      <fname>{fnametxt.text}</fname>
      <lname>{lnametxt.text}</lname>
      <address>{addresstxt.text}</address>
      <city>{citytxt.text}</city>
      <state>{statetxt.text}</state>
      <zip>{ziptxt.text}</zip>
      <phone>{phonetxt.text}</phone>
      <email>{emailtxt.text}</email>
    </contact>
  </mx:Model>
  <mx:Validator id="fNameValidator" required="true" source="{contactmodel}"
property="fname" listener="{fnametxt}"/>
  <mx:Validator id="lNameValidator" required="true" source="{contactmodel}"
property="lname" listener="{lnametxt}"/>
  <mx:Validator id="addressValidator" required="true" source="{contactmodel}"
property="address" listener="{addresstxt}"/>
  <mx:Validator id="cityValidator" required="true" source="{contactmodel}"
property="city" listener="{citytxt}"/>
  <mx:Validator id="stateValidator" required="true" source="{contactmodel}"
property="state" listener="{statetxt}"/>
  <mx:ZipCodeValidator id="zipValidator" required="true" source="{contactmodel}"
property="zip" listener="{ziptxt}"/>
  <mx:EmailValidator id="emailValidator" source="{contactmodel}" property="email"
listener="{emailtxt}"/>
  <mx:PhoneNumberValidator id="phoneValidator" source="{contactmodel}"
property="phone" listener="{phonetxt}"/>
  <mx:Panel title="Contact Info" width="500" height="250">
  <mx:Form>
    <mx:FormItem label="Name" direction="horizontal">
      <mx:TextInput id="fnametxt" />
      <mx:TextInput id="lnametxt" />
    </mx:FormItem>
    <mx:FormItem label="Address">
      <mx:TextInput id="addresstxt"/>
    </mx:FormItem>
    <mx:FormItem label="City State, Zip" direction="horizontal">
      <mx:TextInput id="citytxt"/>
      <mx:TextInput id="statetxt" width="20"/>
      <mx:TextInput id="ziptxt" width="50"/>
    </mx:FormItem>
    <mx:FormItem label="Phone">
      <mx:TextInput id="phonetxt"/>
    </mx:FormItem>
    <mx:FormItem label="Email">
      <mx:TextInput id="emailtxt"/>
    </mx:FormItem>
    <mx:Button id="validatebtn" label="Validate Data Model" click="validate()"/>
  </mx:Form>
  </mx:Panel>
</mx:Application>
Image from book

Figure 9-12 shows the results of Listing 9-9.

Image from book
Figure 9-12: Validation popup

Validating with ActionScript

Another method of validating data is to create and trigger your validators using only ActionScript. Listing 9-10 creates an EmailValidator component as a new object using its default constructor, rather than in the previous examples where validators were created using MXML tags. You can see that the source and property properties are set using ActionScript as well. Both methods of validation will have the same results, so deciding whether to use MXML or ActionScipt to define your validators is more a choice of personal preference.

Listing 9-10: Validating with ActionScript
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="400" height="150">
  <mx:Script>
    <![CDATA[
      import mx.events.ValidationResultEvent;
      import mx.validators.EmailValidator;

      private var isValid:Boolean;
      public var emailValidator:EmailValidator = new EmailValidator();
      public var validator:ValidationResultEvent;

      public function validate():void {
        // set validators source
        emailValidator.source = email;
        // set validators property
        emailValidator.property = "text";
        // call validate()
        validator = emailValidator.validate();
        if (validator.type==ValidationResultEvent.VALID)
{
          isValid = true;
        } else {
          isValid = false;
        }
      }
    ]]>
  </mx:Script>
  <mx:Panel title="Validate with ActionScript" width="210" height="75">
    <mx:HBox width="100%" height="100%" paddingLeft="3" paddingTop="3">
      <mx:TextInput id="email" width="100"/>
      <mx:Button label="Validate" click="validate()" />
    </mx:HBox>
  </mx:Panel>
</mx:Application>
Image from book

Figure 9-13 shows the results of Listing 9-10.

Image from book
Figure 9-13: Validating with ActionScript


Formatting Data

Formatting data for display is quite easy with Flex 2 because it ships with many built-in formatters, as well as making it very easy to create custom formatters when needed. The following section shows how to use a built-in formatter. Chapter 15 provides more information on custom formatters.

Flex Built-in Formatters

Formatters are an easy way to format data into standard character patterns. There are many built-in formatters including phone, zip code, currency, date formatters, plus many more. Many formatters will accept a formatString property, which will define the way in which the data will be represented. Formatting the data is as simple as calling the format method and passing in the data to be formatted.

The following example uses the DateFormatter and shows three different ways to format the same data; along with the data is its raw format:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="500" height="280">

  <mx:DateFormatter id="dateFormatShort" formatString="MM/DD/YY"/>
  <mx:DateFormatter id="dateFormatMedium" formatString="MMM DD, YY"/>
  <mx:DateFormatter id="dateFormatFull" formatString="MMMM DD, YYYY"/>

  <mx:Panel title="Simple Formatter"
          layout="horizontal" width="100%" height="100%">
    <mx:DateChooser id="cal" />

    <mx:VBox>
         <mx:Label text="{cal.selectedDate}"/>
      <mx:Label text="{dateFormatShort.format(cal.selectedDate)}"/>
      <mx:Label text="{dateFormatMedium.format(cal.selectedDate)}"/>
      <mx:Label text="{dateFormatFull.format(cal.selectedDate)}"/>
    </mx:VBox>

  </mx:Panel>
</mx:Application>

The selectedDate property of the DateChooser is being bound to four Label components, with the top one showing the data in its raw format, and the next three using different formatStrings to represent the same data. The results can be seen in Figure 9-14.

Image from book
Figure 9-14: Using built-in formatters

Formatter Errors

Formatters also contain an error property that allows you to get information on the status of the formatter. The error property will return as an empty string when there is no error, or “Invalid Data” when an error exists after calling the format method. Check the documentation on each formatter to see the default errors that are returned.

The following example will attempt to format the phone number using PhoneFormatter every time the data changes. The error property returns with the invalid string on every call until the phone number is valid.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
    [Bindable]
    public var results:String="";
    public function formatNow():void {
      phoneFormatter.format(phone.text);
      // Check value of error property
      if(phoneFormatter.error == "Invalid value"){
           // append error to results
        results+=phoneFormatter.error+" - "+ phone.text + "<br/>";
      } else {
           // append to results
        results+="Valid Phone Number - "+phoneFormatter.format(phone.text) + "<br/>";
        // format original TextInput
        phone.text=phoneFormatter.format(phone.text);
      }
    }
    ]]>
  </mx:Script>

  <mx:PhoneFormatter id="phoneFormatter"
    formatString="(###) ###-####" validPatternChars="#-() "/>

  <mx:Panel title="Formatter Error Example" width="300" height="300"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

  <mx:HBox>
    <mx:Label text="Phone number:" />
    <mx:TextInput id="phone" width="75%" change="formatNow()" restrict="0-9()-."/>
  </mx:HBox>
  <mx:TextArea id="formatterResults" htmlText="{results}" width="100%"
height="100%" editable="false"/>
  </mx:Panel>
</mx:Application>

In a real-world application, it would be better to use a validator and only attempt to format when the data passes validation. You can see the results of this in Figure 9-15.

Image from book
Figure 9-15: Shows the PhoneFormatter’s error property changing on each keystroke

When creating a custom formatter, you can return custom error strings. Chapter 15 provides an example of custom error strings.


Summary

This chapter demonstrated the many different ways to bind data, including using data models and external XML data, as well as simple variable bindings. There were also examples showing a few different methods to validate data. Lastly, the Formatter classes were discussed and some examples were provided to demonstrate how to format and how to catch formatter errors.

Chapter 10 discusses the Flex charting classes, and provides examples of the many chart types and ways to alter the display of the charts. Some advanced charting techniques (including chart events, drill-down charts, and axis manipulation) are demonstrated. Finally, examples of ways to style a chart are shown.


Chapter 10: Flex Charting

This chapter examines the rich capabilities of Flex charting. This chapter is very code-intensive, and offers examples of all of the Flex charting components, as well as examples of some of the advanced features.

Flex Chart Examples

The ability to take data and represent it graphically with such ease is something that is uniquely Flex. Data visualization is one of those features that creates the “wow” factor that leaves a great impression on your audience. Outside of the HighLowOpenClose and Candlestick charts, all of the following examples will share the same data, but will represent it differently. Listing 10-1 shows the data class that will be used.

Listing 10-1: ChartData.as
Image from book

package
{
  import mx.collections.ArrayCollection;

  public class ChartData
  {
    public function getDataSet1():ArrayCollection{
      var productSales:ArrayCollection = new ArrayCollection( [
            { Quarter: "1", Gizmos: 10000, Widgets: 3000, Gadgets: 1000,
Total: 14000 },
            { Quarter: "2", Gizmos: 12000, Widgets: 4000, Gadgets: 2000,
Total: 18000 },
            { Quarter: "3", Gizmos: 15000, Widgets: 8000, Gadgets: 5000,
Total: 28000 },
            { Quarter: "4", Gizmos: 20000, Widgets: 10000, Gadgets: 9000,
Total: 39000 }
            ]);
            return productSales;
    }

    public function getStockData1():ArrayCollection{
      var goog:ArrayCollection = new ArrayCollection( [
      { date: "3-Jul-06", open: 420.04, high: 423.77, low: 419.45, close: 423.20,
volume: "2,156,700" },
      { date: "5-Jul-06", open: 421.52, high: 422.80, low: 415.64, close: 421.46,
volume: "4,985,600" },
      { date: "6-Jul-06", open: 423.38, high: 425.38, low: 421.98, close: 423.19,
volume: "3,687,100" },
      { date: "7-Jul-06", open: 426.05, high: 427.89, low: 415.88, close: 420.45,
volume: "6,041,900" },
      { date: "10-Jul-06", open: 423.44, high: 425.23, low: 416.38, close: 418.20,
volume: "4,436,400" },
      { date: "11-Jul-06", open: 418.51, high: 425.05, low: 413.03, close: 424.56,
volume: "5,971,300" },
      { date: "12-Jul-06", open: 422.09, high: 422.74, low: 416.73, close: 417.25,
volume: "4,906,700" },
      { date: "13-Jul-06", open: 414.00, high: 418.34, low: 406.83, close: 408.83,
volume: "6,924,500" },
      { date: "14-Jul-06", open: 410.33, high: 411.49, low: 398.61, close: 403.50,
volume: "7,552,100" },
      { date: "17-Jul-06", open: 404.63, high: 411.00, low: 403.72, close: 407.89,
volume: "5,811,900" },
      { date: "18-Jul-06", open: 409.75, high: 410.57, low: 397.74, close: 403.05,
volume: "8,536,800" },
      { date: "19-Jul-06", open: 395.01, high: 401.14, low: 394.66, close: 399.00,
volume: "8,518,500" },
      { date: "20-Jul-06", open: 404.28, high: 404.44, low: 385.66, close: 387.12,
volume: "12,538,700" },
      { date: "21-Jul-06", open: 386.14, high: 391.75, low: 377.69, close: 390.11,
volume: "11,754,600" },
      { date: "21-Jul-06", open: 386.14, high: 391.75, low: 377.69, close: 390.11,
volume: "11,754,600" },
      { date: "24-Jul-06", open: 392.82, high: 393.89, low: 381.21, close: 390.90,
volume: "8,086,100" },
      { date: "25-Jul-06", open: 385.02, high: 391.31, low: 383.80, close: 389.36,
volume: "5,761,100" },
      { date: "26-Jul-06", open: 388.20, high: 391.91, low: 383.00, close: 385.50,
volume: "5,531,900" },
      { date: "27-Jul-06", open: 387.37, high: 387.49, low: 377.95, close: 382.40,
volume: "5,641,100" },
      { date: "28-Jul-06", open: 382.00, high: 389.56, low: 381.73, close: 388.12,
volume: "4,083,600" },
      { date: "31-Jul-06", open: 388.00, high: 389.17, low: 383.31, close: 386.60,
volume: "4,595,300" }
      ]);
      return goog;
    }
  }
}
Image from book

Area Chart

As shown in Listing 10-2, the AreaChart component displays its data by lines with fills bounded to these lines to represent the values of the AreaSeries. The area chart has various representations, such as overlaid, stacked, 100 percent stacked, and high-low areas.

Listing 10-2: Area Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
    import  mx.collections.ArrayCollection;

     private  var  chartData:ChartData  =  new  ChartData();
     [Bindable]
     private  var  productSales:ArrayCollection;
    private  function  initApp():void{
      productSales  =  chartDAre ata.getDataSet1();
    }
    ]]>
  </mx:Script>

  <mx:Panel  title="AreaChart  Example"  width="100%"  height="100%"
    paddingTop="10"  paddingLeft="10"  paddingRight="10"  paddingBottom="10">
    <mx:AreaChart  id="areaChart"  height="100%"  width="100%"
        paddingLeft="5"  paddingRight="5"
        showDataTips="true"  dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis  categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:AreaSeries  yField="Gizmos"  form="curve"  displayName="Gizmos"/>
        <mx:AreaSeries  yField="Widgets"  form="curve"  displayName="Widgets"/>
        <mx:AreaSeries  yField="Gadgets"  form="curve"  displayName="Gadgets"/>
      </mx:series>
    </mx:AreaChart>
    <mx:Legend  dataProvider="{areaChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-1 shows an area chart.

Image from book
Figure 10-1: Area chart

Bar Chart

The BarChart component displays data in a series of horizontal bars representing the data of the BarSeries. The bar chart variations include clustered bars, overlaid, stacked, 100 percent stacked, and high-low areas.

Listing 10-3: Bar Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }
    ]]>
  </mx:Script>

  <mx:Panel title="BarChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

     <mx:BarChart id="barChart" height="100%" width="100%"
      paddingLeft="5" paddingRight="5"
      showDataTips="true" dataProvider="{productSales}">
      <mx:verticalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:verticalAxis>
      <mx:series>
        <mx:BarSeries yField="Quarter" xField="Gizmos" displayName="Gizmos"/>
        <mx:BarSeries yField="Quarter" xField="Widgets" displayName="Widgets"/>
        <mx:BarSeries yField="Quarter" xField="Gadgets" displayName="Gadgets"/>
      </mx:series>
    </mx:BarChart>
    <mx:Legend dataProvider="{barChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

The bars can be clustered (Figure 10-2), overlaid, stacked (Figure 10-3), or 100 percent.

Image from book
Figure 10-2: Clustered bar chart
Image from book
Figure 10-3: Stacked bar chart

Bubble Chart

As shown in Listing 10-4, the BubbleChart component displays data as points that are determined by a value for the horizontal axis, a value for the vertical axis, and a value for the size of the chart item. The bubble chart tag also takes the maxRadius property. This defines the size of the bubble representing the largest item in the model.

Listing 10-4: Bubble Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }
    ]]>
  </mx:Script>

  <mx:Panel title="LineChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:BubbleChart id="bubbleChart" height="100%" width="100%"
      paddingRight="5" paddingLeft="5" showDataTips="true" maxRadius="20"
      dataProvider="{productSales}">
      <mx:series>
        <mx:BubbleSeries displayName="Gizmos/Widgets/Gadgets"
          xField="Gizmos" yField="Widgets" radiusField="Gadgets"/>
      </mx:series>
      <mx:horizontalAxis>
             <mx:LinearAxis title="Gizmos" />
      </mx:horizontalAxis>
      <mx:verticalAxis>
             <mx:LinearAxis title="Widgets" />
      </mx:verticalAxis>
    </mx:BubbleChart>
    <mx:Legend dataProvider="{bubbleChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-4 shows a bubble chart.

Image from book
Figure 10-4: Bubble chart

Column Chart

As shown in Listing 10-5, the ColumnChart component displays data in a series of vertical bars representing the data of the ColumnSeries. Column chart variations include simple columns, clustered columns, overlaid, stacked, 100 percent stacked, and high-low.

Listing 10-5: Column Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
    <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
        productSales = chartData.getDataSet1();
    }
    ]]>
    </mx:Script>

  <mx:Panel title="ColumnChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:ColumnSeries xField="Quarter" yField="Gizmos" displayName="Gizmos"/>
        <mx:ColumnSeries xField="Quarter" yField="Widgets" displayName="Widgets"/>
        <mx:ColumnSeries xField="Quarter" yField="Gadgets" displayName="Gadgets"/>
      </mx:series>
    </mx:ColumnChart>
    <mx:Legend dataProvider="{columnChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

The bars can be clustered (Figure 10-5), overlaid (Figure 10-6), stacked, or 100 percent.

Image from book
Figure 10-5: Clustered column chart
Image from book
Figure 10-6: Overlaid column chart

Line Chart

As shown in Listing 10-6, the LineSeries component displays data as a series of points that are connected by a line. You can also display line charts without points, or you can specify an icon to display as the point.

Listing 10-6: Line Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

    <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }
    ]]>
    </mx:Script>

  <mx:Panel title="LineChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:LineChart id="lineChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
         <mx:LineSeries yField="Gizmos" form="curve" displayName="Gizmos"/>
         <mx:LineSeries yField="Widgets" form="curve" displayName="Widgets"/>
         <mx:LineSeries yField="Gadgets" form="curve" displayName="Gadgets"/>
      </mx:series>
    </mx:LineChart>
    <mx:Legend dataProvider="{lineChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-7 shows a line chart.

Image from book
Figure 10-7: Line chart

Pie Chart

As shown in Listing 10-7, the PieChart component displays data in a standard pie chart display.

Listing 10-7: Pie Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

    <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
        productSales = chartData.getDataSet1();
    }
    ]]>
    </mx:Script>

  <mx:Panel title="PieChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">

     <mx:PieChart id="gizmoChart" height="100%" width="100%"
            paddingRight="5" paddingLeft="5"
            showDataTips="true" dataProvider="{productSales}" >
      <mx:series>
        <mx:PieSeries labelPosition="callout" field="Gizmos" displayName="Gizmos"/>
      </mx:series>
    </mx:PieChart>

    <mx:PieChart id="widgetChart" height="100%" width="100%"
            paddingRight="5" paddingLeft="5"
            showDataTips="true" dataProvider="{productSales}"
            innerRadius=".25">
      <mx:series>
        <mx:PieSeries labelPosition="callout" field="Widgets" displayName="Widgets"/>
      </mx:series>
    </mx:PieChart>

    <mx:PieChart id="gadgetChart" height="100%" width="100%"
            paddingRight="5" paddingLeft="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:series>
        <mx:PieSeries labelPosition="callout" field="Gizmos" displayName="Gizmos"/>
        <mx:PieSeries labelPosition="callout" field="Widgets" displayName="Widgets"/>
        <mx:PieSeries labelPosition="callout" field="Gadgets" displayName="Gadgets"/>
      </mx:series>
    </mx:PieChart>
  </mx:Panel>
</mx:Application>
Image from book

The pie chart can be displayed as a standard pie, a doughnut, or a stacked pie chart, as shown in Figure 10-8.

Image from book
Figure 10-8: Pie chart

Plot Chart

The PlotChart component displays data points based on a value for the horizontal position and a second value for the vertical position. Listing 10-8 shows an example of the PlotChart component.

Listing 10-8: Plot Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

    <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }
    ]]>
    </mx:Script>

  <mx:Panel title="PlotChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:PlotChart id="plotChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">

      <mx:series>
        <mx:PlotSeries xField="Gizmos" yField="Widgets" displayName="Gizmos/Widgets"/>
        <mx:PlotSeries xField="Gadgets" yField="Gizmos" displayName="Gadgets/Gizmos"/>
        <mx:PlotSeries xField="Widgets" yField="Gadgets" displayName="Widgets/Gadgets"/>
      </mx:series>
    </mx:PlotChart>
    <mx:Legend dataProvider="{plotChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-9 shows a plot chart.

Image from book
Figure 10-9: Plot chart

Candlestick Chart

Candlestick charts are used in the financial world to represent high, low, open, and close values of a security. The fill of the chart items are determined by the relationship between the open and close values. A chart item that has a solid fill is a representation of a close value that is less than the open value. A chart item with a border and no fill is a representation of a close value that is higher than the open value. The CandlestickSeries shown in Listing 10-9 requires all four values: high, low, open, and close.

Listing 10-9: Candlestick Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;

      private var chartData:ChartData = new ChartData();

      [Bindable]
      private var goog:ArrayCollection;

      private function initApp():void{
        goog = chartData.getStockData1();
      }
     ]]>
   </mx:Script>

   <mx:Panel title="Axis Label Rotation Example" width="100%" height="100%"
     paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

     <mx:CandlestickChart id="candlestickChart" dataProvider="{goog}"
         showDataTips="true" height="100%" width="100%">
       <mx:series>
         <mx:CandlestickSeries dataProvider="{goog}" openField="open"
                  highField="high" lowField="low" closeField="close"
                  displayName="GOOG">
         </mx:CandlestickSeries>
       </mx:series>
       <mx:verticalAxis>
         <mx:LinearAxis baseAtZero="false"/>
       </mx:verticalAxis>
       <mx:horizontalAxis>
         <mx:CategoryAxis categoryField="date" title="Date"/>
       </mx:horizontalAxis>
       <mx:horizontalAxisRenderer>
         <mx:AxisRenderer labelRotation="45"/>
       </mx:horizontalAxisRenderer>
     </mx:CandlestickChart>
     <mx:Legend dataProvider="{candlestickChart}" direction="horizontal"/>
   </mx:Panel>
</mx:Application>
Image from book

Figure 10-10 shows a candlestick chart.

Image from book
Figure 10-10: Candlestick chart

HighLowOpenClose (HLOC) Chart

The HighLowOpenClose chart shown in Listing 10-10 is another financial charting component that represents the same data as the candlestick chart. Rather than using a fill or border on the chart items, HighLowOpenClose adds a tick on the left side to represent the open value and a tick on the right side to represent the close value. As in the candlestick chart, the height of each chart item demonstrates the overall range of all four values.

Listing 10-10: HLOC Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
    import mx.controls.Alert;

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var goog:ArrayCollection;

    private function initApp():void{
      goog = chartData.getStockData1();
    }

    ]]>
  </mx:Script>

  <mx:Panel title="HighLowOpenClose Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:HLOCChart id="hlocChart" dataProvider="{goog}" showDataTips="true"
          height="100%" width="100%">
      <mx:verticalAxis>
        <mx:LinearAxis baseAtZero="false"/>
      </mx:verticalAxis>
      <mx:series>
        <mx:HLOCSeries dataProvider="{goog}" openField="open"
                highField="high" lowField="low" closeField="close"
                displayName="GOOG">
        </mx:HLOCSeries>
      </mx:series>
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="date" title="Date"/>
      </mx:horizontalAxis>
      <mx:horizontalAxisRenderer>
        <mx:AxisRenderer canDropLabels="true"/>
      </mx:horizontalAxisRenderer>
    </mx:HLOCChart>
    <mx:Legend dataProvider="{hlocChart}"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-11 shows an HLOC chart.

Image from book
Figure 10-11: HLOC chart

Charting Classes

This section describes the charting classes in Flex.

Axis Label

Axis labels are defined by the labelFunction property of the chart’s axis. The signature of the method that is called by the labelFunction is as follows:

public function setAxisLabel(labelValue:Object,
                             previousLabelValue:Object,
                             axis:CategoryAxis,
                             labelItem:Object):String {
  return labelValue;
}

Depending on the axis type, the return value can be a String for a CategoryAxis (as shown previously), a Number for a NumericAxis, and a Date for a DateTimeAxis.

By updating the CategoryAxis object to the ColumnChart example from Listing 10-5, adding the setAxisLabel function will update the display of the column labels to show Quarter 1, Quarter 2, Quarter 3, and Quarter 4, as shown in Figure 10-12.

<mx:CategoryAxis dataProvider="{productSales}" categoryField="Quarter"
   labelFunction="setAxisLabel"/>
public function setAxisLabel(labelValue:Object,
                             previousLabelValue:Object,
                             axis:CategoryAxis,
                             labelItem:Object):String {
    return "Quarter " + labelValue;
}
Image from book
Figure 10-12: Axis labels

Axis Title

By simply adding the title property to the horizontal or vertical Axis, Flex will display a title on the corresponding axis. Updating the code in Listing 10-5 to the following will add a title across the bottom of the chart, as shown in Figure 10-12.

<mx:CategoryAxis dataProvider="{productSales}" categoryField="Quarter"
   labelFunction="setAxisLabel" title="Fiscal Year"/>

Axis Renderer

Axis Renderers are used to alter the appearance of the horizontal or vertical axis. Adding the following code to Listing 10-5 will change the color of the horizontal axis and vertical axis to black, and the tick marks to gray, as shown in Figure 10-12.

<mx:horizontalAxisRenderer>
  <mx:AxisRenderer>
    <mx:axisStroke>
      <mx:Stroke color="#000000" weight="3" alpha=".75"/>
    </mx:axisStroke>
  </mx:AxisRenderer>
</mx:horizontalAxisRenderer>

 <mx:verticalAxisRenderer>
   <mx:AxisRenderer>
     <mx:axisStroke>
       <mx:Stroke color="#000000" weight="3" alpha=".75"/>
     </mx:axisStroke>
     <mx:tickStroke>
       <mx:Stroke color="#CCCCCC" weight="1" />
     </mx:tickStroke>
     <mx:minorTickStroke>
       <mx:Stroke color="#CCCCCC" weight="1" />
     </mx:minorTickStroke>
  </mx:AxisRenderer>
</mx:verticalAxisRenderer>

Grid Lines

Grid lines can be added to a chart horizontally, vertically, or in both directions. The fill colors and stroke thicknesses can also be set. The code to add grid lines looks like this:

<mx:GridLines horizontalChangeCount="1" verticalChangeCount="1" direction="both">
  <mx:horizontalStroke>
    <mx:Stroke weight="1"/>
  </mx:horizontalStroke>
  <mx:verticalStroke>
    <mx:Stroke weight="1"/>
  </mx:verticalStroke>
  <mx:horizontalFill>
    <mx:SolidColor color="0xCCCCCC" alpha=".66"/>
  </mx:horizontalFill>
</mx:GridLines>

Axis Types

All axes have similar properties, including the following:

  • dataProvider - Defines the data that will be used within the chart

  • categoryField - The name of the element within the dataProvider to be charted

  • displayName - Any string value to represent the categoryField in human-readable terms

  • title - A value to be displayed along the axis

  • labelFunction - The name of the function that will format the chartItem labels

Following are common axis types:

  • CategoryAxis - CategoryAxis is used to represent the values of chart item data when the data type will be of type String. The column chart throughout this chapter (Figure 10-12) uses a CategoryAxis to represent the quarters of a fiscal year.

  • DateTimeAxis - DateTimeAxis is used to chart date values across an axis. The class contains minimum and maximum values that can be laid out evenly across these values. If these values are not set, the axis will be created based on the supplied data. Setting the dataInterval and dataUnits will determine how the data is displayed. If dataInterval is set to days and dataUnits is set to 15 in a column chart, the chart will attempt to display a column every 15 days along the axis.

  • LinearAxis - LinearAxis is used to display numeric data across an axis. Properties of LinearAxis include minimum, maximum, and interval. If minimum is set to 1000, maximum is set to 5000, and interval is set to 1000, the chart will display data at 1000, 2000, 3000, 4000, and 5000.

  • LogAxis - LogAxis is used to display positive numeric data across an axis. LogAxis cannot display negative data. The LogAxis will display data logarithmically across an axis from a minimum to a maximum value. If a minimum or maximum is not set, it will be determined by the chart’s data.

ChartItem

ChartItem is the unit representing the data within a series. In a ColumnChart, the ChartItem would be a single grouping of columns.

ChartItemEvent

ChartItemEvent is the object that is returned when a specific event occurs (click, double click, and so on). ChartItemEvent contains a reference to the event type as well as the hitData.

Hit Data

HitData contains an item property that holds the data included in the ChartItem that broadcast the ChartItemEvent.

Legend

A chart legend creates a road map of the chart so that the reader can easily interpret the chart items. By simply setting the legend dataProvider, a legend will be automatically created. The legend can be displayed horizontally or vertically by setting the direction property, and can also be manually created. All of the examples displayed in this chapter contain a legend.


Advanced Charting

The following sections cover some of the more advanced features of Flex charting. These include chart events, drill-down charts, mixed series types, multiple-axis charts, and axis label rotation.

Chart Events

Chart components, like most Flex components, broadcast events with user interaction. These include click, double click, mouse down, mouse move, mouse up, item roll out, and item roll over. Listing 10-11 shows the event and the values of the data column that triggered the event. The sample code has the click and double click events active, with the others commented out. Run the code and uncomment the other events to see how each one is broadcast.

Listing 10-11: Chart Event
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[v
    import mx.collections.ArrayCollection;
     import mx.charts.events.ChartItemEvent;

     private var chartData:ChartData = new ChartData();
     [Bindable]
     private var productSales:ArrayCollection;
   [Bindable]
    private var logData:String;

    // Event handler
    public function myListener(e:ChartItemEvent):void {
      logData = logData + "\nEvent: " + e.type + "\n   Gizmos: " +
e.hitData.item.Gizmos
      + " Widgets: " + e.hitData.item.Widgets + " Gadgets: " + e.hitData.item.Gadgets
      + "\n";
      eventLog.verticalScrollPosition=eventLog.verticalScrollPosition+100;
    }
    // Define event listeners.
    private function initApp():void {
      productSales = chartData.getDataSet1();
      columnChart.addEventListener(ChartItemEvent.ITEM_CLICK,myListener);
      columnChart.addEventListener(ChartItemEvent.ITEM_DOUBLE_CLICK,myListener);
      //columnChart.addEventListener(ChartItemEvent.ITEM_MOUSE_DOWN,myListener);
      //columnChart.addEventListener(ChartItemEvent.ITEM_MOUSE_MOVE,myListener);
      //columnChart.addEventListener(ChartItemEvent.ITEM_MOUSE_UP,myListener);
      //columnChart.addEventListener(ChartItemEvent.ITEM_ROLL_OUT,myListener);
      //columnChart.addEventListener(ChartItemEvent.ITEM_ROLL_OVER,myListener);
    }
    ]]>
  </mx:Script>

  <mx:Panel title="ColumnChart Event Example (RollOver, Click, or DoubleClick)"
width="700" height="400"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">

    <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}" doubleClickEnabled=
"true">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:ColumnSeries xField="Quarter" yField="Gizmos" displayName="Gizmos"/>
        <mx:ColumnSeries xField="Quarter" yField="Widgets" displayName="Widgets"/>
        <mx:ColumnSeries xField="Quarter" yField="Gadgets" displayName="Gadgets"/>
      </mx:series>
    </mx:ColumnChart>
    <mx:Legend dataProvider="{columnChart}"/>
    <mx:TextArea id="eventLog" text="{logData}" width="300" height="100%"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 10-13 shows the results of Listing 10-11.

Image from book
Figure 10-13: Chart event

Drill-Down Charts

As shown in Listing 10-11, when clicking one of the columns in the chart, you are able to get the data associated with that column. By simply adding another charting component (in this case, the PieChart component), you can chart the data that is broadcast by the click event. Listing 10-12 creates a new ArrayCollection using the data from the click on the ColumnChart and then assigns it to the dataProvider of the PieChart.

Listing 10-12: Drill-Down Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
    import mx.charts.events.ChartItemEvent;
    import mx.collections.ArrayCollection;
    import mx.charts.HitData;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

     public function myListener(e:ChartItemEvent):void {
       var pieData:ArrayCollection = new ArrayCollection( [
         {Product: "Gizmos", Total: e.hitData.item.Gizmos},
         {Product: "Widgets", Total: e.hitData.item.Widgets},
         {Product: "Gadgets", Total: e.hitData.item.Gadgets},
     ]);
       pieChart.dataProvider=pieData;
     }

    private function initApp():void{
      productSales = chartData.getDataSet1();
      columnChart.addEventListener(ChartItemEvent.ITEM_CLICK,myListener);
    }

    public function display(data:Object, field:String, index:Number,
      percentValue:Number):String {
      return data.Product + ": " + data.Total;
    }

    public function dtFunc(h:HitData):String {
      return h.item.Product + "\n<B>" + h.item.Total +"</B>";
    }
    ]]>
  </mx:Script>

  <mx:Panel title="Drill Down Example" width="100%" height="100%"
      paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:ColumnSeries xField="Quarter" yField="Total" displayName="Quarter"/>
      </mx:series>
    </mx:ColumnChart>

    <mx:PieChart id="pieChart" height="100%" width="100%"
            paddingRight="5" paddingLeft="5"
            showDataTips="true" dataTipFunction="dtFunc">
      <mx:series>
        <mx:PieSeries labelPosition="callout" field="Total" labelFunction="display"/>
      </mx:series>
    </mx:PieChart>

  </mx:Panel>
</mx:Application>
Image from book

As you click each column, the pie chart will be redrawn using the new drill-down data, as shown in Figure 10-14.

Image from book
Figure 10-14: Drill-down chart

Mixed Series Types

All charts that subclass the CartesianChart class allow for mixed data series. By simply adding an additional series to the column chart example from earlier in this chapter, Flex can then display both charting elements within the same chart. Listing 10-13 adds a LineSeries to the column chart example that shows the total product sales. The only code that was added was the LineSeries object. Figure 10-15 shows how the chart has been initialized.

Listing 10-13: Mixed Series Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
    <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
        productSales = chartData.getDataSet1();
    }
    ]]>
    </mx:Script>

  <mx:Panel title="ColumnChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter"/>
      </mx:horizontalAxis>
      <mx:series>
        <mx:ColumnSeries xField="Quarter" yField="Gizmos" displayName="Gizmos"/>
        <mx:ColumnSeries xField="Quarter" yField="Widgets" displayName="Widgets"/>
        <mx:ColumnSeries xField="Quarter" yField="Gadgets" displayName="Gadgets"/>
        <mx:LineSeries yField="Total" form="curve" displayName="Total"/>
      </mx:series>
    </mx:ColumnChart>
    <mx:Legend dataProvider="{columnChart}" direction="horizontal"/>
  </mx:Panel>
</mx:Application>
Image from book
Image from book
Figure 10-15: Mixed series chart

Multiple-Axis Charts

Figure 10-15 now has multiple axes displayed. However, it is more difficult to read because all of the chart components are displayed (columns and line) using a single axis that has now been extended to accommodate the total sales.

Fortunately, there is a way to better utilize the second series, and that is by using a multiple-axis chart. Instead of adding the new LineSeries to the series that includes the ColumnSeries, Listing 10-14 adds a secondSeries to the chart.

Listing 10-14: Multiple-Axis Chart
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[

    import mx.collections.ArrayCollection;

    private var chartData:ChartData = new ChartData();

    [Bindable]
    private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }
    ]]>
  </mx:Script>

  <mx:Panel title="Multiple Axis Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:horizontalAxis>
        <mx:CategoryAxis categoryField="Quarter" title="Quarter"/>
      </mx:horizontalAxis>
      <mx:verticalAxis>
        <mx:LinearAxis title="Product Sales" />
      </mx:verticalAxis>
      <mx:secondVerticalAxis>
        <mx:LinearAxis title="Total Sales" />
      </mx:secondVerticalAxis>
      <mx:series>
        <mx:ColumnSeries xField="Quarter" yField="Gizmos" displayName="Gizmos"/>
        <mx:ColumnSeries xField="Quarter" yField="Widgets" displayName="Widgets"/>
        <mx:ColumnSeries xField="Quarter" yField="Gadgets" displayName="Gadgets"/>
      </mx:series>
      <mx:secondSeries>
        <mx:LineSeries dataProvider="{productSales}" yField="Total" form="curve"
displayName="Total"/>
      </mx:secondSeries>
    </mx:ColumnChart>

    <mx:Legend dataProvider="{columnChart}" direction="horizontal"/>

  </mx:Panel>
</mx:Application>
Image from book

By adding the second series, the interpretation of the chart is now based on both a left vertical axis and a right vertical axis that have different values, as shown in Figure 10-16.

Image from book
Figure 10-16: Multiple-axis chart

The example now has two chart series types, the ColumnSeries as well as the LineSeries that you just added. You will also notice that there is now an additional title on the right axis. This was added using the following code:

<mx:secondVerticalAxis>
  <mx:LinearAxis title="Total Sales" />
</mx:secondVerticalAxis>

Axis Rotation

Referring back to the candlestick chart example in Listing 10-9, you will notice that in order to fit the labels properly, a horizontalAxisRendered was added with canDropLabels set to true. However, there is another option. You can set the axis label rotation to 45 degrees, which would allow the labels to lay out nicely, as shown in Figure 10-17.

Image from book
Figure 10-17: Axis rotation

To set rotation on the axis labels, you must first embed the font class that will be used for the chart component. The following code block will accomplish this for the candlestick chart example. The arial.ttf font file has been added to the root folder of this example.

<mx:Style>
  @font-face {
    fontFamily: arial;
    src:url("arial.ttf");
  }
  CandlestickChart{
    fontFamily: arial;
  }
</mx:Style>

Next, you must add a new horizontalAxisRenderer. The code for this renderer looks like this:

<mx:horizontalAxisRenderer>
  <mx:AxisRenderer labelRotation="45"/>
</mx:horizontalAxisRenderer>


Charting Effects

Charting effects are animations that will run when a charting component is created, and also when the component’s dataProvider is updated.

SeriesInterpolate

The SeriesInterpolate event will morph the chart’s current data to the chart’s new data.

SeriesSlide

The SeriesSlide event will slide the old data off the screen, and then slide the new data onto the screen. You can set the direction of the slide by using the direction property. The default direction is left.

SeriesZoom

The SeriesZoom event will implode and explode the data. You can set the horizontalFocus and verticalFocus of the implosion and explosion. The default focus is center for both.

Listing 10-12 would redraw the pie chart whenever a column from the column chart was clicked. The pie would change very abruptly. The following example adds an effect to the pie chart to make the redraw a more elegant transition. Adding the effect is as simple as defining an effect. In this case, you use the SeriesInterpolate effect with a duration of one second:

<mx:SeriesInterpolate id="showPieEffect" duration="1000"/>

All that is left to do is to update the PieSeries tags by adding showDataEffect="{showPieEffect}", making the completed tag look like this:

<mx:PieSeries showDataEffect="{showPieEffect}" labelPosition="callout"
field="Total" labelFunction="display"/>

When you run the example again, you will see the pie chart morph to show the new data whenever a new column is clicked in the column chart. You may also wish to try the SeriesZoom and SeriesSlide effects. Here is some sample code to try out. Because they all use the same ID, you should only use one at a time.

<mx:SeriesZoom id="showPieEffect" duration="1000"/>
<mx:SeriesSlide id="showPieEffect" duration="1000"/>


Chart Style Examples

Continuing to build on the styling you started earlier, Listing 10-15 adds some gradient fills for the column series, as shown in Figure 10-18.

Listing 10-15: Gradient fill
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="initApp()" backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
    import mx.controls.Alert;

    import mx.collections.ArrayCollection;

     private var chartData:ChartData = new ChartData();
     [Bindable]
     private var productSales:ArrayCollection;

    private function initApp():void{
      productSales = chartData.getDataSet1();
    }

    public function setAxisLabel(labelValue:Object, previousLabelValue:Object,
      axis:CategoryAxis, labelItem:Object):String {
      return "Quarter " + labelValue;
    }

    ]]>
  </mx:Script>

  <mx:Panel title="ColumnChart Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

     <mx:ColumnChart id="columnChart" height="100%" width="100%"
            paddingLeft="5" paddingRight="5"
            showDataTips="true" dataProvider="{productSales}">
      <mx:verticalAxis>
        <mx:LinearAxis title="Quantity" />
       </mx:verticalAxis>
       <mx:backgroundElements>
        <mx:GridLines horizontalChangeCount="1" verticalChangeCount="1"
direction="both">
          <mx:horizontalStroke>
            <mx:Stroke weight="1" alpha=".75"/>
          </mx:horizontalStroke>
          <mx:verticalStroke>
            <mx:Stroke weight="1" alpha=".75"/>
          </mx:verticalStroke>
          <mx:horizontalFill>
            <mx:SolidColor color="#000000" alpha=".5"/>
          </mx:horizontalFill>
        </mx:GridLines>
      </mx:backgroundElements>
      <mx:horizontalAxisRenderer>
        <mx:AxisRenderer>
          <mx:axisStroke>
            <mx:Stroke color="#000000" weight="3" alpha=".75"/>
          </mx:axisStroke>
        </mx:AxisRenderer>
      </mx:horizontalAxisRenderer>
      <mx:verticalAxisRenderer>
        <mx:AxisRenderer>
          <mx:axisStroke>
            <mx:Stroke color="#000000" weight="3" alpha=".75"/>
          </mx:axisStroke>
          <mx:tickStroke>
            <mx:Stroke color="#CCCCCC" weight="1" />
          </mx:tickStroke>
          <mx:minorTickStroke>
            <mx:Stroke color="#CCCCCC" weight="1" />
          </mx:minorTickStroke>
        </mx:AxisRenderer>
      </mx:verticalAxisRenderer>
      <mx:horizontalAxis>
        <mx:CategoryAxis dataProvider="{productSales}" categoryField="Quarter"
                     labelFunction="setAxisLabel" title="Fiscal Year"
displayName="Quarter"/>
      </mx:horizontalAxis>
        <mx:series>
          <mx:ColumnSeries xField="Quarter" yField="Gizmos" displayName="Gizmos">
            <mx:fill>
                <mx:LinearGradient>
                   <mx:entries>
                      <mx:Array>
                    <mx:GradientEntry color="#B22C02" ratio="0" alpha="1" />
                    <mx:GradientEntry color="#E3AC9A" ratio=".2" alpha="1" />
                    <mx:GradientEntry color="#B22C02" ratio=".4" alpha="1" />
                    <mx:GradientEntry color="#FD8E6B" ratio=".75" alpha="1" />
                    <mx:GradientEntry color="#B22C02" ratio="1" alpha="1" />
                  </mx:Array>
                    </mx:entries>
                 </mx:LinearGradient>
               </mx:fill>
          </mx:ColumnSeries>
          <mx:ColumnSeries xField="Quarter" yField="Widgets" displayName="Widgets">
            <mx:fill>
                <mx:LinearGradient>
                   <mx:entries>
                      <mx:Array>
                    <mx:GradientEntry color="#A6A602" ratio="0" alpha="1" />
                         <mx:GradientEntry color="#DFDF97" ratio=".2" alpha="1" />
                         <mx:GradientEntry color="#A6A602" ratio=".4" alpha="1" />
                         <mx:GradientEntry color="#F5F655" ratio=".75" alpha="1" />
                         <mx:GradientEntry color="#A6A602" ratio="1" alpha="1" />
                  </mx:Array>
                    </mx:entries>
                 </mx:LinearGradient>
               </mx:fill>
            </mx:ColumnSeries>
          <mx:ColumnSeries xField="Quarter" yField="Gadgets" displayName="Gadgets">
            <mx:fill>
                <mx:LinearGradient>
                   <mx:entries>
                      <mx:Array>
                    <mx:GradientEntry color="#A1AECF" ratio="0" alpha="1" />
                         <mx:GradientEntry color="#47447A" ratio=".2" alpha="1" />
                         <mx:GradientEntry color="#A1AECF" ratio=".4" alpha="1" />
                         <mx:GradientEntry color="#47447A" ratio=".75" alpha="1" />
                         <mx:GradientEntry color="#A1AECF" ratio="1" alpha="1" />
                  </mx:Array>
                    </mx:entries>
                 </mx:LinearGradient>
               </mx:fill>
          </mx:ColumnSeries>
        </mx:series>
      </mx:ColumnChart>
      <mx:Legend dataProvider="{columnChart}" direction="horizontal"/>
    </mx:Panel>
</mx:Application>
Image from book
Image from book
Figure 10-18: Gradient fill


Summary

This chapter demonstrated the power of the Flex charting components and just how easy it is to create beautiful charts displaying the same data in many different formats. It also demonstrated some of the advanced charting techniques, ways to change the look and feel of a chart through effects and styling, and also how to listen for charting events.

Chapter 11 delves into the many ways of getting data into Flex. It demonstrates how to configure and implement Flex data services, RPC services, and messaging services.


Chapter 11: Data Access

This chapter describes features regarding external data, such as either sending data or receiving data from a remote server. It also introduces you to Flex Data Services (FDS), which run on standard J2EE platforms and servlet containers. You learn about the three Flex features designed to transport data to and from applications: RPC services, Data Management Service, and Message Service.

Note that in order to implement FDS, you must have at least a basic knowledge of Java Web applications. All the examples in this chapter require that you install FDS to use some of the FDS classes in the examples.

Server-side Data

Flex 2 provides a new messaging infrastructure that allows you to build data-rich applications. FDS integrates with existing common middleware and provides services that automatically synchronize data between client and server. There is support for real-time pushing of data and publish-subscribe messaging to enable collaborative and occasionally disconnected applications.

Flex Data Access

The new messaging capabilities of Flex 2 allow you to build data-rich applications. The following describes the three features Flex provides to send and retrieve data from your applications:

  • RPC services - Remote Procedure Call (RPC) is initiated by the client sending a request message to a known remote server in order to execute a specified procedure using supplied parameters. A response is returned to the client, where the application continues along with its process. The Flex 2 SDK allows you to call the services directly, but you cannot use server-side features that require FDS.

  • Data Management Service - Provides your application with data synchronization, real-time data updates, data replication, data paging, and occasionally connected applications. You can manage large collections of data and nested data relationships, such as one-to-one and one-to-many relationships. You can also use data adapters to integrate with data sources, or even create your own.

  • Message Service - Enables Flex clients to use publish-subscribe messaging to integrate with enterprise backends that use message-oriented middleware, such as Java Messaging Service (JMS) systems. Flex Message Service offers data-push capability, enabling data to automatically be pushed to the client application without polling the server. You can create applications that collaborate or share data with other clients or other servers.

RPC Services

RPC services allows you to make asynchronous calls to remote services that process the request and return the data back to the application. You define an RPC component in MXML using the <mx:RemoteObject>, <mx:HTTPService>, or <mx:WebService> tag. The client RPC component calls a remote service, which then stores the response in an ActionScript object from which you can access the data.

Figure 11-1 shows how RPC components interact with RPC services.

Image from book
Figure 11-1: RPC components interact with RPC services

RPC Components with Flex 2 SDK

You can use the Flex 2 SDK without FDS to create applications that call HTTP or Web services without a going through a proxy service. The <mx:HTTPService/> and <mx:WebService/> components send data either using HTTP or SOAP format.

If you want to call remote services using the RemoteObject components, you should use FDS for Java objects or ColdFusion MX 7.0.2 with the Remoting Update. The data format for these two solutions would be Action Message Format (AMF) version 3.

Following are some third-party solutions that achieve functionality similar to FDS or ColdFusion:

  • WebORB - Midnight Coders (http://www.themidnightcoders.com) offers a product called WebORB, which is a platform-enabling development, deployment, and run-time execution of Rich Internet Applications. The product facilitates connectivity between rich clients created with Flex, Flash, or Ajax, and server-side applications developed with .NET, Java, Ruby on Rails, PHP, or XML Web Services. They all implement AMF0 and AMF3 protocols, and FDS. As of this writing, the full implementation of the Flex Data Management Services functionality will be available only in the commercial edition of the WebORB products.

  • AMFPHP - AMFPHP is a free Open Source Flash Remoting gateway that is fast and reliable. You can check it out at http://www.amfphp.org.

  • OpenAMF - The OpenAMF project (http://www.openamf.com) is a free Open Source alternative to Macromedia’s Java Flash Remoting. It is as capable of providing application services to Flash MX as Macromedia’s proprietary solution. This project began as a Java port of AMF-PHP.

  • RemoteObject component for AMF0 - If you would like to use AMFPHP or OpenAMF, you must download a modified version of the RemoteObject components that Flex 2 provides for RPC services. This will allow you to call PHP or Java remote objects using the AMF0 protocol. The RemoteObjectAMF0 component, which was written by Renaun Erickson (http://renaun.com/blog/flex-components/remoteobjectamf0), provides functionality to connect Flex 2 applications with AMF0 remoting servers.

RPC Components with FDS

RPC components and FDS provide you with enterprise functionality, such as client authentication, proxying of services from different domains, white lists of permitted RPC service URLs, server-side logging of data, localization support, and centralized management of RPC services.

Instead of contacting services directly, RPC components contact their relevant destinations, which are service endpoints that you can manage through a server-side XML file.

Data Management Service

Data Management Service contains features such as data synchronization, which removes the complexity and error potential by providing a robust, high-performance synchronization engine between client and server. In addition to that, you also have functionality for data replication, occasionally connected applications, and for managing large datasets and nested relationships.

Messaging Service

The Data Management Service consists of ActionScript libraries, which talk to Java libraries running under a J2EE server. This provides the capability to call Java methods running in your J2EE server, and use publish-and-subscribe messaging to enable push messaging to Flex 2 clients.

You can create the messaging components on the client, either in MXML or ActionScript, which connect to server-side message destinations, send messages to those destinations, and receive messages from other messaging clients.

Components that send messages are called producers, and those that receive messages are called consumers. The messages are sent over channels using the Real-time Messaging Protocol (RMTP) and AMF.

A good example of using the messaging service feature in a Flex application would be a real-time stock ticker or a weather station application. These two applications would require regular updates provided by the messaging service.


Data Services Configuration

To use FDS, you must configure the Remoting Service, Proxy Service, Message Service, and Data Management Service in the <services> tag of the Data Services services-config.xml configuration file.

Service Configuration Files

The following table contains the files needed in configuring FDS. Commented versions of these files are available in the resources/configuration subdirectory of the FDS install directory. You can use those files as a template for your own configuration.

Open table as spreadsheet
Filename | Description
service-config.xml | This is the main FDS configuration file. This contains security constraints, channel definitions, and logging settings for each service. The services can be defined inline, or you can reference them in other files.
remoting-config.xml | The Remoting Service configuration file defines the Remoting Service destinations to work with remote objects.
proxy-config.xml | The Proxy Service configuration file defines the Proxy Service destinations for working with Web services and HTTP services (REST services).
messaging-config.xml | The Message Service configuration file defines Message Service destinations for performing publish-subscribe messaging.
data-management-config.xml | The Data Management Service configuration file defines the Data Management Service destinations for working with Data Management Service destinations.

The following example shows you how to include a file by reference into the services-config.xml:

<services>
    <!-- REMOTING SERVICE -->
    <service-include file-path="remoting-config.xml"/>

    <!-- PROXY SERVICE -->
    <service-include file-path="proxy-config.xml"/>

    <!-- MESSAGE SERVICE -->
    <service-include file-path="messaging-config.xml"/>

    <!-- DATA MANAGEMENT SERVICE -->
    <service-include file-path="data-management-config.xml"/>
</services>

The file-path attribute is relative to the location of the services-config.xml file.

Message Channels

Messages are transported to and from service destinations over message channels that are part of the Flex messaging system. You can take any service and pair it with any type of channel.

The channels that are supported are HTTP, AMF, and RMTP, and all of them can be used securely. The AMF and HTTP secure channels transport data using HTTP over Secure Socket Layer (HTTPS) and the RMTP secure channel uses RMTP over Transport Layer Security (TLS).

The following example is an AMF channel definition. Below the channel definition is a destination that references it.

<destination id="MyTopic">
        <channels>
            <channel ref="samples-amf"/>
        </channels>
</destination>

<channel-definition id="samples-amf"
        type="mx.messaging.channels.AMFChannel">
        <endpoint uri="/myapp/messagebroker/amf" port="8100"
            type="flex.messaging.endpoints.AmfEndpoint"/>
</channel-definition>

Channels can also be assigned on the client at run-time by using the ChannelSet object. This object contains one or more Channel objects.

var channelSet:ChannelSet = new ChannelSet();
var myChannel:Channel = new AMFChannel("my-polling-channel", endpointURL);
channelSet.addChannel(myChannel);
// Assign the ChannelSet object to the RemoteObject instance
myRO.channelSet = channelSet;

You can add as many Channel objects to the ChannelSet as you like. The ChannelSet object will search through the list of channels to find one it can connect to successfully.

The endpointURL is a read-only property, and is calculated depending on the value of the uri property.

The process of connecting to a channel involves searching for the first channel and trying to connect. If this fails and the channel has failover URIs defined, it will try all of those before searching for the next available channel.

Data Serialization

This section describes the serialization to and from ActionScript objects on the client and Java objects on the server. It also contains information about serialization to and from ActionScript objects on the client and SOAP and XML schema types.

ActionScript-to-Java Conversion

When sending arguments from a Flex application to a Java object, the data is converted automatically from an ActionScript data type to a Java data type.

An ActionScript Array can be indexed in two ways: a strict Array (in which the indexes are Numbers), or an associative Array (which has at least one index that is a String). It is very important that you know which Array you are sending to the server, because the data type changes in the arguments when used to invoke the Java object method.

The following table shows simple data type conversions from ActionScript (AMF 3) to Java.

Open table as spreadsheet
ActionScript Type (AMF 3) | Deserialization to Java | Supported Java Type Binding
Array (dense) | java.util.List | java.util.Collection, Object (native array)
 |  | A custom collection implementation is bound to the relative type.
Array (sparse) | java.util.Map | java.util.Collection, native array
Boolean | java.lang.Boolean | Boolean, Boolean, String
String “true” or “false” |  |
flash.utils.ByteArray | Byte |
flash.utils.IExternalizable | java.io.Externalizable |
Date | java.util.Date | java.util.Date, java.util.Calendar, java.sql.Timestamp, java.sql.Time, java.sql.Date
int/uint | java.lang.Integer | java.lang.Byte, java.lang.Double, java.lang.Float, java.lang.Long, java.lang.Short, java.math.BigDecimal
 |  | String, primitive types of byte, double, float, long, and short
null | null | Primitives (0, false, ‘’, and so on)
number | java.lang.Double | java.lang.Byte, java.lang.Double, java.lang.Float, java.lang.Long, java.lang.Short, java.math.BigDecimal
 |  | String, 0 (zero) if null is sent, primitive types of byte, double, float, long, and short
Object (generic) | java.util.Map | If a Map interface is specified, FDS creates a new java.util.HashMap for java.util.Map and a new java.util.TreeMap for java.util.SortedMap.
String | java.lang.String | java.lang.String, java.lang.Boolean, java.lang.Number
typed Object | Typed Object when you use [RemoteClass] metadata that specifies remote class name. Bean type must have a public no args constructor. | Typed Object
undefined | null | null for Object, default values for primitives
XML | org.w3c.dom.Document | org.w3c.dom.Document
XMLDocument | org.w3c.dom.Document | org.w3c.dom.Document

Primitive values cannot be set to null in Java, and so Flex interprets null values as the default primitive types. Note that a Java Collection can contain any number of Object types, but a Java Array must be the same type.

Java-to-ActionScript Conversion

The following table shows simple data type conversions from Java to ActionScript (AMF 3).

Open table as spreadsheet
Java Type | ActionScript Type (AMF 3)
java.lang.String | String
java.lang.Boolean, boolean | Boolean
java.lang.Integer | int
 | If i < 0xF0000000 || i > 0x0FFFFFFF, the value is promoted to Number.
java.lang.Short | int
 | If i < 0xF0000000 || i > 0x0FFFFFFF, the value is promoted to Number.
java.lang.Byte | int
 | If i < 0xF0000000 || i > 0x0FFFFFFF, the value is promoted to Number.
java.lang.Byte[] | flash.utils.ByteArray
java.lang.Double | Number
java.lang.Long | Number
java.lang.Float | Number
java.lang.Character | String
java.lang.Character[] | String
java.util.Calendar | Date
 | Dates are sent in the Coordinated Universal Time (UTC) time zone. Clients and servers must adjust time accordingly for time zones.
java.util.Date | Date
 | Dates are sent in the UTC time zone. Clients and servers must adjust time accordingly for time zones.
java.lang.Object (other than previously listed types) | Typed Object
 | Objects are serialized using Java Bean introspection rules. Fields that are static, transient, or nonpublic are excluded.
java.util.Collection | mx.collection.ArrayCollection
java.lang.Object[] | Array
java.util.Map | Object (untyped)
 | In Flex 1.5, java.util.Map was sent as an associative or ECMA Array. This is no longer a recommended practice. You can enable legacy Map support to associative Arrays, but Adobe recommends against doing this. For more information, see “Providing legacy AMF serialization on a channel” (http://127.0.0.1:52419/help/topic/com.adobe.flexbuilder.help/html/00001105.html#268711).
java.util.Dictionary | Object (untyped)
org.w3c.dom.Document | XML object
 | You can enable legacy XML support for the XMLDocument type on any channel defined in the services-config.xml file. For more information, see “Providing legacy AMF serialization on a channel.”
null | null

You use the [RemoteClass(alias="the.package.and.class.name")] metadata tag to create an ActionScript object that maps directly to the Java object found on the remote server. The data converted to the relevant ActionScript class must be referenced or used in the MXML file. The typical way of casting the result object is shown in the following example:

var result:MyCustomClass = MyCustomClass(event.result);

The following example shows you how to use the [RemoteClass(alias="")] metadata tag:

package com.mycompany.vo.User
{
     [RemoteClass(alias="com.mycompany.vo.User")]
     [Bindable]
     public class User
     {
          public var id:Number;
          public var username:String;
          public var password:String;
          public var emailaddress:String;
     }
}

Note that you can use the [RemoteClass] metadata tag even if you do not have an alias or Java object to map to on the server, but you do send back a typed version from the server. If you send your typed ActionScript object to the server, it is serialized to a Map object. However, if the typed object on the server is sent back, it will be serialized to the original ActionScript type.

ActionScript to Schema and SOAP types

Sending SOAP requests using Flex requires that the information be appropriately represented in the corresponding ActionScript types. Complex types and SOAP-encoded Array types are supported.

The following table shows type mappings between SOAP types and ActionScript types.

Open table as spreadsheet
SOAP Type | ActionScript Type | Supported Java Type Binding
base64 | flash.utils.ByteArray | Typed Object
number types | Number |
boolean | Boolean | null for Object, default values for primitives
Array | Array | org.w3c.dom.Document
string | String | org.w3c.dom.Document

Custom Serialization

You may find that the standard serialization and deserialization between ActionScript on the client and Java on the server do not meet your requirements. Instead, you can implement the flash.utils.IExternalizable interface on the client and the corresponding Java java.io.Externalizable interface on the server.

The typical use of custom serialization is to avoid passing all the properties of either the client or server-side object across the network. The use of the standard serialization process means that all public properties are passed back and forth between the client and the server.

If performance is your main goal, use custom serialization instead of the default serialization. For example, in a real-time stock application, the size of the serialized objects should be very small. The longer the variable names, the larger the footprint will be during serialization, which will, in turn, slow down the application. Renaming the variables to something like var1, var2, and so on will help tremendously when sending custom objects to and from the server.

The writeExternal() and readExternal() methods must be used in the class that implements the flash.utils.IExternalizable interface. The methods control how the contents of the class are formatted for the serialization stream. Also note that these methods supersede the native AMF serialization behavior.

Listing 11-1 shows an ActionScript class called User, which maps to a Java User class on the server (Listing 11-2). The client User class implements the IExternalizable interface, and the server User class implements the Externalizable interface.

Listing 11-1: User.as
Image from book

package com.mycompany.vo
{
     import flash.utils.IDataOutput;
     import flash.utils.IDataInput;
     import flash.utils.IExternalizable;

     [RemoteClass(alias="com.mycompany.vo")]
     [Bindable]
     public class User implements IExternalizable
     {
          public var id:Number;
          public var username:String;
          public var password:String;
          public var emailaddress:String;
          public var isAdmin:Boolean;

          public function readExternal(input:IDataInput):void
          {
               id = input.readInt();
               username = input.readUTF();
               isAdmin = input.readBoolean();
          }

          public function writeExternal(output:IDataOutput):void
          {
               output.writeInt(id);
               output.writeUTF(username);
               output.writeBoolean(isAdmin);
          }
     }
}
Image from book
Listing 11-2: User.java
Image from book

package com.mycompany.vo;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class User implements Externalizable
{
     private int id;
     private String username;
     private String password;
     private String emailaddress;
     private boolean isAdmin;

     public String getEmailaddress() {
          return emailaddress;
     }

     public void setEmailaddress(String emailaddress) {
          this.emailaddress = emailaddress;
     }

     public int getId() {
          return id;
     }

     public void setId(int id) {
          this.id = id;
     }

     public boolean isAdmin() {
          return isAdmin;
     }

     public void setAdmin(boolean isAdmin) {
          this.isAdmin = isAdmin;
     }

     public String getPassword() {
          return password;
     }

     public void setPassword(String password) {
          this.password = password;
     }

     public String getUsername() {
          return username;
     }

     public void setUsername(String username) {
          this.username = username;
     }

     public void readExternal(ObjectInput input) throws IOException,
ClassNotFoundException
     {
          id = input.readInt();
          username = input.readUTF();
          isAdmin = input.readBoolean();
     }

     public void writeExternal(ObjectOutput output) throws IOException
     {
          output.writeInt(id);
          output.writeUTF(username);
          output.writeBoolean(isAdmin);
     }
}
Image from book

You may notice how similar the implementation of the writeExternal() method of the client User class is to the corresponding method on the server User class.

Following is the writeExternal() method of the client (ActionScript) User class:

public function writeExternal(output:IDataOutput):void
{
     output.writeInt(id);
     output.writeUTF(username);
     output.writeBoolean(isAdmin);
}

Following is the writeExternal() method of the server (Java) User class:

public void writeExternal(ObjectOutput output) throws IOException
{
     output.writeInt(id);
     output.writeUTF(username);
     output.writeBoolean(isAdmin);
}

Destinations and Security

You can restrict access to destinations to a privileged group of users by applying a security constraint in a destination definition. This ensures that a user must be authenticated either by custom or basic authentication before accessing the destination.

The following example shows a security constraint that is declared inline in a destination definition:

<service>
    <destination id="destination">
        <security>
            <security-constraint>
                <auth-method>SomeAuthMethod</auth-method>
                <roles>
                    <role>destUser</role>
                </roles>
            </security-constraint>
        </security>
    </destination>
</service>

There is also a way to declare a global security constraint to use with several destinations. You define one security constraint in the security section of the FDS configuration file and refer to it in each destination definition. The following example shows a global security constraint that is referenced in three destination definitions:

<service>
    <destination id="Destination1">
        <security>
            <security-constraint ref="trusted"/>
        </security>
    </destination>
    <destination id="Destination2">
     <security>
             <security-constraint ref="trusted"/>
     </security>
    </destination>
    <destination id="Destination3">
     <security>
             <security-constraint ref="trusted"/>
     </security>
    </destination>
</service>

<security>
    <security-constraint id="trusted">
        <auth-method>CustomAuthMethod</auth-method>
        <roles>
            <role>trustedUsers</role>
        </roles>
    </security-constraint>
</security>

In Flex, there is a way to send user credentials to a destination that uses a security constraint. You specify the username and password as parameters of the setCredentials() method of the HTTPService, WebService, RemoteObject, DataService, Publisher, or Consumer component that you are using.

Note that the setCredentials() and setRemoteCredentials() methods don’t do anything when the service component’s userProxy property is set to false.

The following example shows you how to use the setCredentials() method to send a username and password from a WebService component to a destination:

var wSrv:WebService = new WebService();
wSrv.destination = "SecureWSDest";
wSrv.setCredentials("myUsername", "myPassword");
wSrv.getWeather("27596");

The setRemoteCredentials() method is used to pass credentials to a remote HTTP service or Web service. The username and password are sent to the destination in the message headers.

You can also use the setRemoteCredentials() method for a Remoting Service destination that requires a username and password for authentication, such as a ColdFusion component (CFC).

The following example shows you how to use the setRemoteCredentials() method to send a username and password from a RemoteObject component to a destination:

var rSrv:RemoteObject = new RemoteObject();
rSrv.destination = "SecureRODest";
rSrv.setRemoteCredentials("myUsername", "myPassword");
rSrv.getWeather("27596");

Another alternative to setting remote credentials is to define them in the FDS configuration file. The following example shows destination with remote username and password defined inline:

<destination id="samplesProxy">
        <channels>
            <channel ref="samples-amf"/>
        </channels>

        <properties>
            <url>
                http://www.server.com/secure_service.cfm
            </url>
            <remote-username>sbarber</remote-username>
            <remote-password>password</remote-password>
        </properties>
</destination>

Configuring Logging

In FDS, you can configure server-side logging for requests and responses. This can be done in the logging section of the Flex services configuration file. The default setting is sent to System.out.

The following table shows several logging levels that are available.

Open table as spreadsheet
Logging Level | Description
all | Designates that all messages should be logged.
debug | DEBUG messages indicate internal Flex activities.
 | Select the debug logging level to include Debug, Info, Warn, and Error log messages in your log files.
info | Info messages indicate general information to the developer or administrator.
 | Select the Info logging level to include Info, Warn, and Error log messages in your log files.
warn | Warn messages indicate that Flex encountered a problem with the application, but it does not stop running.
 | Select the warn logging level to include warn and error log messages in your log files.
error | Error messages indicate when a critical service is not available, or a situation has occurred that restricts use of the application.
 | Select the Error logging level to include Error log messages in your log files.
none | Designates that no messages should be logged.
string | String

The filter pattern elements are defined to specify the categories of information to log. The class attribute of the target element can define the flex.messaging.log.ConsoleTarget to log messages to the standard output, or the flex.messaging.log.ServletLogTarget to log messages to the application server’s default logging system.

The following example defines a logging configuration that uses the Info logging level:

<logging>
    <target class="flex.messaging.log.ConsoleTarget" level="Info">
        <properties>
            <prefix>[Flex ]</prefix>
            <includeDate>false</includeDate>
            <includeTime>false</includeTime>
            <includeLevel>false</includeLevel>
            <includeCategory>false</includeCategory>
        </properties>
        <filters>
            <pattern>Endpoint</pattern>
            <!--<pattern>Service.*</pattern>-->
            <!--<pattern>Message.*</pattern>-->
        </filters>
    </target>
</logging>

Software Clustering

In FDS, a software clustering feature handles failover when using stateful services and non-HTTP channels (such as RMTP channels). So, the process starts with a particular service on one host in a subnet, and if that host fails, the client has the ability to send messages to another host in the same subnet. This feature is available to all services defined in the FDS configuration file.

In most scenarios, clustering for FDS does not use software clustering. Instead, a set of load balancers are used in the form of hardware, and are positioned in front of the HTTP servers. These load balancers direct requests to individual HTTP servers. This can also work in conjunction with the software clustering feature.

The software clusters are defined in the clusters section of the FDS configuration file. You can define multiple clusters, and each must have an id and a path to a JGroups properties file. JGroups is the Open Source software that FDS uses to provide software clustering. You can find out more at the following URL:

  • http://www.jgroups.org/javagroupsnew/docs/index.html

Note that the jgroups.jar and jgroups-*.xml properties files are located in the resources/clustering folder of the FDS installation. You will need to copy the jgroups.jar to the WEB-INF/lib and the jgroups-*.xml files to the WEB-INF/flex directory before you define any clusters.

The following example shows the configuration of a cluster in the services-config.xml file:

<?xml version="1.0"?>
<services-config>
    <clusters>
        <cluster id="Cluster1" properties="jgroups-udp.xml"/>
        <cluster id="Cluster2" properties="jgroups-tcp.xml"/>
    </clusters>
</services-config>

The following example shows a reference to a cluster in a service destination:

<destination id="MyDestination">
    <properties>
        <network>
            <cluster ref="default-cluster" shared-backend="true"/>
        </network>
    </properties>
</destination>

Custom Error Handling

In some cases, you may want to return additional information to the client as part of a message exception. You can use the extendedData property of the flex.messaging.MessageException class. This property is a HashMap that provides a flexible way to return additional data to the client in the event of a failure occurring.

Note that FDS provides bean serialization of any Throwable type.

The following example shows a Java test class that adds extra information to an exception:

package errorhandling;

import java.util.HashMap;
import java.util.Map;
import flex.messaging.MessageException;

public class MyCustomException
{

     public String generateMessageException(String extraData)
     {
          MessageException me = new MessageException("Testing extendedData.");
          Map extendedData = new HashMap();
          extendedData.put("extraData", extraData);
          me.setExtendedData(extendedData);
          me.setCode("999");
          me.setDetails("Some custom details go here.");
          throw me;
     }
}

The following example calls the previous Java object to return an exception with extra data:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="init()">

    <mx:Script>
          <![CDATA[

             import mx.rpc.events.*;
             import mx.messaging.messages.*;

             public var dataString:String = "Extra data.";
             public var actualData:String;

             public function onServiceFault(event:FaultEvent):void
             {
                 actualData = ErrorMessage(event.message).extendedData.extraData;
             }

             public function runException():void
             {
                var call:Object = myException.generateMessageExceptionWithExtendedData
(dataString);
             }

             public function init():void
             {
                 runException();
             }
         ]]>
     </mx:Script>

     <mx:RemoteObject destination="myDest"
          id="myException"
        fault="onServiceFault(event)" />

</mx:Application>


RPC Service Components

Flex supports an architecture that interacts with remote data sources by calling different kinds of services and receiving responses from them. In a typical Flex application, a client-side RPC service sends asynchronous requests to a remote service, which returns the results back to the client.

Defining RPC Components

RPC components can be defined in MXML or ActionScript, depending on your requirements. They can be used to connect to HTTP services and Web services without configuring FDS destinations.

The RemoteObject components send and receive data in AMF format over HTTP. You can either use FDS and define destinations in your services-config.xml file, or use a third-party solution that supports either AMF0 or AMF3 binary format.

You can use the HTTPService and WebService components to send and receive data without configuring FDS destinations. This means that you must set the url property of the HTTPService component or the wsdl property of the WebService component, instead of using the destination property.

Note that the RPC service must be in the same domain as your application, or a crossdomain.xml file must be installed on the Web server hosting the RPC service.

The following example shows two MXML tags: one is an HTTPService component and the other a WebService component. These components directly reference an RPC service using the url and wsdl properties, respectively.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:HTTPService id="httpSrv"
          url="http://www.somedomain.com/search.cfm?q=adobe" />

     <mx:WebService id="webSrv"
          wsdl="http://www.somedomain.com/searchWeather.wsdl" />

</mx:Application>

To ensure HTTP codes are returned correctly, you must use the Flex proxy in FDS. If a service returns any status code other than 200, the Flash Player cannot read the body of the response. The proxy gets around this by forcing the status code to 200, and then the player passes the body with the fault intact.

If you decide to use FDS, you can specify the destination property of the RPC components, instead of using the direct reference. This means you do not have to worry about security sandbox issues with the Flash Player, and no crossdomain.xml file must be on the server of the RPC service.

The following example is the same example as previously shown, except that a RemoteObject component has been added, and the url and wsdl properties of the HTTPService and WebService components have been replaced with the destination property:

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:HTTPService id="httpSrv"
          destination="HTTPDestination"
          useProxy="true" />

     <mx:WebService id="webSrv"
          destination="WebServiceDestination"
          useProxy="true" />

     <mx:RemoteObject id="rObject"
          destination="RODestination"
          useProxy="true" />

</mx:Application>

These destinations are configured in the FDS service-config.xml file.

Calling a Service and Handling Results

The process of calling a service and returning results starts off when you call an RPC service on a remote server, which handles the request, does some processing on the remote server (such as retrieving data from a database), and returns the results back to the client.

To achieve this, you declare an RPC component and call the service using MXML or ActionScript. The calls to the services are asynchronous, so you must declare an event listener to handle the results and faults. If you need to pass parameters to the service, that can be done explicitly or by using binding.

The data is returned in some format that can be controlled using the resultFormat property of the HTTPService or WebService component. The default value for this property is object, so the data is returned as a simple tree of ActionScript objects.

The HTTPService and WebService components return anonymous Objects and Arrays for complex types. By default, Objects are wrapped in mx.utils.ObjectProxy instances, and Arrays are wrapped in mx.collections.ArrayCollection instances.

The following example converts a temperature in Fahrenheit into Celsius. The farenheitTextInput instance’s text property is passed into the getCelsius() method of the RPC service using parameter binding. The result is handled inline and sets the celsiusLabel instance’s text property to the result from the remote server.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[
               import mx.controls.Alert;
          ]]>
     </mx:Script>

     <mx:RemoteObject id="tempRO"
          destination="FarenheitToCelsius"
          useProxy="true"
          result="celsiusLabel.text = event.result as String"
          fault="Alert.show(event.fault.faultString, 'Error')" />

     <mx:TextInput id="farenheitTextInput" />
     <mx:Label id="celsiusLabel"/>
     <mx:Button label="Convert" click="tempRO.getCelsius(farenheitTextInput.text)" />

</mx:Application>


RPC Services Configuration

This section describes how to set up a destination or destinations for your RPC services. As you know, you can call an actual URL or WSDL URL of an HTTP service or Web service, or define a destination. These are configured in the FDS configuration file either directly or by reference within another file.

Destination Configuration

When defining a destination, you reference one or many messaging channels to contact the corresponding server-side service. One or more adapters must also be defined, and that is the server-side code that interacts with the service directly. Default adapters can be defined to avoid explicitly referencing them in each case.

The following example is a Remoting Service definition that contains a destination, one adapter, and one messaging channel:

<service id="remoting-service"
    class="flex.messaging.services.RemotingService"
    messageTypes="flex.messaging.messages.RemotingMessage">

    <adapters>
        <adapter id="java-object"
            class="flex.messaging.services.remoting.adapters.JavaAdapter"
            default="true"/>
    </adapters>

    <default-channels>
        <channel ref="samples-amf"/>
    </default-channels>

    <destination id="UserRO">
        <properties>
            <source>com.company.business.UserDelegate</source>
            <scope>application</scope>
        </properties>
    </destination>
</service>

The following example declares an HTTP service destination with a dynamic-url value, which means that you can use more than one HTTP service url property in the client-side service tags and still go through the Proxy Service:

<destination id="HTTPDestination">
    <channels>
        <channel ref="my-amf"/>
    </channels>
    <properties>
            <dynamic-url>http://www.somedomain.com/services/*</dynamic-url>
    </properties>
</destination>

Destination Properties

The Remote object, Web service, and HTTP service components contain properties that you may find useful when defining destinations in the FDS configuration file.

The following table shows Remote object properties.

Open table as spreadsheet
Element | Description
source | Fully qualified class name of the Java object (Remote object).
scope | Indicates whether the object is available in the request scope, the application scope, or the session scope. Objects in the request scope are stateless. Objects in the application scope are available to the Web application that contains the object. Objects in the session scope are available to the entire client session.
 | The valid values are request, application, and session. The default value is request.
string | String

The following table shows Web service properties.

Open table as spreadsheet
Element | Description
wsdl | (Optional) Default WSDL URL.
soap | SOAP endpoint URL patterns that would typically be defined for each operation in the WSDL document.
 | You can use more than one SOAP entry to specify multiple SOAP endpoint patterns. Flex matches these values against endpointURI property values that you specify in client-side service tags or ActionScript code.
string | String

The following table shows HTTP service properties.

Open table as spreadsheet
Element | Description
url | (Optional) Default URL.
dynamic-url | (Optional) HTTP service URL patterns. You can use more than one dynamic-url entry to specify multiple URL patterns. Flex matches these values against url property values that you specify in client-side service tags or ActionScript code.
string | String


Flex Messaging

Flex Messaging provides a client-side API and a server-side Message Service for creating Flex messaging applications, and enables participation in Java Messaging Service (JMS) messaging.

ColdFusion supports sending messages to a CFC using the ColdFusion Event Gateway Adapter.

The Basics of Flex Messaging

In Flex Messaging, the applications communicate asynchronously by passing packets of data called messages back and forth through a Message Service. The message normally contains a header and a body. The header consists of an identifier and routing information, and the body contains application data.

Applications that send messages are called producers, and, as mentioned previously, the applications that receive messages are called consumers. You will find in most messaging systems that the producers and consumers do not need to know anything about each other. The basic process is one in which a producer sends messages to a specific destination, and the Message Service routes the messages to the appropriate consumers.

A message channel connects consumers and producers to message destinations. A message endpoint encodes data into messages and decodes them into a format that consumers can understand. A message adapter allows you to connect to other messaging systems with Flex Message Service. For example, a JMS adapter will allow your Flex application to connect to JMS topics and queues.

Figure 11-2 shows the flow of data from a producer to consumer.

Image from book
Figure 11-2: Flow of data from a producer to consumer

Flex supports publish-subscribe messaging or topic-based messaging, as well as point-to-point messaging or queue-based messaging. Publish-subscribe messaging is used for a one-to-many relationship between producer and consumers. Point-to-point messaging is used for a one-to-one relationship between producer and consumer.

A topic or queue is represented by a message service destination. Producers publish a message to a specific topic on the message server, and consumers subscribe to those topics to receive messages.

Figure 11-3 shows a publish-subscribe messaging flow. This is a one-to-many relationship with one producer and two or more consumers.

Image from book
Figure 11-3: Publish-subscribe messaging flow

Flex Messaging Architecture

The Flex messaging architecture allows your Flex application to connect to a message destination, send messages, and receive messages from other messaging clients.

The messaging clients can consist of other Flex applications, or other types of clients such as JMS clients. JMS clients can subscribe and publish to the same message destinations as Flex applications. In other words, Flex applications can communicate with Java clients using messages.

Flex Message Service

Flex Message Service contains four components: channels, destinations, producers, and consumers. You can configure Flex Message Service to transport messages over one or more channels. The channels correspond to a specific transport protocol such as AMF, RTMP, or XML socket.

Message Channels

Flex Message Service can be accessed by your Flex application over several different messaging channels. Each channel corresponds to a specific network protocol. On the client, there is code that corresponds to each channel. Any time a message arrives at an endpoint, the message is decoded and passed along to a message broker. This determines where the message must be sent. The message broker does the same for the RPC service and Date Management Service features.

JMS Message Adapter

JMS is a Java API that lets your application create, send, receive, and read messages. The JMS adapter allows Flex messaging to communicate and interact with external messaging systems. The JMS adapter is a very important component of Flex Message Service because it allows Flex applications to subscribe to JMS topics and queues.

Producer Components

Producer components are defined in MXML or ActionScript. You create an AsyncMessage object and call the send() method of a producer to send the message.

A producer component contains an acknowledge and fault event. The acknowledge event is dispatched when a destination successfully receives a message from the producer component. The fault event is dispatched when a destination cannot successfully process the message because of some error.

Creating a Producer Component in MXML and ActionScript

The <mx:Producer> MXML tag is used to create an instance of the producer component. The tag must contain an id tag and should also specify a destination that is defined in the services-config.xml file located on the server.

The following example shows an <mx:Producer> tag that defines a destination and acknowledge and fault event handlers:

<mx:Producer id="myProducer" destination="myDestination" acknowledge=
"acknowledge(event)" fault="fault(event)" />

The following code example is the same as the previous one, except it is written in ActionScript within the <mx:Script> tags:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.events.*;
               import mx.messaging.Producer;

               public function sendMessage():void
               {
                    var producer:Producer = new Producer();
                    producer.destination = "myDestination";
                    producer.addEventListener(MessageAckEvent.ACKNOWLEDGE,
acknowledgeHandler);
                    producer.addEventListener(MessageFaultEvent.FAULT,
faultHandler);
               }

          ]]>
     </mx:Script>

</mx:Application>

Sending a Message

To send a message to a destination you must create an AsyncMessage object, populate it with data in the body property, and pass it into the Producer object’s send() method.

The following code example shows how these steps are accomplished:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.messages.AsyncMessage;

               public function sendMessage():void
               {
                    var message:AsyncMessage = new AsyncMessage();
                    message.body = "body";
                    producer.send(message);
                }

          ]]>
     </mx:Script>

     <mx:Producer id="producer" />

</mx:Application>

The body property of the AsyncMessage object can be set to a custom ActionScript class CustomBody, as the following example shows:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.messages.AsyncMessage;

               public function sendMessage():void
               {
                    var message:AsyncMessage = new AsyncMessage();
                    message.body = new CustomBody();
                    CustomBody(message.body).property1 = "p1";
                    CustomBody(message.body).property2 = "p2";
                    producer.send(message);
               }

          ]]>
     </mx:Script>

     <mx:Producer id="producer" />

</mx:Application>

Adding More Information to a Message

In the AsyncMessage object, there is a headers property in which you can include strings and numbers. The headers property is an associative array where the key is the headers name. The following example calls header1 and sets its corresponding value:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.messages.AsyncMessage;

               public function sendMessage():void
               {
                    var message:AsyncMessage = new AsyncMessage();
                    message.headers = new Array();
                    message.headers["property1"] = 1000;
                    producer.send(message);
               }

          ]]>
     </mx:Script>

     <mx:Producer id="producer" />

</mx:Application>

Consumer Components

The Consumer components in Flex allow you to subscribe to a destination of the Consumer component.

The Consumer component contains a message and fault event to which you can assign event handlers. The message event dispatches when a message is received from the destination. A fault event is broadcast when the channel the Consumer component is connected to cannot establish a connection.

Creating a Consumer Component in MXML and ActionScript

The <mx:Consumer> MXML tag is used to create an instance of the Consumer component. You must specify an id property and should also have a destination defined that matches the relevant one in the services-config.xml.

The following code shows in <mx:Consumer> tag that defines a destination and message and fault handlers:

<mx:Consumer id="consumer" destination="myDestination"
message="messageHandler(event)" fault="faultHandler(event)" />

The following code example creates a Consumer component instance in ActionScript within the <mx:Script> tag:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.*;
               import mx.messaging.events.*;

               private var consumer : Consumer;

               private function sendMessage():void
               {
                    consumer = new Consumer();
                    consumer.destination = "myDestination";
                    consumer.addEventListener(MessageEvent.MESSAGE, messageHandler);
                    consumer.addEventListener(MessageEvent.RESULT, resultHandler);
               }

               private function messageHandler(event:MessageEvent):void
               {
                    // Implementation goes here
               }

               private function resultHandler(event:MessageEvent):void
               {
                    // Implementation goes here
               }

          ]]>
     </mx:Script>

</mx:Application>

Subscribing to a Destination

To subscribe to a destination, the Consumer component’s subscribe() method must be called to receive messages.

The following code example creates a Consumer object and calls the subscribe() method. You can unsubscribe by calling the unsubscribe()method of the Consumer instance.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.messaging.*;
               import mx.messaging.events.*;

               private var consumer : Consumer;

               private function sendMessage():void
               {
                    consumer = new Consumer();
                    consumer.destination = "myDestination";
                    consumer.addEventListener(MessageEvent.MESSAGE, messageHandler);
                    consumer.addEventListener(MessageEvent.FAULT, faultHandler);
                    consumer.subscribe();
               }

          ]]>
     </mx:Script>

     <!--<mx:Consumer id="consumer" destination="myDestination" message=
"messageHandler(event)" fault="faultHandler(event)" /> -->

</mx:Application>

Filtering Messages

Use the selector property of the Consumer component to filter out messages that the component should receive. A selector property uses a string formatted in SQL92 syntax. The Consumer component receives only messages with the headers that match the selector property’s criteria.

The following code example defines the selector property of the Consumer component:

<mx:Consumer id="consumerMXML" destination="myDestination" selector="property1 >
10" />

In this example, the selector property is set to an expression of “property1 > 10”. This means that the consumer will process only messages containing a header of property1 with a value that is greater than 10. You may wonder where these headers are defined. Well, before a producer sends a message to a destination, you can define multiple headers in the AsyncMessage headers array property, as the following example shows:

private function sendMessage():void
{
     var message:AsyncMessage = new AsyncMessage();
     message.headers = new Array();
     message.headers["property1"] = 11;
     message.body = input.text;
     producer.send(message);
}

This message will be accepted by the consumer because the headers array property of the AsyncMessage instance contains a property1 value of 11.


Message Service Configuration

To get messaging to work, you must declare a connection to the server-side destination in the <mx:Producer> and <mx:Consumer> tags. A Message Service destination is the endpoint that you send messages to and receive messages from when performing publish-subscribe or point-to-point messaging.

Message Service Configuration

Common tasks that you will perform in configuring the Message Service are defining message destinations, adding security to message destinations, and modifying logging settings. Message Service destinations can be configured in the FDS configuration file, or a file that is included by reference.

The following example shows a basic Message Service configuration file:

<service id="message-service" class="flex.messaging.services.MessageService"
messageTypes="flex.messaging.messages.AsyncMessage">
    <adapters>
        <adapter-definition id="actionscript"
        class="flex.messaging.services.messaging.
            adapters.ActionScriptAdapter" default="true"/>
        <adapter-definition id="jms"
            class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
    </adapters>
    <destination id="chat-topic">
        <properties>
            <network>
                <session-timeout>0</session-timeout>
                <throttle-inbound policy="ERROR" max-frequency="50"/>
                <throttle-outbound policy="REPLACE" max-frequency="500"/>
            </network>
            <server>
                <max-cache-size>1000</max-cache-size>
                <message-time-to-live>0</message-time-to-live>
                <durable>true</durable>
                <durable-store-manager>
                    flex.messaging.durability.FileStoreManager
                </durable-store-manager>
            </server>
        </properties>
        <channels>
            <channel ref="samples-rtmp"/>
            <channel ref="samples-amf-polling"/>
        </channels>
    </destination>
</service>

Message Service Destination Configuration

Channels are used to transport messages to and from a destination. A destination can reference one or more channels that are defined in the FDS configuration file. Only one channel can be used to conduct a destination.

The following example shows two channels being referenced in a destination:

<destination id="myDestination">
        <channels>
            <channel ref="samples-rtmp"/>
            <channel ref="samples-amf-polling"/>
        </channels>
</destination>

A destination can contain network properties for defining client-server messaging behavior. The following example shows the network properties defined within a destination:

<destination id="myDestination">
        <properties>
            <network>
                <session-timeout>0</session-timeout>
                <throttle-inbound policy="ERROR" max-frequency="50"/>
                <throttle-outbound policy="REPLACE" max-frequency="500"/>
            </network>
        </properties>
</destination>

Message Service destinations use the network properties shown in the following table.

Open table as spreadsheet
Property | Description
session-timeout | Idle time in minutes before a subscriber is unsubscribed. When the value is set to 0, subscribers are not forced to unsubscribe automatically.
throttle-inbound | The max-frequency attribute controls how many messages per second the server can receive. The policy attribute indicates what to do when the message limit is reached.
 | A policy value of ERROR indicates that an error should be returned if the limit is reached. A policy value of IGNORE indicates that no error should be returned if the limit is reached.
throttle-outbound | The max-frequency attribute controls how many messages per second the server can send. The policy attribute indicates what to do when the message limit is reached.
 | A policy value of ERROR indicates that an error should be returned if the limit is reached. A policy value of IGNORE indicates that no error should be returned if the limit is reached. A policy value of REPLACE indicates that the previous message should be replaced when the limit is reached.

A destination can contain server-related properties for controlling server-related parameters. The following example shows the network-related properties defined within a destination:

<destination id="myDestination">
        <properties>
            <server>
                <max-cache-size>1000</max-cache-size>
                <message-time-to-live>0</message-time-to-live>
                <durable>true</durable>
                <durable-store-manager>
                    flex.messaging.durability.FileStoreManager
                </durable-store-manager>
            </server>
        </properties>
</destination>

Message Service destinations use the service-related properties shown in the following table.

Open table as spreadsheet
Property | Description
max-cache-size | Maximum number of messages to maintain in memory cache.
message-time-to-live | This is how many milliseconds a message is kept on the server. A value of 0 means the message lasts forever.
Durable | Boolean value that indicates whether messages should be saved in a durable message store to ensure that they survive connection outages and reach destination subscribers.
durable-store-manager | Durable store manager class to use when not using the JMS adapter. By default, the flex.messaging.durability.FileStoreManager, included with FDS, stores messages in files in the /WEB-INF/flex/message_store/DESTINATION_NAME of your Flex Web application. You can change this location by setting the file-store-root property.
batch-write-size | (Optional) Number of message files to write in each batch.
file-store-root | (Optional) Location for storing message files.
max-file-size | (Optional) Maximum file size in kilobytes for message files.

In Message Service, you can specify an adapter to use (such as ActionScript, JMS, or ColdFusion Event Gateway adapter). You reference the adapter in the destination definition, or use the default configured adapter.

The following example shows two adapter definitions referenced inside a destination:

<service id="myMessageService" class="flex.messaging.services.MessageService"
messageTypes="flex.messaging.messages.AsyncMessage">
    <adapters>
        <adapter-definition id="actionscript"
        class="flex.messaging.services.messaging.
            adapters.ActionScriptAdapter" default="true"/>
        <adapter-definition id="jms"
            class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
    </adapters>

    <destination id="chat-topic-jms">
        <adapter ref="jms"/>
    </destination>
</service>

Building a Custom Message Service Adapter

If you find that the standard adapter does not provide the desired functionality, you can create a custom Message Service adapter. The custom adapter must extend the Flex Message Service Adapter class.

The primary method of any Message Service adapter is the invoke() method. This method is called when a client sends a message to a destination. In the invoke() method, you can include code to send to all the subscribing clients or consumers, or to specify clients by evaluating the selector statements included in the message.

The MessageService.PushMessagesToClients() method is used to send messages in the invoke() method. This method takes a Message object as a parameter. The second parameter is of type Boolean and indicates whether to evaluate the message selector statements. The MessageService.Push MessagesToPeer() method in the invoke() method is used to broadcast messages to peer server nodes in a clustered environment.

package custompackagename;

import flex.messaging.services.ServiceAdapter;
import flex.messaging.services.MessageService;
import flex.messaging.messages.Message;
import flex.messaging.Destination;

public class SimpleCustomAdapter extends ServiceAdapter
{
    public Object invoke(Message message)
    {
        MessageService msgService = (MessageService)service;
        msgService.pushMessageToClients(message, true);
        msgService.sendPushMessageFromPeer(message, true);
        return null;
    }
}

If you want the Message Service adapter to manage its own subscriptions, override the ServiceAdapter.HandleSubscriptions() method. You must also override the ServiceAdapter.Manage() method, which is passed command Messages for subscribe and unsubscribe operations.

To use the custom adapter class, you specify it in the adapter-definition element in the FDS configuration. The following example shows this:

<adapters>
    <adapter-definition id="cfgateway" class="foo.bar.SampleMessageAdapter"/>
</adapters>


Data Management Services

The Data Management Service feature uses client-side and server-side functionality to distribute data among multiple clients and server tiers. The client-side contains the DataService component in ActionScript that works in conjunction with the server-side Data Management Service to provide distributed data. The Data Service component manages data on the client, while the server-side Data Management Service manages the distribution of data among multiple clients and server-side data resources.

Data Management Service vs. RPC Features

The Data Management Service employs a different approach to data than the RPC approach. Data Management Service supports automatic and manual synchronization of a common set of data on multiple clients and server-side data. It also supports offline client-side data persistence for occasionally connected clients. RPC components invoke operations on a remote service that return static results that you bind into an object. Data Management Service is different. The set of data is replicated to multiple clients from the Data Manage ment Service and data is changed. The changes are automatically set to the Data Management Service, which updates the data resource and client applications.

Data Management Service Data Flow

A Data Management Service application uses the Flex messaging framework, discussed earlier in this chapter. Instead of having a client application as the producer and another client application as a consumer, Data Management Services client applications act as both producers and consumers.

Figure 11-4 shows the flow of data between the server-side data resource and an Array Collection object.

Image from book
Figure 11-4: Flow of data between the server-side data resource and an Array Collection object

A Data Management Service uses an adapter to update a data store. If data in one or more clients changes, the Data Management Service automatically synchronizes all client and server versions of the data. Any changes to database or directories do not automatically propagate back into the Data Management Service and client applications.

The Data Management Service also provides functionality for server-side and client-side conflict resolution (APIs for handling data synchronization conflicts).

Data Synchronization Conflicts

When one or more clients change the same piece of data at the same time, data synchronization conflicts can occur. There is an API for detecting and handling data synchronization conflicts, and ensuring the integrity of distributed data by limiting any further changes until conflicts are resolved. The Data Management Service can detect when a data update from a client is out-of-date and inform the client of the conflict.


Distributed Data

As you know by now, Data Management Service allows you to distribute and synchronize data among multiple clients. This section describes how to create client-side Flex applications that can show and distribute data.

Distributed Data Application

A Flex application uses a Data Service component to receive data and send data to the server-side Data Management Service. The data travels over a protocol-specific message channel to and from the Data Manage ment Service. You can manage an ArrayCollection object on multiple clients by using a Data Service component. Any changes made to the data synchronize with the rest of the clients.

The following example creates and fills an ArrayCollection object in ActionScript. The fill() method populates the Array Collection object with data from the Data Management Service destination.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initUI()">

     <mx:Script>
          <![CDATA[

               import mx.collections.ArrayCollection;
               import mx.data.DataService;

               public var ds:DataService;

               [Bindable]
               public var ac:ArrayCollection;

               public function initUI():void
               {
                    ac = new ArrayCollection();
                    ds = new DataService("myDestination");
                    ds.fill(ac);
               }

          ]]>
     </mx:Script>

</mx:Application>

The following example shows a manual update of an item in an Array Collection object. The commit() method of the Data Service object sends the changes to the Data Management Service destination.

var users:ArrayCollection = new ArrayCollection();
var userDS:DataService = new DataService("myUserDestination");
userDS.autoCommit = false;

var user:User = users.getItemAt(10);
user.firstname = "Simon";
userDS.fill(users);
userDS.commit();

Call the DataService.disconnect() method to disconnect connected clients. The Data Service component keeps a copy of its managed data and will resubscribe to pick the changes when you reconnect.

Class Mappings

To map a server-side Java object to a client-side ActionScript object, you use the [RemoteClass(alias="")] metadata tag. You must specify the package and class name of the Java object in the alias value. This is the same technique used when you map client and Java objects using RemoteObject components.

If you do not want to map the ActionScript object to the Java object, but do want it mapped from the server to client, just specify the [RemoteClass] metadata tag without the alias value.

The following example shows an ActionScript object that is mapped to a Java object called com.mycompany.vo.User:

package com.learningpc.livecourse.vo
{

     [Bindable]
     [RemoteClass(alias="com.mycompany.vo.UserVO")]
     public class UserVO
     {
          public var id:Number;
          public var sessionkey:String;
          public var username:String;
          public var password:String;
          public var firstname:String;
          public var middlename:String;
          public var lastname:String;
          public var photo:String;
          public var emailaddress:String;
          public var logincount:Number;
          public var lastlogindate:Date;
          public var lastlogoutdate:Date;
          public var homepage:String;
          public var usertype:String;
          public var lastIp:String;
          public var active:Number;
     }
}

The following shows the corresponding Java object contact:

package com.learningpc.livecourse.vo;

import java.io.Serializable;

public class User implements Serializable
{
     private static final long serialVersionUID = 4832904328320999999L;

     private int id;
     private String username;
     private String password;
     private String firstname;
     private String lastname;
     private String emailaddress;

     public static long getSerialVersionUID()
     {
          return serialVersionUID;
     }

     public String getEmailaddress()
     {
          return emailaddress;
     }

     public void setEmailaddress(String emailaddress)
     {
          this.emailaddress = emailaddress;
     }

     public String getFirstname()
     {
          return firstname;
     }

     public void setFirstname(String firstname)
     {
          this.firstname = firstname;
     }

     public int getId()
     {
          return id;
     }

     public void setId(int id)
     {
          this.id = id;
     }

     public String getLastname()
     {
          return lastname;
     }

     public void setLastname(String lastname)
     {
          this.lastname = lastname;
     }

     public String getPassword()
     {
          return password;
     }

     public void setPassword(String password)
     {
          this.password = password;
     }

     public String getUsername()
     {
          return username;
     }

     public void setUsername(String username)
     {
          this.username = username;
     }

     public String toString()
     {
          StringBuffer sb = new StringBuffer();
          sb.append(username);
          sb.append(" ");
          sb.append(password);
          sb.append(" ");
          sb.append(firstname);
          sb.append(" ");
          sb.append(lastname);
          return sb.toString();
     }
}

Data Synchronization Handling

When working with distribution data, there are often times that clients try to make changes already made. The following example displays an Alert box when a client conflict occurs:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initUI()">

     <mx:Script>
          <![CDATA[
               import mx.controls.Alert;

               import mx.data.*;
               import mx.data.events.DataConflictEvent;

               public var ds:DataService;

               public function initUI():void
               {
                    ds = new DataService("myDestination");
                    ds.addEventListener(DataConflictEvent.CONFLICT, conflictHandler);
               }

               private function conflictHandler(event:DataConflictEvent):void
               {
                    var conflicts:Conflicts = ds.conflicts;
                    var c:Conflict;

                    for (var i:Number = 0; i < conflicts.length; i++)
                    {
                         c = Conflict(conflicts.getItemAt(i));
                         Alert.show("Rolling back", "Conflict has occured");
                         c.acceptServer();
                    }
               }

          ]]>
     </mx:Script>

</mx:Application>


Data Management Service Configuration

To connect to Data Management Service using the <mx:DataService> tag, you must configure a destination in your service-config.xml file. The section describes how to configure the destinations and data adapters they use, and also how to push data to clients.

Data Management Service Destination Configuration

As mentioned previously, messages are transported over message channels. You can define one or more message channels for a destination definition. If one channel cannot be reached, the next one in the list is tried.

The following example shows a destination definition with two message channels defined:

<service id="myDataManagementService" class="flex.data.DataService" messageTypes=
"flex.data.messages.DataMessage">

    <adapters>
        <adapter-definition id="actionscript"
            class="flex.data.adapters.ASObjectAdapter" default="true"/>
        <adapter-definition id="java-adapter"
            class="flex.data.adapters.JavaAdapter"/>
    </adapters>

    <default-channels>
        <channel ref="my-rtmp"/>
    </default-channels>

    <destination id="contact">
        <adapter ref="java-adapter" />
            <properties>
                <source>dev.contacts.ContactAssembler</source>
                <scope>application</scope>
                <cache-items>true</cache-items>
                <metadata>
                    <identity property="contactId"/>
                </metadata>

                <network>
                    <session-timeout>20</session-timeout>
                    <paging enabled="true" pageSize="10" />
                    <throttle-inbound policy="ERROR" max-frequency="500"/>
                    <throttle-outbound policy="REPLACE" max-frequency="500"/>
                </network>

                <server>
                    <fill-method>
                        <name>loadContacts</name>
                    </fill-method>
                    <fill-method>
                        <name>loadContacts</name>
                        <params>java.lang.String</params>
                    </fill-method>
                    <sync-method>
                        <name>syncContacts</name>
                    </sync-method>

                </server>
            </properties>
    </destination>
</service>

Configure Network-Related Properties

The network-related properties are the same as configuring the Flex Message Service, except that there are two additional properties, cluster and paging, as shown in the following table.

Open table as spreadsheet
Element | Description
cluster | The ref attribute of the cluster element references the name of a software cluster, which is configured in the clusters section of the services-config.xml file. For information about clusters, see the earlier section, “Software Clustering.”
paging | The enabled attribute of the paging element indicates whether data paging is enabled for the destination. When you enable paging, the pageSize attribute indicates the number of records to be sent to the client when the client-side DataService.fill() method is called. This element is optional; the default value is false.

Transactions

All client changes are handled as one unit and, if the value cannot be changed, all changes are rolled back. Your J2EE server must support J2EE transactions (JTA) for distributed transactions to work.

The following defines the use of transactions within a destination definition:

<destination id="myDestination">
    <properties>
        <metadata>
            <identity property="name"/>
        </metadata>
    </properties>
</destination>

Item Caching

The default setting in Data Management Service is set to true for items returned from fill() and getitem() calls. This means a complete copy of the managed state of all active clients is kept in each server’s memory.

The following example turns off the cache of items in the destination definition:

<destination id="myDestination">
    <properties>
            <cache-items>false</cache-items>
    </properties>
</destination>

Data Push from Servers to Client

To push data from server to client, you use the Flex.data.DataServiceTransactions Java class. The object is used on the server-side to push changes to managed code stored on clients that have the AutoSyncEnabled property of the DataService component set to true.

The Data Management Service creates an instance of the DataServiceTransaction class when you make changes to a sync method. With the instance, you can call the getcurrentDataServiceTransaction(), deleteitem(), and createitem() methods to trigger additional changes. If the current transaction is rolled back, these changes are not pushed to clients.

Note that when you compile code that uses the FDS Java APIs, you must include the messaging JAR and flex-messaging-common.jar files in your class path.


Summary

FDS adds a new dimension to Rich Internet Applications with publish-subscribe messaging, data synchronization, being able to push data to clients, and much more. With these features, you can build enterprise-class applications that take full advantage of the rich presentation layer provided by Adobe Flex.

Chapter 12 discusses creating MXML components in your Flex applications. MXML components are MXML files or documents that are referenced using MXML tags within your other MXML files. Chapter 12 teaches you about creating MXML components to reuse in your Flex applications.


Part III: Creating and Extending Flex Components

Chapter List

Chapter 12: Creating MXML Components
Chapter 13: Flex Component Properties
Chapter 14: Flex Components
Chapter 15: Custom Formatter, Validator, and Effect Components


Chapter 12: Creating MXML Components

Creating components is one of the most important features of Flex because it allows for the reuse of code created either by you or by other developers. Once a component is created, it can be reused by simply including it within your application. This chapter shows you how to create simple, composite, and advanced components. You learn how to scope and style your components, as well as how to create interfaces and template components.

Creating Simple MXML Components

To create a component, you simply create a new MXML file and add a visual component as the root tag. Ensure that you add the mx namespace to the root tag. If you are using Flex Builder, you can accomplish this by selecting File Image from book New Image from book MXML Component. Simply give it a unique name and choose a Based On tag and you should end up with something like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300">

</mx:Canvas>

Now, add anything you want to the custom component and use it within your application. To use a custom component, you will need to add it as an xml namespace in the parent’s root tag. Assuming the component created is named Test.mxml and is in a folder named components, this is what the main application file would look like when the component is added:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns:comps="components.*">
    <comps:Test id="myComponent"/>
</mx:Application>

Take a look at a real-world example of where you may want to use a very simple custom component. Imagine that you are building an application where the user needs to select his or her birthday and you want the user to choose the month from a ComboBox rather than allowing him or her to free-type the value (which will result in inconsistent data). You could add a ComboBox to your application and create an array of months as the dataProvider, or you could create a very simple custom component that could then be reused within the same application or any application you will build in the future. Selecting the ComboBox to base the component on is the same as extending ComboBox. It just makes it easier to extend a ComboBox, rather than creating a composite component with a ComboBox and its data wrapped in a Canvas. The component would look something like that shown in Listing 12-1.

Listing 12-1: SimpleMonths.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:dataProvider>
    <mx:ArrayCollection>
      <mx:String>January</mx:String>
      <mx:String>February</mx:String>
      <mx:String>March</mx:String>
      <mx:String>April</mx:String>
      <mx:String>May</mx:String>
      <mx:String>June</mx:String>
      <mx:String>July</mx:String>
      <mx:String>August</mx:String>
      <mx:String>September</mx:String>
      <mx:String>October</mx:String>
      <mx:String>November</mx:String>
      <mx:String>December</mx:String>
    </mx:ArrayCollection>
  </mx:dataProvider>
</mx:ComboBox>
Image from book

Listing 12-2 shows the new component being included in the application.

Listing 12-2: SimpleMonthsMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*" backgroundColor="#FFFFFF">
  <mx:Panel title="Simple Months" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <comps:SimpleMonths />
  </mx:Panel>
</mx:Application>
Image from book

Figure 12-1 shows the SimpleMonths component.

Image from book
Figure 12-1: The SimpleMonths component


Scoping Your Components

Scoping within a Flex application refers to the value that will be returned from the this keyword. When this is accessed from within the application’s main file, it will be returned as the reference that Flex has assigned to mx.core.Application.application. When this is accessed from any Flex component, it will be returned as the full path from the root of your application to the component. In other words, this will always refer to the file you are working within. Take a look at Listing 12-3 and Listing 12-4.

Listing 12-3: Index.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 backgroundColor="#FFFFFF" width="350" height="150"
 xmlns:comps="*">
    <mx:Label text="'this = ' {this}" />
    <comps:MyHBox id="myHBox"/>
</mx:Application>
Image from book
Listing 12-4: MyHBox.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Label text="'MyHBox this = ' {this}" />
</mx:HBox>
Image from book

In these examples, this is being accessed from the Index.mxml file (Listing 12-3) within the Label component, and this is also being accessed within the Label component of the MyHBox custom component (Listing 12-4). The results can be seen in Figure 12-2. Notice that when this is called from the custom component, the ID of the component is returned. If there is no ID supplied, Flex assigns an ID.

Image from book
Figure 12-2: The this being accessed in multiple ways


Styling Your Components

Components are self-contained and can be styled individually, or they can simply accept the style properties defined by the parent application’s style settings. Components can be styled inline by adjusting the style properties within the MXML code. They can be styled using CSS within an <mx:Style> tag, or they can be skinned. Listing 12-5 shows SimpleStyledMonths.mxml. In the example shown in Figure 12-3, the properties of the MXML root tag were updated to take on a purple style and square corners. Figure 12-3 shows the original custom component, as well as the styled version.

Listing 12-5: SimpleStyledMonths.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
   themeColor="#400080" borderColor="#800080"
   fillColors="[#800080, #ffffff]"
   fillAlphas="[0.5, 0.5]"
   cornerRadius="0">
  <mx:dataProvider>
    <mx:ArrayCollection>
      <mx:String>January</mx:String>
      <mx:String>February</mx:String>
      <mx:String>March</mx:String>
      <mx:String>April</mx:String>
      <mx:String>May</mx:String>
      <mx:String>June</mx:String>
      <mx:String>July</mx:String>
      <mx:String>August</mx:String>
      <mx:String>September</mx:String>
      <mx:String>October</mx:String>
      <mx:String>November</mx:String>
      <mx:String>December</mx:String>
    </mx:ArrayCollection>
  </mx:dataProvider>
</mx:ComboBox>
Image from book
Image from book
Figure 12-3: SimpleMonths and SimpleStyledMonths components


Advanced MXML Components

The SimpleMonths example was a very basic implementation of a custom component. More advanced components include custom properties, methods, and even additional components combined together to create what is known as a composite component.

Adding Custom Properties and Methods to a Component

The SimpleMonths example created previously is limited to showing only the name of the month. But what if the application calls for the display to show only the number or the abbreviation of the months? Should you then create new components called MonthsByName, MonthsByNumber, and MonthsByAbr? he answer is no, because you can very easily build this functionality into one simple component. This can be accomplished by adding properties to your component, which can be set when the component is included in the parent document.

The example shown in Listing 12-6 adds a property named labelFieldVar to determine what value to show within the ComboBox. The values that can be set are full, abr, and num, which will display the full month name, the month’s three-letter abbreviation, or the month’s number (1–12), respectively.

Listing 12-6: AdvancedMonths.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml"
    creationComplete="init()"
    dataProvider="{this.months}"
    labelField="{this.labelFieldVar}">
  <mx:Script>
      <![CDATA[
         [Bindable]
         private var months:Array = [{full:"January",abr:"Jan",num:1},
                    {full:"February",abr:"Feb",num:2},
                    {full:"March",abr:"Mar",num:3},
                    {full:"April",abr:"Apr",num:4},
                    {full:"May",abr:"May",num:5},
                    {full:"June",abr:"Jun",num:6},
                    {full:"July",abr:"Jul",num:7},
                    {full:"August",abr:"Aug",num:8},
                    {full:"September",abr:"Sep",num:9},
                    {full:"October",abr:"Oct",num:10},
                    {full:"November",abr:"Nov",num:11},
                    {full:"December",abr:"Dec",num:12}];
         [Bindable]
         public var labelFieldVar:String = "full";

         public function getSelectedMonth(s:String):String{
             return "You have selected "+this.selectedItem[s];
         }
      ]]>
  </mx:Script>
</mx:ComboBox>
Image from book

Notice that labelFieldVar is set as a public property. This is important because only public variables and methods can be accessed from the parent, and only public properties can be set from within the custom MXML tag that is used to add the component to the parent. The labelFieldVar is also set to be bindable, which allows the property to be bound to the component root tag’s labelField property. Also notice that, when the variable is bound, it is accessed by scoping the variable name with this using dot notation. It is not necessary to scope it, because it is a local property, but it is a best practice to do so. If you do not use this, the variable is scoped to this by default.

To set the labelFieldVar, simply add the property to the new MXML tag. Following is an example showing all three versions of this component within a single application. Figure 12-4 shows all three versions of the AdvancedMonths component.

Image from book
Figure 12-4: All three versions of the AdvancedMonths component

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*" backgroundColor="#FFFFFF">
    <mx:Script>
        <![CDATA[
           import mx.controls.Alert;
        ]]>
    </mx:Script>
  <mx:Panel title="Advanced Months" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <comps:AdvancedMonths id="full" labelFieldVar="full"
        change="mx.controls.Alert.show(full.getSelectedMonth('full'))" />
    <comps:AdvancedMonths id="abr" labelFieldVar="abr"
        change="mx.controls.Alert.show(abr.getSelectedMonth('abr'))"/>
    <comps:AdvancedMonths id="num" labelFieldVar="num"
        change="mx.controls.Alert.show(num.getSelectedMonth('num'))" />
  </mx:Panel>
</mx:Application>

The AdvancedMonths component also has a public function added to demonstrate how methods can be added to component. In this example, the method will be called when the component’s change event occurs, passing in the type of month that should be returned. An Alert will show the current value of the component. Although this example may not have any use in the real world, it is simply meant to show the process of calling a method within a component. In the next section, you see the value of calling methods on components within a more detailed example. Figure 12-5 shows the custom component’s method being called from the parent.

Image from book
Figure 12-5: The custom component’s method being called from the parent


Creating Composite Components

A composite component is a component that is made up of multiple components. In the example shown in Listing 12-7 and Listing 12-8, a composite component has been created to capture a user’s birth date.

Listing 12-7: Birthdate.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*"
    creationComplete="init()">
  <mx:Script>
    <![CDATA[
      [Bindable]
      private var days:Array = new Array();

      [Bindable]
      private var years:Array = new Array();

      private function init():void{
        for(var i:int=1; i<=31; i++){
          this.days.push(i);
        }
        for(var j:int=1950; j<=2006; j++){
          this.years.push(j);
        }
        this.daysCB.selectedIndex=1;
        this.yearsCB.selectedIndex=30;
      }

      [Bindable]
      public var labelFieldVar:String = "full";

      public function getBirthdate():Date{
          return new Date(this.yearsCB.selectedItem,this.monthsCB.selectedItem['num']
-1,this.daysCB.selectedItem);
      }
    ]]>
  </mx:Script>
  <comps:AdvancedMonths id="monthsCB" labelField="{this.labelFieldVar}"/>
  <mx:ComboBox id="daysCB" dataProvider="{this.days}" width="50"/>
  <mx:ComboBox id="yearsCB" dataProvider="{this.years}" width="65"/>
</mx:HBox>
Image from book
Listing 12-8: BirthdateMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*" backgroundColor="#FFFFFF">

  <mx:Panel title="Birth date" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <comps:Birthdate labelFieldVar="full" id="birthdate" />
    <mx:Button label="getBirthdate()"
        click="mx.controls.Alert.show(birthdate.getBirthdate().toString())"/>
  </mx:Panel>
</mx:Application>
Image from book

The component consists of an HBox as the root element with three nested ComboBox components representing the month, day, and year of a birth date. The new component reuses the AdvancedMonths component that was created earlier in this chapter to represent the birth date month. It contains its own labelFieldVar property, which is passed along to the AdvancedMonths labelFieldVar property. Two new Arrays were added to create the dataProviders for the new ComboBox elements. The new component also contains a public method named getBirthdate that returns a Date object representing the current values of the month, day, and year. The results of this component can be seen in Figure 12-6.

Image from book
Figure 12-6: The results of the Birthdate component’s getBirthdate method


Template Components

Template components are a unique type of component where the variables are typed in a more general way, allowing for flexibility in design. By creating a template component, you can control the layout of the component but still give another developer who implements your template component the freedom to use whatever UI components are desired. The following example illustrates this.

Creating a Template Component

To create a template component, you must first create properties to act as placeholders for the components. In Listing 12-9, four properties are created. They are header, menu, and footer (all of which are typed as UIComponent), and content (which is an Array of UIComponents). Next, run the init function, which adds the components into whatever order and layout you would like.

Listing 12-9: TemplateLayoutComp.mxml Template Component
Image from book

<?xml version="1.0"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init();"
width="100%" height="100%">
  <mx:Script>
    <![CDATA[
    import mx.containers.HBox;
    import mx.core.UIComponent;

    // Define a property for components
    public var header:UIComponent;
    public var menu:UIComponent;
    public var footer:UIComponent;

    // Define an Array of elements for the mainContent
    // components of type mx.core.UIComponent.
    [ArrayElementType("mx.core.UIComponent")]
    public var content:Array;

    private function init():void {

      // Add the header component
      this.addChild(header);

      // Create an HBox container. This container
      // is the parent container of the bottom row of components.
      var body:HBox= new HBox();
      body.percentHeight=100;
      body.percentWidth=100;
      addChild(body);
      body.addChild(menu);
      var mainContent:VBox = new VBox();
          mainContent.percentHeight=100;
          mainContent.percentWidth=100;

      // Loop through the content Array and add components to mainContent section
      for (var i:int = 0; i < this.content.length; i++){
        mainContent.addChild(this.content[i]);
      }

      // Add the body
      body.addChild(mainContent);

      // Add the footer
      this.addChild(footer);
    }
    ]]>
  </mx:Script>
</mx:VBox>
Image from book

In this particular example, the header is added to the root VBox. An HBox named body is created to hold the menu and the mainContent, which is a VBox that was created to hold the contents of the content Array. The mainContent is created by looping over the content Array and adding each component as a child of mainContent. Finally, the footer is added to the root VBox, and the function is complete.

Using a Template Component

To use a template component, you must add it to your MXML file (just as you would add any other custom component) and then define the content sections by name, scoped with the component namespace.

Take a look at the examples shown in Listing 12-10 and Listing 12-11. Both use the TemplateLayoutComp that was defined earlier in this section. The namespace is defined as comps, so this is what is used to scope the inclusion of the TemplateLayoutComp. Nested within this component tag are the definitions of the component properties.

Listing 12-10: UseTemplate1.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comps="*"
  width="500" height="500"
  backgroundColor="#FFFFFF">
  <comps:TemplateLayoutComp id="tc1" borderStyle="solid">
    <comps:header>
      <mx:Canvas width="100%" height="30" backgroundColor="#CCCCCC">
        <mx:Label text="This is the section where the header would be."
          horizontalCenter="0" verticalCenter="0"/>
      </mx:Canvas>
    </comps:header>
    <comps:menu>
      <mx:LinkBar color="#0000FF" fontWeight="bold"
        dataProvider="{myViewStack}" direction="vertical"/>
    </comps:menu>
    <comps:content>
      <mx:Label text="This section is set to allow multiple UIComponents" />
      <mx:ViewStack id="myViewStack" borderStyle="solid"
        width="100%" height="100%">
        <mx:Canvas id="s1" backgroundColor="#CC3399"
          label="Screen 1" width="100%" height="100%">
          <mx:Label text="This is Screen 1 of the ViewStack component"/>
        </mx:Canvas>
        <mx:Canvas id="s2" backgroundColor="#33FFCC"
          label="Screen 2" width="100%" height="100%">
          <mx:Label text="This is Screen 2 of the ViewStack component"/>
        </mx:Canvas>
        <mx:Canvas id="s3" backgroundColor="#FFFF66"
          label="Screen 3" width="100%" height="100%">
          <mx:Label text="This is Screen 3 of the ViewStack component"/>
        </mx:Canvas>
      </mx:ViewStack>
      <mx:Label text="Here is a 3rd component in the content section." />
    </comps:content>
    <comps:footer>
      <mx:Canvas width="100%" height="30" backgroundColor="#CCCCCC">
        <mx:Label text="This is the section where the footer would be."
          horizontalCenter="0" verticalCenter="0"/>
      </mx:Canvas>
    </comps:footer>
  </comps:TemplateLayoutComp>
</mx:Application>
Image from book
Listing 12-11: UseTemplate2.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comps="*"
  width="500" height="500" backgroundColor="#FFFFFF">
  <comps:TemplateLayoutComp id="tc2" borderStyle="solid">
    <comps:header>
      <mx:Image source="header.gif" />
    </comps:header>
    <comps:menu>
      <mx:ToggleButtonBar color="#0000FF" fontWeight="bold"
        dataProvider="{myViewStack}" direction="vertical"/>
    </comps:menu>
    <comps:content>
      <mx:Label text="This section is set to allow multiple UIComponents" />
      <mx:ViewStack id="myViewStack" borderStyle="solid"
        width="100%" height="100%">
        <mx:Canvas id="s1" backgroundColor="#CC3399"
          label="Screen 1" width="100%" height="100%">
          <mx:Label text="This is Screen 1 of the ViewStack component"/>
        </mx:Canvas>
        <mx:Canvas id="s2" backgroundColor="#33FFCC"
          label="Screen 2" width="100%" height="100%">
          <mx:Label text="This is Screen 2 of the ViewStack component"/>
        </mx:Canvas>
        <mx:Canvas id="s3" backgroundColor="#FFFF66"
          label="Screen 3" width="100%" height="100%">
          <mx:Label text="This is Screen 3 of the ViewStack component"/>
        </mx:Canvas>
      </mx:ViewStack>
      <mx:TextInput width="100%"
        text="Here is a 3rd component, this time a TextInput." />
    </comps:content>
    <comps:footer>
      <mx:Canvas width="100%" height="30" backgroundColor="#CCCCCC">
        <mx:Label text="This is the section where the footer would be."
          horizontalCenter="0" verticalCenter="0"/>
      </mx:Canvas>
    </comps:footer>
  </comps:TemplateLayoutComp>
</mx:Application>
Image from book

Notice that the first example header is defined as a Canvas with a Label nested within. Looking further, you will see the menu defined as a LinkBar, the content defined as a ViewStack with nested Label and Canvas components, and, finally, a footer defined as a Label. The results of this example can be seen in Figure 12-7.

Image from book
Figure 12-7: The results of UseTemplate1.mxml

Now, take a look at the second example using the same TemplateLayoutComp and you will see that the header has been replaced by an Image, the menu has changed from a LinkBar to a ToggleButtonBar, and one of the Label components in the content section has been changed to a TextInput. These changes are all valid because they still meet the requirements of the TemplateLayoutComp, which had all of these areas typed as UIComponent. The results of the second example can be seen in Figure 12-8.

Image from book
Figure 12-8: The results of UseTemplate2.mxml


MXML Interfaces

As in most object-oriented languages, MXML allows the use of interfaces to define component functionality. Interfaces are a great way to decouple function definitions from implementations. Interfaces are created to act as a blueprint for any object that implements them. The interface declares public method and property definitions that must be included in the class that implements the interface.

Creating Interfaces

To create a Flex interface, you must simply create a new ActionScript file and define it as an interface. You can also create an interface in Flex Builder. Click File Image from book New Image from book ActionScript Interface. A dialog box will ask for the package, interface name, and whether it extends any other interface. The basic syntax for an interface looks like Listing 12-12.

Listing 12-12: IBirthdate.as Interface Example
Image from book

package {
  public interface IBirthdate {
    function getBirthdate():Date;
  }
}
Image from book
Tip

You cannot define interface methods as public or private. Interfaces are typically used only to define methods. However, in the event that you want the interface to enforce a property, you can add implicit getters and setters to an interface.

This example shows how a single function must be defined by all classes that implement this interface.

Using Interfaces

To use an interface within an MXML component, you simply need to use the implements property of the component’s root tag. You will also need to define the necessary properties and methods that are outlined in the interface. To use the IBirthdate interface shown in Listing 12-12 within the Birthdate custom component that was shown in Listing 12-7, you simply add implements="IBirthDate" to the component’s root HBox tag. Listing 12-13 shows what it would look like.

Listing 12-13: Birthdate.mxml Component Using IBirthdate as the Interface
Image from book

<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*"
    creationComplete="init()" implements="IBirthdate">
Image from book


Using IMXMLObject

When creating custom components, it is often necessary to run a function when the component is initialized to manipulate data or visual components within the component. To do this, you would usually add a call to a function using the component’s initialize or creationComplete properties. However, if you are building a nonvisual component by extending Object (using <mx:Object> as the root tag), you will not be able to do this, because these properties are not available for type Object.

The solution is to implement mx.core.IMXMLObject. When implementing IMXMLObject, you are required to define a function named initialized. The initialized function will be called automatically after the properties of the component are initialized. The examples in Listing 12-14 and Listing 12-15 show a component implementing IMXMLObject. It has two properties, a and b, that are public, and a private property named total.

Listing 12-14: MyObjectComp.mxml
Image from book

<?xml version="1.0"?>
<mx:Object xmlns:mx="http://www.adobe.com/2006/mxml" implements="mx.core.IMXMLObject">
  <mx:Script>
    <![CDATA[
      private var total:Number;
      public var a:Number;
      public var b:Number;
      // You must define the initialized() method when implementing IMXMLObject.
      public function initialized(document:Object, id:String):void{
        total=a+b;
      }
      public function getTotal():Number{
        return total;
      }
    ]]>
  </mx:Script>
</mx:Object>
Image from book
Listing 12-15: IMXMLObjectExample.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:comps="*" backgroundColor="#FFFFFF">
  <comps:MyObjectComp id="myObjectComp" a="1" b="2"/>
  <mx:Panel title="IMXLObject Sample" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <mx:Button label="getTotal"
      click="mx.controls.Alert.show('Total = ' + myObjectComp.getTotal())" />
  </mx:Panel>
</mx:Application>
Image from book

When the component is initialized the function runs and sets the value for total, which is then returned and shown in the Alert. Figure 12-9 shows the results.

Image from book
Figure 12-9: The results of the getTotal method


Summary

This chapter covered many subtopics, but all had to do with creating MXML components. The ability to extend the built-in Flex components, as well as create composite components, interfaces, and templates, creates limitless possibilities for developers to build components that suit the needs of their projects. It also opens the doors to third-party companies creating new components for Open Source or commercial use to further expand the base that Adobe has provided. The next couple of chapters show additional ways to extend Flex.

Chapter 13 examines all of the pieces that make up a component, including the package statement, import statements, the class name, the default constructor, properties, getters and setters, and methods. It also demonstrates how to create simple and advanced components using ActionScript rather than MXML.


Chapter 13: Flex Component Properties

This chapter examines the many properties of a custom ActionScript component. The first half of this chapter discusses how to create a full ActionScript component, starting with a package statement and finishing with overriding of methods. The second half of the chapter shows additional examples of ActionScript components.

Elements of a Component

ActionScript components are made up of many elements, some of which are required and others of which are optional. The package statement, class name, and constructor are required, whereas the import statements, properties, and methods are optional.

The package Statement

The first thing to define in a custom ActionScript class is the package statement. The package statement includes the full folder path from the root of your application to the class, using dot notation to navigate the folder path, as shown here:

package com.mydomain.components
{
    // Class definition
}

import Statements

The first section of the class definition includes the import statements. This is the area where you define all of the classes that you will need to import to meet the requirements of your class. To add the import statements, simply use the import keyword, followed by the path to the class you would like to import. Following is an example of importing a single class:

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;
}

You can also import a package of classes using the asterisk in place of a single class name. Following is an example of importing a package of classes:

package com.mydomain.components
{
  // import statements
  import mx.controls.*;
}

Both of these examples will give access to the Button class. However, the second example will also give you access to all of the classes in the mx.controls package.

Defining the Class Name

The next piece of a custom class is the section where you would define the class name. The class name must match the name of the file. For example, if you name your class UCaseTextInput.as, the class name must be defined as UCaseTextInput. Following is an example of naming the class:

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;
  // class name
  public class ValidateButton extends Button {

  }
}

The Default Constructor

The default constructor is the method that Flex uses when it initializes an instance of the class. It should always be declared as public, and it may contain optional arguments if the class will be initialized using ActionScript. If you intend to initialize your class using MXML, you must have a zero argument constructor. The default constructor should not have a return type and should be named the same as the class name. Although not required, it is good practice to make a call to the super method, which calls the default constructor of the parent class.

Following is an example of adding a default constructor:

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;
  // class name
  public class ValidateButton extends Button {
    // default constructor
    public function ValidateButton(){
      // a good practice is to include a call to super().
      super();
    }
  }
}

Defining Properties

Properties are the variables that will be used within the class to hold data. They can be defined as public (which will allow access of their data from outside the class), or they can be defined as protected or private (which restricts their access). Protected properties can be accessed from other classes that extend the custom class, and private properties cannot be accessed from outside the class. Adding getters and setters will allow your private properties to be accessed from outside the class, but you gain the control of how the private data is stored and returned.

Standard Properties

Standard properties are defined as [Access type] var [property name]:[property type]. The following example includes two properties, checkIcon and xIcon. Both are defined as private, which means they will only be accessible from within the class itself.

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;

  // class name
  public class ValidateButton extends Button {

    // define properties
    [Embed(source="good.png")]
    private var checkIcon:Class;

    [Embed(source="bad.png")]
    private var xIcon:Class;

    // default constructor
    public function ValidateButton (){
      // a good practice is to include a call to super().
      super();
      this.setStyle("icon",xIcon);
    }

  }
}

Getters and Setters

A property that is typed as private can only be accessed from within the containing class. To allow this property to be accessed, you will need to add getters and setters. Listing 13-1 has a property named _isValid, which is a private Boolean. Naming the property with a leading underscore will allow you to use implicit getters and setters. Implicit getters and setters allow the variable to be set or retrieved by property name rather than method call. The methods are named with get, followed by a space and then the property name, and set, followed by a space and the property name. The getter returns the class variable (in this case, _isValid), and the setter sets the _isValid variable. Using private properties with get and set methods allows you to have more control over the data.

Listing 13-1: Adding Private Properties with Getters and Setters
Image from book

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;

  // class name
  public class ValidateButton extends Button {

    // define properties
    [Embed(source="good.png")]
    private var checkIcon:Class;

    [Embed(source="bad.png")]
    private var xIcon:Class;

    private var _isValid:Boolean;

    // default constructor
    public function ValidateButton (){
      // a good practice is to include a call to super().
      super();
      this.setStyle("icon",xIcon);
    }

    // getters and setters
    public function get isValid():Boolean{
      return this._isValid;
    }
    public function set isValid(b:Boolean):void{
      this._isValid = b;
      if(b){
        this.setStyle("icon",checkIcon);
      }else{
        this.setStyle("icon",xIcon);
      }
    }

  }
}
Image from book

Listing 13-1 shows that the set isValid method does more than simply set the _isValid property; it also changes the button’s icon to a check or “x” mark. The results of this class in its current state can be seen in Figure 13-1 and Figure 13-2.

Image from book
Figure 13-1: The ValidateButton component in an invalid state
Image from book
Figure 13-2: The ValidateButton component in a valid state

Defining Methods

You can add private methods to your class to perform operations within the class, public methods that can be called from outside the class, or protected methods that can only be called from child classes. Listing 13-2 now includes a method named getProperties, which returns a few properties of the custom Button component. The results of this new method can be seen in Figure 13-3.

Listing 13-2: Adding a Custom Method
Image from book

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;

  // class name
  public class ValidateButton extends Button {

    // define properties
    [Embed(source="good.png")]
    private var checkIcon:Class;

    [Embed(source="bad.png")]
    private var xIcon:Class;

    private var _isValid:Boolean;

    // default constructor
    public function ValidateButton (){
      // a good practice is to include a call to super().
      super();
      this.setStyle("icon",xIcon);
    }

    // getters and setters
    public function get isValid():Boolean{
      return this._isValid;
    }
    public function set isValid(b:Boolean):void{
      this._isValid = b;
      if(b){
        this.setStyle("icon",checkIcon);
      }else{
        this.setStyle("icon",xIcon);
      }
    }

    // a method to return propeties
    public function getProperties():String{
      var s:String = "Label = " + this.label + "\n" +
        "Width = " + this.width + "\n" +
        "Height = " + this.height;
      return s;
    }

  }
}
Image from book
Image from book
Figure 13-3: An Alert with the results of a call to the getProperties method

Overriding Methods Using super

To override a method, you will need to use the keyword override. You can also access the parent’s properties and methods using the super keyword. Listing 13-3 now contains a new function that overrides the label property by overriding the implicit public get label method. The new method adds parentheses before and after the original label, which is accessed using super.label. The results of this class with the added override method can be seen in Figure 13-4.

Listing 13-3: Overriding a Method
Image from book

package com.mydomain.components
{
  // import statements
  import mx.controls.Button;

  // class name
  public class ValidateButton extends Button {

    // define properties
    [Embed(source="good.png")]
    private var checkIcon:Class;

    [Embed(source="bad.png")]
    private var xIcon:Class;

    private var _isValid:Boolean;

    // default constructor
    public function ValidateButton (){
      // a good practice is to include a call to super().
      super();
      this.setStyle("icon",xIcon);
    }

    // getters and setters
    public function get isValid():Boolean{
      return this._isValid;
    }
    public function set isValid(b:Boolean):void{
      this._isValid = b;
      if(b){
        this.setStyle("icon",checkIcon);
      }else{
        this.setStyle("icon",xIcon);
      }
    }

    // a method to return propeties
    public function getProperties():String{
      var s:String = "Label = " + this.label + "\n" +
        "Width = " + this.width + "\n" +
        "Height = " + this.height;
      return s;
    }

    // an override to add parentheses to the label
    override public function get label():String{
      return "("+super.label+")";
    }

  }
}
Image from book
Image from book
Figure 13-4: The button label with the parentheses added by the override method

The custom class is now complete, and although it may not be the most useful component, it does demonstrate all of the key elements of an ActionScript component. The following discussion further explores the creation of ActionScript components.


Creating a Simple ActionScript Component

Listing 13-4 is an example of a simple ActionScript component. It is a simple example that creates a TextInput component that self-validates the text property for a valid e-mail address.

Listing 13-4: EmailTextInput Component
Image from book

package com.mydomain.components
{
  import mx.controls.TextInput;
  import mx.events.ValidationResultEvent;
  import mx.validators.EmailValidator;
  import flash.events.Event;

  public class EmailTextInput extends TextInput {

    private var emailValidator:EmailValidator = new EmailValidator();
    private var validator:ValidationResultEvent;

    public function EmailTextInput(){
      super();
      this.addEventListener("change", this.validate);
      this.emailValidator.source = this;
      this.emailValidator.property = "text";
    }

    private function validate(event:Event):void{
      validator = emailValidator.validate();
      if (validator.type==ValidationResultEvent.VALID){
        this.errorString="";
      } else {
        this.errorString = validator.message;
      }
    }
  }
}
Image from book

The class is defined within the com.mydomain.components package and imports the needed classes (including TextInput), as well as the necessary validation and event classes. The class extends TextInput and declares EmailValildator and ValidationResult properties that will be used in the validate function. The default constructor creates a listener that calls the validate function when the text property changes. It also assigns the source and property properties of the emailValidator. Finally, the validate function calls the validate function of the emailValidator and sets the errorString. The results of this component can be seen in Figure 13-5.

Image from book
Figure 13-5: The EmailTextInput component in action


Implementing and Overriding UIComponent Methods

When creating a custom component, you may find it necessary to override public or protected methods to accomplish your needs. Fortunately, Flex makes this a very simple thing to do. The CircleLabel example shown in Listing 13-5 overrides the updateDisplayList function and uses the graphics class to draw an ellipse around the label’s text property.

Listing 13-5: CircleLabel Component
Image from book

package com.mydomain.components
{
  import mx.controls.Label;

  public class CircleLabel extends Label {

    public var circleColor:uint = 0x000000;

    public function CircleLabel(){
      super();
    }
    override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
      super.updateDisplayList(unscaledWidth, unscaledHeight);
      // Draw a circle around the label text
      graphics.lineStyle(1, this.circleColor, 1.0);
      graphics.drawEllipse(-5,-5,this.width+10,this.height+10);
    }
  }
}
Image from book

The updateDisplayList function was selected as the function to override because it is called before the component appears onscreen. The results of the CircleLabel component can be seen in Figure 13-6.

Image from book
Figure 13-6: Two instances of the CircleLabel component


Creating Advanced Components in ActionScript

Listing 13-6 shows an example of an advanced ActionScript component that includes many UIComponents, private variables, getters, setters, styles, and events. The class extends Canvas and is named MultiRowTabs. It has several import statements to give access to Flex containers, controls, and collections. There are also import statements to allow the use of the TabSkin and MouseEvent classes.

Listing 13-6: MultiRowTabs.as
Image from book

package com.mydomain.components
{
  import mx.containers.Canvas;
  import mx.containers.HBox;
  import mx.containers.ViewStack;
  import mx.controls.Button;
  import mx.collections.ArrayCollection;
  import mx.skins.halo.TabSkin;
  import flash.events.MouseEvent;

  public class MultiRowTabs extends Canvas {

   // declare class properties
    public var myViewStack:ViewStack;
    public var tabsPerRow:Number = 4;
    public var rowHeight:Number = 22;
    public var tabRows:Array = new Aray();
    private var _dp:ArrayCollection;
    private var buttonArray:ArrayCollection;

    // default constructor
    public function MultiRowTabs(){

    }

    // getters and setters
    public function get dp():ArrayCollection{
      return _dp;
    }
    public function set dp(a:ArrayCollection):void{
      _dp=a;
      this.removeAllChildren();
      buttonArray = new ArrayCollection();
      var start:Number = 0;
      var end:Number = tabsPerRow;
      var currentY:Number = 0;
      // add rows
      for(var i:Number=0; i<this.dp.length/tabsPerRow; i++){
        // add a new row of tabs by adding a HBox
        tabRows[i] = new HBox();
        // set HBox properties and style
        tabRows[i].percentWidth=100;
        tabRows[i].y = currentY;
        tabRows[i].setStyle("paddingTop",0);
        tabRows[i].setStyle("paddingBottom",0);
        tabRows[i].setStyle("horizontalGap",0);
        tabRows[i].setStyle("verticalGap",0);
        currentY = currentY + rowHeight;
        // add the HBox as a child
        this.addChild(tabRows[i]);
        // add buttons
        for(var j:Number=start; j<end; j++){
          // add button and set properties and style
          var button:Button = new Button();
          button.label = this.dp[j].label;
          button.data = i + "|" + j;
          button.setStyle("upSkin",TabSkin);
          button.setStyle("downSkin",TabSkin);
          button.setStyle("overSkin",TabSkin);
          button.setStyle("selectedUpSkin",TabSkin);
          button.setStyle("selectedOverSkin",TabSkin);
          button.setStyle("selectedDownSkin",TabSkin);
          button.setStyle("selectedDisabledSkin",TabSkin);
          button.percentWidth=100;
          button.height = rowHeight;
          // add eventListener for mouse clicks
          button.addEventListener(MouseEvent.CLICK, clickHandler);
          // add button to the HBox
          tabRows[i].addChild(button);
          // set button selected as false
          button.selected=false;
          // set as selected button if in the o position
          if(j==0)button.selected=true;
          buttonArray.addItem(button);
        }
        // calculate buttons per row
        start = start + tabsPerRow;
        end = end + tabsPerRow;
        if(end > this.dp.length){
           end = this.dp.length;
        }

        var myRowNumber:Number = 0;
        var newCurrentY:Number = 0;
        // position rows so that selected tab is in bottom row
        for(var k:Number=0; k<tabRows.length; k++){
          if(myRowNumber != k){
            tabRows[k].y = newCurrentY;
            newCurrentY = newCurrentY + rowHeight;
          }
        }
        tabRows[myRowNumber].y = newCurrentY;
      }
    }

    private function clickHandler(event:MouseEvent):void{
      // create array to hold row and button info
      var splitArray:Array = event.target.data.split("|");
      var myRowNumber:Number = Number(splitArray[0]);
      var myButtonIndex:Number = Number(splitArray[1]);
      // set viewStack selectedIndex
      this.myViewStack.selectedIndex=myButtonIndex;
      // set all buttons selected property to false
      for(var i:Number=0; i<buttonArray.length; i++){
        this.buttonArray[i].selected = false;
      }
      // set clicked button to selected
      event.target.selected=true;
      var currentY:Number = 0;
      // position rows so that selected tab is in bottom row
      for(var j:Number=0; j<tabRows.length; j++){
        if(myRowNumber != j){
          this.tabRows[j].y = currentY;
          currentY = currentY + rowHeight;
        }
      }
      this.tabRows[myRowNumber].y = currentY;
    }
  }
}
Image from book

Several class properties are defined with both public and private access. The _dp property (which is declared as a private ArrayCollection) is the most important property of the class because it also has a public setter that re-creates the component whenever the dp property changes. The set dp function first clears all of the current child objects, then creates rows of HBox components and adds buttons to each row to act as the tabs. The buttons are styled as tabs, given eventListeners, and assigned data to hold their button index and row number. The clickHandler function is responsible for changing the ViewStack index, setting the clicked button to the selected state, and moving the selected button’s row to the bottom of the component.

The results of this component can be seen in Figure 13-7.

Image from book
Figure 13-7: The MultiRowTabs component with seven tabs


Summary

This chapter has provided definitions of package statements, import statements, class names, default constructors, properties, getters and setters, methods, and override methods. It also has provided examples of simple ActionScript components, overriding of UIComponent methods, as well as advanced ActionScript components.

The definitions and examples show just how powerful ActionScript has become and how easy it is to extend and combine existing classes to create components to meet the needs of any project.

Chapter 14 discusses the use of custom events and metadata tags in custom components. It demonstrates how to compile components to SWC archive files, as well as Runtime Shared Libraries (RSLs) using the Flex SDK or Flex Builder. Finally, it demonstrates how to deploy the SWC and RSL files using the Flex SDK or Flex Builder.


Chapter 14: Flex Components

This chapter discusses many aspects of custom components. It includes examples of using custom events in components and examples of all of the different types of metadata tags that can be used in custom components. It also includes examples of how to compile and deploy your custom components using both the free Flex SDK and Flex Builder.

Custom Events in Components

The ability to define and dispatch events from custom components makes it very easy to get feedback from your components and adjust your application. Adding a custom event to a component is a very simple thing to do. First, define the events within metadata tags at the top of the class definition and then dispatch the event when the criteria you determined necessary have been met.

Dispatching Custom Events

Listing 14-1 shows a class file that extends TextInput and demonstrates how to dispatch a custom event.

Listing 14-1: TextInputWithCountEvent.as
Image from book

package
{
  import mx.controls.TextInput;
  import flash.events.Event;

  [Event(name="lengthOf5Event", type="flash.events.Event")]
  [Event(name="lengthOf10Event", type="flash.events.Event")]
  public class TextInputWithCountEvent extends TextInput
  {
    private var _myText:String;
    private var eventObj:Event;

    public function set myText(s:String):void{
      _myText = s;
      this.text = s;
      if(s.length == 5){
        // Create and dispatch custom event
       eventObj = new Event("lengthOf5Event");
       dispatchEvent(eventObj);
      } else if (s.length==10){
        eventObj = new Event("lengthOf10Event");
       dispatchEvent(eventObj);
      }
    }
  }
}
Image from book

This class declares two custom events by using the Event metadata tag right above the class declaration. There is additional information on the Event metadata tag later in this chapter. The set myText function accepts a String as an argument and sets the text property of the class to the value. It also will dispatch an event when the length of the String is 5 or 10 characters. To dispatch the event, first instantiate the event object and then use the dispatchEvent method to dispatch the event.

The main file, shown in Listing 14-2, creates an instance of the TextInputWithCountEvent custom component and adds event handlers to respond when a custom event is dispatched. The event handler functions simply to show an Alert to demonstrate that they received the dispatched event.

Listing 14-2: TextInputLengthEventSample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns:comps="*"
  backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;
      import flash.events.Event;

      // method to handle custom event
      public function lengthOf5EventHandler(eventObj:Event):void {
        mx.controls.Alert.show("Length is 5");
      }
      public function lengthOf10EventHandler(eventObj:Event):void {
        mx.controls.Alert.show("Length is 10");
      }
    ]]>
  </mx:Script>
  <mx:Panel title="Text Input Length Event Sample" width="300" height="150"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="absolute">
   <!--Instantiate custom class and define method to handle labelChanged event-->
   <comps:TextInputWithCountEvent id="myTI" myText="{myTI.text}"
       lengthOf5Event="lengthOf5EventHandler(event);"
       lengthOf10Event="lengthOf10EventHandler(event);"
       horizontalCenter="0" verticalCenter="0"/>
 </mx:Panel>
</mx:Application>
Image from book

Figure 14-1 shows the results of Listing 14-2.

Image from book
Figure 14-1: The custom event being dispatched


Using Metadata Tags in Components

Metadata tags are special tags that are inserted within your source code that give the compiler information on how to compile the application. There are 12 documented metadata tags, each of which is described here.

[ArrayElementType]

Defining an Array is usually very generic in nature because the elements of the Array can be of any type. However, using the ArrayElementType metadata tag allows you to define the data types of the array elements. Here is the example syntax of [ArrayElementType]:

[ArrayElementType("String")]
public var arrayOfStrings:Array;

[ArrayElementType("Number")]
public var arrayOfNumbers:Array;

[ArrayElementType("mx.core.UIComponent")]
public var arrayOfUIComponents:Array;

[Bindable]

The Bindable metadata tag is one of the most used metadata tags because it allows for easy data synchronization within the components of your application. Bindable can be used to bind simple data, classes, complex data, and functions. To bind a simple piece of data, you must simply define the data with the metadata tag included, as shown in Listing 14-3.

Listing 14-3: SimpleBinding.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
      [Bindable]
      private var me:String="Rich Tretola";
    ]]>
  </mx:Script>
  <mx:Panel title="Simple Binding"  width="500" height="90"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
      <mx:Label text="{me}"/>
  </mx:Panel>
</mx:Application>
Image from book

Figure 14-2 shows the results of Listing 14-3.

Image from book
Figure 14-2: Simple data binding

Bindable also allows binding to events. Listing 14-4 shows how to bind a property using getters and setters, along with an event binding.

Listing 14-4: BindWithGettersAndSetters.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

  <mx:Script>
    <![CDATA[
    private var _phoneNumeber:String = "";
    // Bind getter function to phoneNumberChanged event
    [Bindable(event="phoneNumberChanged")]
    public function get phoneNumber():String {
      return _phoneNumeber;
    }
    // Setter method.
    public function set phoneNumber(value:String):void {
      if (value.length<10) {
        _phoneNumeber = value;
      } else {
        _phoneNumeber = phoneFormatter.format(value);
      }
      // Create and dispatch event
      var eventObj:Event = new Event("phoneNumberChanged");
      dispatchEvent(eventObj);
    }
    ]]>
  </mx:Script>
  <mx:PhoneFormatter id="phoneFormatter"
    formatString="() -#" validPatternChars="#-() "/>
  <mx:Panel title="Bind with Getters and Setters"  width="500" height="90"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <mx:TextInput id="ti1" change="phoneNumber=ti1.text" maxChars="10"
restrict="0-9"/>
    <mx:TextInput id="ti2" text="{phoneNumber}"/>
  </mx:Panel>
</mx:Application>
Image from book

This example has a private variable named phoneNumber, as well as a public getter and setter. The getter method uses the Bindable tag to bind to an event named phoneNumberChanged. This setter method dispatches the phoneNumberChanged event whenever its data changes. By using a setter method, the data can be manipulated before it is set to the private variable. In this example, the data is formatted only when the length of the value coming into the method is 10. When the phoneNumberChanged event is dispatched, the second TextInput component updates because its text property is bound to the phoneNumber variable.

Figure 14-3 and Figure 14-4 show the results of Listing 14-4.

Image from book
Figure 14-3: The example with a length of less than 10
Image from book
Figure 14-4: The formatter has executed when the length is 10

[DefaultProperty]

The DefaultProperty metadata tag is used to set a single property as a default property of a class. This allows the property to be set within a container tag without the need to define the property name. A simple example of this would be a custom Button class. Listing 14-5 shows a simple Button class that has the label property set as the DefaultProperty. Listing 14-6 shows how the label is defined as a string within the custom Button container tags.

Listing 14-5: MyButton.as
Image from book

package
{
  import mx.controls.Button;

  [DefaultProperty("label")]

  public class MyButton extends Button
  {

  }
}
Image from book
Listing 14-6: Main.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns:comps="*">

  <comps:MyButton>
    <mx:String>Test</mx:String>
  </comps:MyButton>

</mx:Application>
Image from book

[Embed]

The Embed metadata tag is used to import images into your application. There are two ways to use Embed. You can either Embed the image within ActionScript and assign it to a variable (as in the first example in the following code), or you can assign it directly to the component property (using the syntax shown in the second example of the following code).

[Embed(source="myIcon.gif")]
[Bindable]
public var myIcon:Class;

<mx:Button label="Icon Button 1" icon="{myIcon}"/>

<mx:Button label="Icon Button 2" icon="{myIcon}"/>

The output from the following is identical to the previous code block. The benefits of creating the myIcon class are that it can be defined one time within a single class, and bound to multiple components within your application.

<mx:Button label="Icon Button 1" icon="@Embed(source=myIcon.gif')"/>

<mx:Button label="Icon Button 2" icon="@Embed(source=myIcon.gif')"/>

[Event]

The Event metadata tag is used to declare events that will be dispatched by your custom class. Adding this metadata tag to your class definition allows you to add an event handler function to the MXML tag used to instantiate your custom class. Listing 14-7 creates a custom Button class that will dispatch an event whenever its label property changes. The main application file shown in Listing 14-8 instantiates the custom Button and creates the event handler function, which dumps the new label property to a TextArea component to show the changes that occur.

Listing 14-7: ButtonLabel.as
Image from book

package
{
 import mx.controls.Button;
 import flash.events.Event;
 // Define the custom event
 [Event(name="labelChanged", type="flash.events.Event")]
 public class ButtonLabel extends Button {
   // property to hold label value
   private var _myLabel:String;
    // public setter method
   public function set myLabel(s:String):void {
     _myLabel = s;
     this.label = s;
     // Create and dispatch custom event
     var eventObj:Event = new Event("labelChanged");
     dispatchEvent(eventObj);
   }
 }
}
Image from book
Listing 14-8: EventSample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 xmlns:comps="*"
  backgroundColor="#FFFFFF">
  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;
           import flash.events.Event;

      // method to handle custom event
      public function labelChanged(eventObj:Event):void {
        myTA.text= myTA.text + "\n"+ eventObj.target.label;
        myTA.verticalScrollPosition = myTA.verticalScrollPosition + 20;
      }
    ]]>
  </mx:Script>
  <mx:Panel title="Event Sample" width="500" height="275"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="absolute">
   <mx:TextInput id="buttonLabelTI"
     change="myButton.myLabel=buttonLabelTI.text" x="10" y="9"/>
   <!--Instantiate custom class and define method to handle labelChanged event-->
   <comps:ButtonLabel id="myButton" labelChanged="labelChanged(event);"
     x="10" y="39"/>
   <mx:TextArea id="myTA" width="200" height="200"  x="249" y="10"/>
 </mx:Panel>
</mx:Application>
Image from book

Figure 14-5 shows the results of Listing 14-7 and Listing 14-8.

Image from book
Figure 14-5: The custom event being dispatched

[Effect]

The Effect metadata tag is used to define a custom effect that will be dispatched when an event occurs. This can be easily demonstrated by building on the earlier Event examples. By simply changing a single line to the ButtonLabel class (Listing 14-9), an effect is defined that can be assigned to an Effect instance (Listing 14-10).

Listing 14-9: Adding the Effect Metadata Tag
Image from book

...
// Define the custom event
 [Event(name="labelChanged", type="flash.events.Event")]
 [Effect(name="labelChangedEffect", event="labelChanged")]
 public class ButtonLabel extends Button {
...
Image from book
Listing 14-10: Adding labelChangedEffect to the Component Instantiation MXML Tag
Image from book

<comps:ButtonLabel id="myButton" labelChanged="labelChanged(event);"
     labelChangedEffect="myEffect" x="10" y="39"/>
Image from book

[IconFile]

IconFile is used to identify the filename of a jpg, gif, or png file that will be used as the icon for your custom class. Whereas the [Embed] metadata tag can be used to embed image files, SWF files, music files, video files, and so on, IconFile is only used to embed a file that will be used as the icon for the custom class. Here is the example of the IconFile syntax:

 [IconFile("icon.png")]
public class CustomButton extends Button
{

}

[Inspectable]

The Inspectable metadata tag is used to define the attributes of your custom component that you would like to display within the code hints and property inspector of Flex Builder 2. The example shown in Listing 14-11 defines a variable named ccType that is inspectable. It defines a defaultValue of Visa, a category of Credit Card, and enumeration values of Visa, Mastercard, Discover, and American Express.

Listing 14-11: MyComponent.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">

  <mx:Script>
    <![CDATA[
      [Inspectable(defaultValue="Visa",
        enumeration="Visa,Mastercard,Discover,American Express"
        category="Credit Card" type="String")]
      public var ccType:String;
    ]]>
  </mx:Script>

</mx:HBox>
Image from book

Figure 14-6 shows an example of the code hints being displayed as the component is added to an application.

Image from book
Figure 14-6: Code hints

Figure 14-7 shows the same example, but this time in Design view, which exposes the property inspector. You can see that the category of properties is Credit Card with the property showing as ccType and the available values within the drop-down list.

Image from book
Figure 14-7: Code hints when in Design view

[InstanceType]

The InstanceType metadata tag is used to declare the type of object that will be allowed when declaring a variable as IDeferredInstance within a template object. The syntax of InstanceType looks like this:

[InstanceType("package.className")]

[NonCommittingChangeEvent]

The NonCommittingChangeEvent is a metadata tag that will prevent a change from occurring when a specified event occurs. Listing 14-12 demonstrates how this works. A private variable named s of type String is created and bound to the ti2 TextInput component. The other TextInput component with the id of ti1 sets the value of s equal to the value of its text property whenever the text changes. Additionally, the Binding metadata tag attached to the s variable is set to bind when the trigger Binding event is dispatched. The triggerBinding event is dispatched only when the Enter key is pressed while typing in the ti1 TextInput component.

Listing 14-12: NonCommittingChangeEventSample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
      import flash.events.Event;
      private var eventObj:Event;

      [Bindable(event="triggerBinding")]
      [NonCommittingChangeEvent("change")]
      private var s:String;

      private function triggerBinding():void{
        eventObj = new Event("triggerBinding");
       dispatchEvent(eventObj);
      }
    ]]>
  </mx:Script>
  <mx:Panel title="NonCommittingChangeEvent Sample"  width="500" height="90"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <mx:TextInput id="ti1" change="s=ti1.text" enter="triggerBinding()" />
    <mx:TextInput id="ti2" text="{s}" />
  </mx:Panel>
</mx:Application>
Image from book

[RemoteClass]

RemoteClass is used to bind an ActionScript class to a Java class. This will allow for automatic data type conversions. Following is an example of an ActionScript class named MyClass in package com.mydomain being bound to a Java class named MyClass in package com.mydomain:

package com.mydomain {
    [Bindable]
    [RemoteClass(alias="com.mydomain.MyClass")]
    public class MyClass {
        public var id:int;

        public var myText:String;

    }
}

[Style]

The Style metadata tag is used to define custom style properties for your components. Simply add the Style metadata tag or tags to your class definition, and then use the getStyle method to retrieve its value.

Listing 14-13 and Listing 14-14 show examples of how to define two styles named borderColor and fillColor, both of which are defined as uint data types. The styles are set within the component tag when the class is instantiated. The updateDisplayList function is overridden and the custom styles are used to draw the circle border and fill.

Listing 14-13: CustomCircle.as
Image from book

package
{
  import mx.core.UIComponent;

  [Style(name="borderColor",type="uint",format="Color",inherit="no")]
  [Style(name="fillColor",type="uint",format="Color",inherit="no")]
  public class CustomCircle extends UIComponent {

    public function CustomCircle(){
      super();
    }

    override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
      super.updateDisplayList(unscaledWidth, unscaledHeight);
      graphics.lineStyle(1, getStyle("borderColor"), 1.0);
      graphics.beginFill(getStyle("fillColor"),1.0);
      graphics.drawEllipse(0,0,100,100);
    }
  }
}
Image from book
Listing 14-14: StyleSample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:comps="*"
  backgroundColor="#FFFFFF">
  <mx:Panel title="Style Sample"  width="200" height="200"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="horizontal">
    <comps:CustomCircle borderColor="#000000" fillColor="#FF0000" />
  </mx:Panel>
</mx:Application>
Image from book

Figure 14-8 shows the results of Listing 14-13 and Listing 14-14.

Image from book
Figure 14-8: Using the Style metadata tag


Compiling Components

To allow components to be easily shared between applications and developers, components can be compiled to SWC files and distributed as SWC files or Runtime Shared Libraries (RSLs). Components can be compiled using the free Flex SDK or Flex Builder. The following examples demonstrate how to compile components in these methods, as well as how to use these compiled components.

Compiling Components with Flex SDK

The Flex SDK uses the compc compiler to compile your custom components into SWC files.

SWC

To create an SWC file with a single class, simply open the compc compiler command window and change directory to the root of your class path. The following command compiles an SWC file named EmailTextInput to c:/jrun4/servers/flex2/flex/WEB-INF/flex/user_classes/EmailTextInput.swc:

compc -source-path . -output c:/swcs/ValidateButton.swc -include-classes
com.mydomain.components. ValidateButton

To create an SWC file that contains multiple files, simply add additional –include-classes statements. To include assets, simply add –include-file, followed by the filename and its path.

compc -source-path . -output c:/swcs/ValidateButton.swc -include-classes
com.mydomain.components.ValidateButton -include-file bad.png
com/mydomain/components/bad.png -include-file good.png
com/mydomain/components/good.png

RSL

To compile the component to a simple library.swf file, you can use the following syntax within the compc compiler. The library.swf within the ValidateButton folder can now be renamed and deployed as an RSL.

compc -source-path . -output c:/swcs/ValidateButton -include-classes
com.mydomain.components.ValidateButton -directory=true -debug=false

Create a folder named RSLSample at C:\RSLSample and copy the ValidateButton folder to this folder. The example at the end of this chapter demonstrates how to compile your application with this new RSL.

Compiling Components with Flex Builder

Flex Builder makes compiling your components to SWC files a very easy procedure. Simply follow the directions here and your SWC will be created automatically.

SWC

To compile an SWC file within Flex Builder, you must first create a Flex Library project by selecting File Image from book New Image from book Flex Library Project (Figure 14-9).

Image from book
Figure 14-9: Creating a Flex library project

Next, name your project the same name as you would like your SWC to be named, as shown in Figure 14-10.

Image from book
Figure 14-10: Naming the project

Once you have named your project, you must either copy your component files into the new project, or link to them as source files. After you have done this, you can add your classes and assets to your build path. You can open this view by right-clicking the Project and selecting Properties, as shown in Figure 14-11 and Figure 14-12.

Image from book
Figure 14-11: Adding classes to the library build path
Image from book
Figure 14-12: Adding assets to the library build path

After you have added your classes and assets, the SWC file will be created automatically (assuming you have your project set to build automatically) within the bin folder of your project, as shown in Figure 14-13. You can now distribute your compiled SWC file to other projects or developers. An SWC file is a file that you can open to show its contents. By renaming the SWC as a zip, you can open and see the contents of the SWC, as shown in Figure 14-14.

Image from book
Figure 14-13: The compiled SWC file in the bin folder
Image from book
Figure 14-14: The contents of the compiled SWC file

RSL

To extract the SWC that was just created to a Runtime Shared Library, simply follow these directions.

The first thing you must do is to add the ValidateButton SWC file that was created earlier to the library path of the Flex build path of the project, as shown in Figures 14-15 and 14-16.

Image from book
Figure 14-15: Adding an SWC file to the project’s library path
Image from book
Figure 14-16: The SWC file after being added

Next, highlight the RSL URL property and click the Edit button. Change the link type to “Runtime shared library (RSL)” and check “Auto extract to swf to RSL URL,” as shown in Figure 14-17. Because the RSL URL was left as a local reference, this will create a new SWF file named ValidateButton.swf in the bin folder of your project.

Image from book
Figure 14-17: Changing RSL URL properties

You can now include any components within this library file in your application, just as you would when working with components that are in a local folder path. To demonstrate this, copy the ValidateButtonMain.mxml file from Chapter 13 into your project and compile it. The results of the compiled SWF from Chapter 13 and the same compiled SWF from this chapter can be seen in Figure 14-18 and Figure 14-19. Notice the large difference in file size of the compiled SWFs.

Image from book
Figure 14-18: Compiled with the components embedded
Image from book
Figure 14-19: Compiled using an RSL for the components

The benefits of RSL are very dramatic. However, they are only useful if you will be using the components compiled within your RSL in multiple applications, because the RSL still must be downloaded. The benefits are only realized when a second application loads using the RSL, and this time it will not need to download the RSL, because it has already cached the RSL it downloaded when running the first application. Another advantage is that the end developer, using an RSL, will always have the latest component when compiling the application.

Deploying Components

Components can be deployed in more than one method. The first method is to simply include the folder path of your component within your project build and compile a single SWF. This is the method that has been demonstrated many times throughout this book. Other methods include deployment as an RSL, or an embedded SWC merged into your code.

RSL with SDK

If you haven’t already done so, create a folder named RSLSample located at C:\RSLSample, and copy the ValidateButton folder that was compiled earlier in this chapter in the section “Compiling Components with Flex SDK” and the subsection “RSL.” Also copy the ValidateButtonMain.mxml file that was created in Chapter 13 into C:\RSLSample. Your folder structure should now look like Figure 14-20.

Image from book
Figure 14-20: C:\RSLSample before compiling the ValidateButtonMain with RSL

Open the command window and navigate to C:\RSLSample (using cd C:\RSLSample) and run the following command to compile the ValidateButtonMain.swf with the RSL. The results of this can be seen in Figure 14-21. To include more than one RSL, simply supply a comma-separated list.

Image from book
Figure 14-21: The newly compiled ValidateButtonmain.swf

mxmlc -runtime-shared-libraries=ValidateButton/library.swf -ex
ternal-library-path=ValidateButton -file-specs ValidateButtonMain.mxml

RSL with Flex Builder

If you are using RSLs with Flex Builder as shown earlier in this chapter, the RSL SWF will be automatically created and moved to the bin folder of your project. It will then be deployed along with your application SWF when you run your application from Flex Builder.

SWC with SDK

Create a new folder directly under C:\ and name it SWCExample. Copy the ValidateButtonMain.mxml file that was created in Chapter 13 and also used in the earlier RSL examples in this chapter. Open the command window and navigate to the SWCExample folder (using cd C:\SWCExample) and run the following command:

mxmlc -library-path+=C:/swcs/ValidateButton.swc --file-specs ValidateButtonMain.mxml

As opposed to the earlier RSL examples, this will compile an SWF file that will include all of the files needed to deploy by itself. You will notice that the file size for this SWF is larger, but you can deploy the SWF as a single file without the need to deploy the SWC file. To include more than one SWC file, simply supply a comma-separated list.

SWC with Flex Builder

Compiling an application when using an SWC that has been defined in the library path of the Flex build path of your project and not set to be an RSL will automatically embed all of the files needed in the compiled application SWF. You will be able to deploy the SWF without deploying the SWC file.


Summary

This chapter included information of how to create custom events in components. It provided examples showing custom events being dispatched based on logic within a custom component. It included examples on how to use the [ArrayElementType], [Bindable], [DefaultProperty], [Embed], [Event], [Effect], [IconFile], [Inspectable], [InstanceType], [NonCommittingChangeEvent], [RemoteClass], and [Style] metadata tags.

Lastly, this chapter covered creating SWCs and RSLs, using both the free Flex SDK and Flex Builder. It also provided examples on how to deploy your applications using SWCs and RSLs, using both the free Flex SDK and Flex Builder.

Chapter 15 discusses nonvisual Flex components. These types of components include custom formatters, custom validators, and custom effects. Examples are provided to show how to use the SwitchSymbolFormatter class, how to extend the Formatter class and create custom formatters, and how to create custom validators, as well as examples of how to extend the Effect class.


Chapter 15: Custom Formatter, Validator, and Effect Components

Flex 2 provides RIA developers with the ability to extend the factory base classes and override functions to create custom classes that fit better with the needs of the application being created. This chapter shows you how to customize some of these factory classes. You learn how to use SwitchSymbolFormatter and also how to create a custom formatter. This chapter also shows you how to create custom validators and custom effects.

Custom Formatters

Many built-in formatter classes are used to format phone numbers, dates, currency, and so on. How ever, there will be occasions when it will be necessary to format a string to a format that is not covered by any of the built-in formatter classes. The way to do this is by creating a custom formatter.

Customizing the SwitchSymbolFormatter Class

The SwitchSymbolFormatter class is a very flexible formatter that allows custom format strings as well as custom format characters. Listing 15-1 creates an instance of the SwitchSymbolFormatter on creationComplete as well as on change of the ComboBox component. The formatValue method has two arguments passed in. The first argument is the format string, which, in this example, uses the selected value from the ComboBox. The second argument is the string that will be formatted.

Listing 15-1: Customizing the SwitchSymbolFormatter Class
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="format()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
    import mx.formatters.SwitchSymbolFormatter;

    private function format():void {
         // Create instance of the SwitchSymbolFormatter
      var switchSymbolFormatter:SwitchSymbolFormatter= new SwitchSymbolFormatter();
      // Apply formatter on the unformatted TextInput data using selectedItem from
ComboBox
      formatted.text = switchSymbolFormatter.formatValue(formatString.selectedItem
.toString(), unformatted.text);
    }
    ]]>
  </mx:Script>

  <mx:Panel title="SwitchSymbolFormatter Example"  width="400" height="200"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

          <mx:Form>
      <mx:FormItem label="Unformatted Data:">
        <mx:TextInput id="unformatted" text="123456789" editable="false"/>
      </mx:FormItem>
      <mx:FormItem label="Format String:">
        <mx:ComboBox id="formatString" change="format()">
          <mx:ArrayCollection>
            <mx:String>#-##</mx:String>
            <mx:String>-</mx:String>
            <mx:String>##--#</mx:String>
            <mx:String>#-##</mx:String>
        </mx:ArrayCollection>
      </mx:ComboBox>
      </mx:FormItem>
      <mx:FormItem label="Formatted Data:">
        <mx:TextInput id="formatted" editable="false"/>
      </mx:FormItem>
    </mx:Form>
    </mx:Panel>
</mx:Application>
Image from book

By selecting a new value from the ComboBox, you will see that the new format string will be applied that will reformat the string. The default format character is the pound (#) symbol. Wherever Flex encounters a pound symbol, it places the corresponding character form the string being formatted. If there are other characters in the format string (such as –, as in this example), they will be included in the formatValue results. So a string such as 123456789 with a format string of ###-###-### will be formatted to 123-456-789, as shown in Figure 15-1.

Image from book
Figure 15-1: Formatting a string with the # symbol

There will probably be occasions where the results you would like in your formatted string should include the # symbol. The SwitchSymbolFormatter can accommodate this by allowing the format character to be a custom character rather than the default # symbol.

Listing 15-2 is the same as Listing 15-1, except that the constructor of the SwitchSymbolFormatter is now being passed the asterisk symbol * as the format character. The format string would now use * symbols instead of # symbols, which allows you to now use # in the format string and it will be included in the newly formatted string.

Listing 15-2: Passing the * Character as the Format Character
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
 creationComplete="format()" backgroundColor="#FFFFFF">

  <mx:Script>
    <![CDATA[
    import mx.formatters.SwitchSymbolFormatter;

    private function format():void {
         // Create instance of the SwitchSymbolFormatter and pass in mask character
      var switchSymbolFormatter:SwitchSymbolFormatter = new SwitchSymbolFormatter("*");
      // Apply formatter on the unformatted TextInput data using selectedItem from
ComboBox
      formatted.text = switchSymbolFormatter.formatValue(formatString.selectedItem.
.toString(), unformatted.text);
    }
    ]]>
  </mx:Script>

  <mx:Panel title="SwitchSymbolFormatter Example"  width="400" height="200"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">
          <mx:Form>
      <mx:FormItem label="Unformatted Data:">
        <mx:TextInput id="unformatted" text="123456789" editable="false"/>
      </mx:FormItem>
      <mx:FormItem label="Format String:">
        <mx:ComboBox id="formatString" change="format()">
          <mx:ArrayCollection>
            <mx:String># *-********</mx:String>
            <mx:String># ***-******</mx:String>
            <mx:String># **-***-****</mx:String>
            <mx:String># *******-**</mx:String>
        </mx:ArrayCollection>
      </mx:ComboBox>
      </mx:FormItem>
      <mx:FormItem label="Formatted Data:">
        <mx:TextInput id="formatted" editable="false"/>
      </mx:FormItem>
    </mx:Form>
    </mx:Panel>
</mx:Application>
Image from book

So a string such as 123456789 with a format string of #***-***-*** will result in #123-456-789, as shown in Figure 15-2.

Image from book
Figure 15-2: Formatting a string with the * character

Extending the Formatter Class

Formatters have also been built to be easily extendable, so you have the ability to create custom formatters to meet your needs. To write a custom formatter, you must simply extend the mx.formatters.Formatter class and override the format method.

Custom Formatter Example

Listing 15-3 is admittedly a rather useless example in the real world, but it does demonstrate how easy it is to create a custom formatter. The ReverseFormatter overrides the format method, which accepts an argument of type Object that contains the data to be formatted. It then checks to see if the Object has length and loops over the data and returns it in reverse.

Listing 15-3: Custom Formatter that Will Reverse the Text
Image from book

package
{
  import mx.formatters.Formatter
  // Custom formatters must extend mx.formatters.Formatter
  public class ReverseFormatter extends Formatter {

    public function ReverseFormatter() {
      super();
    }
    // Custom formatters must override format().
    override public function format(formatObj:Object):String         {
      if(formatObj.length == 0) {
        // return empty string and set error property if string has zero length.
        error="Cannot format an empty String";
        return ""
      } else {
           error=null;
        var returnString:String = "";
        // loop through value and build string in reverse
        for(var i:Number=formatObj.length; i>=0; i--){
          returnString = returnString + formatObj.charAt(i);
        }
        return returnString;
      }
    }
  }
}
Image from book

Figure 15-3 shows the ReverseFormatter from Listing 15-4.

Image from book
Figure 15-3: ReverseFormatter in action
Listing 15-4: Sample Application Running the Custom Formatter
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="475" height="175" xmlns:comps="*">

  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;

       private function format():void{
         reversetxt.text = reverseFormatter.format(validatetxt.text);
         if(reverseFormatter.error != null){
           Alert.show(reverseFormatter.error, "Formatter Error");
         }
       }
       ]]>
  </mx:Script>

  <comps:ReverseFormatter id="reverseFormatter" />

  <mx:Panel title="Reverse Formatter" width="100%" height="100%" layout="absolute">
    <mx:TextInput id="validatetxt" width="400" change="this.format()" y="30" x="3"/>
    <mx:TextInput id="reversetxt" width="400" x="3" y="60" editable="false"/>
    <mx:Label width="400" x="3" y="5" text="Type into the field below and see the
results"/>
  </mx:Panel>
</mx:Application>
Image from book

Formatter Errors

Formatters also contain an error property that allows you to get information on the status of the formatter. In the ReverseFormatter example shown in Listing 15-3, the error property is being set to "Cannot format an empty String" when the Object coming into the format function has a length of zero. It is set to null when the Object has a length greater than zero. The sample application will show the error property when it is not null as an Alert. You can see the results of this in Figure 15-4.

Image from book
Figure 15-4: Displaying a formatter error


Custom Validators

Like most of the Flex 2 objects, Validator is extendable. To create your own custom validator you will simply need to extend Validator and override the doValidation method.

The class shown in Listing 15-5 is a custom password validator that will apply certain rules to a string to ensure it complies with a predetermined standard. In this example, you are requiring a password to have at least 1 uppercase letter, 1 lowercase letter, 1 number, and a length of between 6 and 10 characters. Looking at the code, you will see a results Array is defined and then appended to when the validation fails. Determining whether the validation passes or fails is handled by the doValidation method. Within the doValidation method, you will see a series of conditional tests that check the length, as well as searching for specific characters. If the condition being tested returns false, a new Validation Result object is created with a custom errorCode and errorString, which is then appended to the results array and returned.

Listing 15-5: PasswordValidator.as
Image from book

package
{
    import mx.validators.Validator;
    import mx.validators.ValidationResult;

    public class PasswordValidator extends Validator {

        private var results:Array;

        public function PasswordValidator() {
            super();
        }
        // Override the doValidation() method.
        override protected function doValidation(value:Object):Array {

            results = [];

            // Call super's doValidation().
            results = super.doValidation(value);
            // Return if super's doValidation contains errors (required would be an
example).
            if (results.length > 0){
                return results;
            }
            // Check for min length
            var dataString:String = String(value);
            if (dataString.length < 6){
                 results.push(new ValidationResult(true, null, "Short", "Password
must be at least 6 characters."));
                 return results;
            }
            // Check for max length (this can be set in the text component's
maxChars property).
            if (dataString.length > 10){
                 results.push(new ValidationResult(true, null, "Long", "Password
must be no larger than 10 characters."));
              return results;
            }

            // Check for at least 1 uppercase letter.
            if (dataString.search("[A-Z]")<0) {
                results.push(new ValidationResult(true, null, "Upper", "Passwords
must contain at least one upper case letter."));
                return results;
            }
            // Check for at least 1 lowercase letter.
            if (dataString.search("[a-z]")<0) {
                results.push(new ValidationResult(true, null, "Lower", "Passwords
must contain at lease one lower case letter."));
                return results;
            }
            // Check for at least 1 number.
            if (dataString.search("[0-9]")<0) {
                results.push(new ValidationResult(true, null, "Number", "Passwords
must contain at least one number."));
                return results;
            }
            return results;
        }
    }
}
Image from book

Figure 15-5 shows the results of the sample application in Listing 15-6.

Image from book
Figure 15-5: PasswordValidator results
Listing 15-6: Sample Application Using PasswordValidator
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
   backgroundColor="#FFFFFF" width="550" height="300" xmlns:comps="*">

  <comps:PasswordValidator required="true" source="{passwordtxt}" property="text"
trigger="{validatebtn}" triggerEvent="click" listener="{passwordtxt}"/>

  <mx:Panel title="Password Validator" width="350" height="150">
    <mx:TextArea width="100%" height="45" editable="false" borderStyle="none"
text="Password must be between 6-10 characters and contain at least 1 upper case, 1
lower case, and 1 number." />
    <mx:HBox paddingLeft="3">
      <mx:TextInput id="passwordtxt" width="75"/>
      <mx:Button id="validatebtn" label="Validate Password"/>
    </mx:HBox>
  </mx:Panel>
</mx:Application>
Image from book


Creating Effects

There are many built-in effects within Flex 2. However, there will come a time when you would like to create a custom effect. This is made possible by extending the Effect class.

Extending the Effect Class

Extending the Effect class has several requirements. You must create a base class that extends the mx.effects.Effect factory class and also create an instance of a custom mx.effects.Effect Instance class.

The following MyEffect example imports the necessary effects classes. It then extends the Effect class and creates a default constructor that accepts Object and calls the Effect base class constructor. The default constructor also creates an instance of your new EffectInstance class. This example uses the MyEffectInstance class defined later in this section. Next, you must override the getAffected Properties method, and the last thing MyEffect does is override the initInstance method.

package
{
  import mx.effects.Effect;
  import mx.effects.EffectInstance;

  public class MyEffect extends Effect {
    public function MyEffect(targetObj:Object = null)         {
      // Call mx.effects.Effect constructor.
      super(targetObj);

      // Set instanceClass to the name of your new custom EffectInstance
      instanceClass= MyEffectInstance;
    }
    // override the getAffectedProperties() method
    override public function getAffectedProperties():Array         {
    return [];
  }

  // Override initInstance() method.
  override protected function initInstance(inst:EffectInstance):void{
    super.initInstance(inst);
    }
  }
}

Extending the EffectInstance Class

To create an EffectInstance custom class, you must extend the mx.effects.EffectInstance class and override the play() method. Within the play method, you must make a call to super.play. You can also override the end, pause, resume, and reverse methods to customize your effect further, as shown in the following example. The constructor accepts a targetObj, which is passed to the EffectInstance class when super is called. This is the object that the effect will be applied to.

package
{
  import mx.effects.EffectInstance;

  public class MyEffectInstance extends EffectInstance {
    // Define constructor.
    public function MyEffectInstance(targetObj:Object) {
      super(targetObj);
    }
    // Override play() method.
    override public function play():void    {
      super.play();
      // Your custom effect goes here
    }
  }
}

Custom Effect Example

Listing 15-7 creates an effect that will accept a scale factor that will be applied to the target object’s scaleX and scaleY properties. This example of a custom effect demonstrates everything involved in the creation of a custom effect.

Listing 15-7: CustomEffect.as
Image from book

package
{
  import mx.effects.Effect;
  import mx.effects.EffectInstance;

  public class CustomEffect extends Effect {
    // Define scaleTo parameter
    public var scaleTo:Number;

    public function CustomEffect(targetObj:Object = null)         {
      super(targetObj);
      instanceClass= CustomEffectInstance;
    }

    // override getAffectedProperties() and
    // pass the properties effected
    override public function getAffectedProperties():Array         {
      return ["scaleX,scaleY"];
    }

    // Override initInstance()
    override protected function initInstance(inst:EffectInstance):void{
      super.initInstance(inst);
      CustomEffectInstance(inst).scaleTo = scaleTo;
    }
  }
}
Image from book

The CustomEffect class extends mx.effects.Effect and creates a scaleTo variable, which will hold the scale factor. Within the default constructor, the instanceClass variable is set to CustomEffect Intance. The getAffetctedProperties method is overridden and returns the properties that will be affected by this effect. Because you will be altering the scale, the properties returned are scaleX and scaleY. Last, the initInstance method is overridden and the scaleTo property is passed along to your instanceClass.

The CustomEffectInstance class shown in Listing 15-8 extends mx.effects.EffectInstance and creates a variable to hold the scaleTo value. The play method is overridden where the scaleX and scaleY properties of the target are set to the scaleTo variable, which will increase or decrease the target’s size. Last, the reverse method is overridden where the scaleX and scaleY are set back to 1, which returns the target to its original size.

Listing 15-8: CustomEffectInstance.as
Image from book

package
{
  import mx.effects.EffectInstance;

  public class CustomEffectInstance extends EffectInstance {
    // Custom Parameter
    public var scaleTo:Number;

    public function CustomEffectInstance(targetObj:Object) {
      super(targetObj);
    }
    // Override play() method.
    override public function play():void    {
      super.play();
      target.scaleX=scaleTo;
      target.scaleY=scaleTo;
    }
    override public function reverse():void{
      target.scaleX=1;
      target.scaleY=1;
    }
  }
}
Image from book

Using the custom effect is the same as using any other effect class. You simply define the effect and its properties, and set a target. The play and reverse methods are called on the effect from the button’s rollOver and rollout events.

The results of the CustomEffect application in Listing 15-9 can be seen in Figure 15-6 and Figure 15-7, where Figure 15-6 shows the default state of the button and Figure 15-7 shows the button upon rollover. The rollOver and rollOut events are triggered when the cursor enters the boundaries of the button, and then leaves the button boundaries, respectively. In this case, the effect’s play method is called on rollOver and then the reverse method is called on rollOut.

Listing 15-9: CustomEffectApp.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comps="*">

  <comps:CustomEffect id="effect" scaleTo="2" target="{btn}"/>

  <mx:Panel title="Custom Effect Example"  width="250" height="125"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10"
    layout="absolute">

    <mx:Button id="btn" label="Roll Over Me"
      rollOver="effect.play()"
      rollOut="effect.reverse()"
      horizontalCenter="0" verticalCenter="0"  />

  </mx:Panel>
</mx:Application>
Image from book
Image from book
Figure 15-6: Default state of button
Image from book
Figure 15-7: Button upon rollover

Extending the TweenEffect Class

Extending the TweenEffect class has several requirements. You must create a base class that extends the mx.effects.TweenEffect factory class and also create an instance of a custom TweenEffect class.

The following MyTweenEffect example imports the necessary effects classes. It then extends the TweenEffect class and creates a default constructor that accepts Object and calls the TweenEffect base class constructor. The default constructor also creates an instance of your new EffectInstance class. This example uses the MyTweenEffectInstance class defined later in this section. Next, you must override the getAffectedProperties method. The last thing MyTweenEffect does is override the initInstance method.

package
{
    import mx.effects.TweenEffect;
    import mx.effects.EffectInstance;

    public class MyTweenEffect extends TweenEffect
    {
        // Default constructor
        public function Rotation(targetObj:Object = null)         {
            super(targetObj);
           // Define the instanceClass
            instanceClass= MyTweenEffectInstance;
        }
        // override getAffectedProperties()
        override public function getAffectedProperties():Array         {
            return [];
        }
        // Override initInstance() method
        override protected function initInstance(inst:EffectInstance):void         {
            super.initInstance(inst);
        }
    }
}

Extending the TweenEffectInstance Class

To create a TweenEffectInstance custom class, you must extend the mx.effects.effectClasses.Tween EffectInstance class and override the play() method. When overriding the play method, you must call super.play(). After creating a Tween object within the play method, you then override the onTweenUpdate method. If you include an override of the onTweedEnd method, you must make a call to super.onTweenEnd. You can also override the end, pause, resume, and reverse methods to customize your effect further, as shown in the following example:

package myEffects
{
  import mx.effects.effectClasses.TweenEffectInstance;
  import mx.effects.Tween;

  public class MyTweenEffectInstance extends TweenEffectInstance {
    public function MyTweenEffectInstance (targetObj:Object){
      super(targetObj);
    }
    // Override play()
    override public function play():void         {
      // call super.play()
      super.play();
      // Create a Tween object
      var tween:Tween = createTween(this, angleFrom, angleTo, duration);
    }

    // Override onTweenUpdate()
    override public function onTweenUpdate(val:Object):void {
      target.rotation = val;
    }

    // Override onTweenEnd() method.
    override public function onTweenEnd(val:Object):void         {
      // call super.onTweenEnd().
      super.onTweenEnd(val);
    }
  }
}

Custom TweenEffect Example

Listing 15-10 creates a custom tween effect that moves an object from one position to another. This type of tween can be handled with the built-in Move effect class, which demonstrates how a custom TweenEffect that accepts arguments performs the tween.

Listing 15-10: CustomTweenEffect.as
Image from book

package
{
    import mx.effects.TweenEffect;
    import mx.effects.EffectInstance;

    public class CustomTweenEffect extends TweenEffect
    {
        // Define xFrom and xTo parameters
        public var xFrom:Number;
        public var xTo:Number;

        public function CustomTweenEffect(targetObj:Object = null)         {
            super(targetObj);
            instanceClass= CustomTweenEffectInstance;
        }

        // override getAffectedProperties() and
        // pass the properties effected
        override public function getAffectedProperties():Array         {
            return ["x"];
        }

        // Override initInstance()
        override protected function initInstance(inst:EffectInstance):void         {
            super.initInstance(inst);
            CustomTweenEffectInstance(inst).xFrom = xFrom;
            CustomTweenEffectInstance(inst).xTo = xTo;
        }
    }
}
Image from book

The CustomTweenEffect class extends mx.effects.TweenEffect and creates two variables, xFrom and xTo. It sets the instanceClass to the new CustomTweenEffectInstance class within the constructor. The getAffectedProperties method is then overridden, and only the property x being affected is added to the return array. The last thing that is needed is to override the initInstance method and pass the xFrom and xTo properties to the CustomTweenEffectInstance.

The CustomTweenEffectInstance class shown in Listing 15-11 extends mx.effects.effectClasses.Tween EffectInstance and creates the same two variables, xFrom and xTo, which were set by the CustomTweenEffect’s initInstance method. The play method is then overridden and a Tween is created and accepts the xFrom ad xTo arguments within its constructor. The onTweenUpdate method is overridden where the target’s x property is updated, which causes the movement of the target object. The onTweenEnd method is also overridden, but in this case, it only contains the call to the super’s onTweenEnd method.

Listing 15-11: CustomTweenEffectInstance.as
Image from book

package
{
    import mx.effects.effectClasses.TweenEffectInstance;
    import mx.effects.Tween;

    public class CustomTweenEffectInstance extends TweenEffectInstance
    {
        // Custom parameters
        public var xFrom:Number;
        public var xTo:Number;

        public function CustomTweenEffectInstance(targetObj:Object)         {
          super(targetObj);
        }

        // Override play() method.
        override public function play():void         {
          super.play();
          // Create the Tween object
          var tween:Tween = createTween(this, xFrom, xTo, duration);
        }

        // Override onTweenUpdate() method.
        override public function onTweenUpdate(val:Object):void         {
          target.x = val;
        }

        // Override onTweenEnd() method.
        override public function onTweenEnd(val:Object):void         {
          // call super.onTweenEnd().
          super.onTweenEnd(val);
        }
    }
}
Image from book

Figure 15-8 shows the results of the sample application in Listing 15-12. Figure 15-9 shows the result of clicking the button.

Image from book
Figure 15-8: CustomTweenEffect application
Image from book
Figure 15-9: Result of clicking the button
Listing 15-12: CustomTweenEffectApp.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:comps="*"
     backgroundColor="#FFFFFF">

  <comps:CustomTweenEffect id="effect" xFrom="10" xTo="150" duration="1000"
target="{btn}"/>

  <mx:Panel title="Custom Tween Effect Example"  width="250" height="125"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <mx:Button id="btn" label="Click Me" click="effect.play();" />

  </mx:Panel>
</mx:Application>
Image from book

Custom Effect Triggers

Flex 2 has provided developers with the ability to create custom effect triggers to handle circumstances where the built-in events don’t accomplish what is needed by the application. To create a custom effect trigger, you would first define the events and effects using the Event and Effect metadata tags. You will also need to import the flash.events.Event class to create new instances of your custom events. The last thing you need to do is determine what will be the trigger that dispatches the new events.

Listing 15-13 shows two custom events. There is a glowOn and a glowOff event that will trigger the glowOnEffect and the glowOffEffect. The glowOnEffect and glowOffEffect properties are set to glowing and unglow within the <comps:GlowingTextInput /> custom component tag. The glowing and unglow effects are defined within the main application file.

Listing 15-13: GlowingTextInput.as Component
Image from book

<?xml version="1.0"?>
<mx:TextInput xmlns:mx="http://www.adobe.com/2006/mxml"
     focusIn="dispatchEvent(new Event('glowOn'))"
     focusOut="dispatchEvent(new Event('glowOff'))">

    <mx:Metadata>
      <!-- Define the events and effect triggers using the Event and Effect
metadata tags -->
      [Event(name="glowOn", type="flash.events.Event")]
      [Event(name="glowOff", type="flash.events.Event")]
      [Effect(name="glowOnEffect", event="glowOn")]
      [Effect(name="glowOffEffect", event="glowOff")]
    </mx:Metadata>

    <mx:Script>
      <![CDATA[
        import flash.events.Event;

          public function set glow(on:Boolean):void{
            if(on){
              dispatchEvent(new Event('glowOn'));
            } else {
              dispatchEvent(new Event('glowOff'));
            }
          }
        ]]>
    </mx:Script>

</mx:TextInput>

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:comps="*"
     backgroundColor="#FFFFFF">

  <mx:Script>
       <![CDATA[
         private function glow(status:Boolean):void{
        t1.glow=status;
        t2.glow=status;
      }
    ]]>
  </mx:Script>

  <mx:Sequence id="glowing" repeatCount="0">
    <mx:Glow duration="250" alphaFrom="1.0" alphaTo="0.5" blurXFrom="3"
blurXTo="13" blurYFrom="3" blurYTo="13"/>
    <mx:Glow duration="250" alphaFrom="0.5" alphaTo="1.0" blurXFrom="13"
blurXTo="3" blurYFrom="13" blurYTo="3"/>
  </mx:Sequence>

  <mx:Glow id="unglow" duration="500" alphaFrom="0.5" alphaTo="1.0" blurXFrom="13"
blurXTo="0.0" blurYFrom="13" blurYTo="0.0"/>

  <mx:Panel title="Custom Effect Events"  width="240" height="250"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10">

    <comps:GlowingTextInput id="t1" text="Tab between to" width="200"
glowOnEffect="{glowing}" glowOffEffect="{unglow}"/>
    <comps:GlowingTextInput id="t2" text="trigger effects" width="200"
glowOnEffect="{glowing}" glowOffEffect="{unglow}"/>

    <mx:HBox>
      <mx:Button label="All On" click="this.glow(true)"/>
      <mx:Button label="All Off" click="this.glow(false)"/>
    </mx:HBox>
  </mx:Panel>

</mx:Application>
Image from book

This example dispatches the events in two different ways. The first is by using the built-in focusIn and focusOut event handlers to dispatch the custom events. So far, this doesn’t seem very impressive, because you could have simply attached the effects to the focusInEffect and focusOutEffect properties. How ever, the example also dispatches the same custom events when the user clicks the All On and All Off buttons on the user interface. This method of dispatching the events is triggered when a property of the custom TextInput component gets set from the click handler of the on and off buttons.

Figure 15-10 shows the application with a simple focusIn to the TextInput, and Figure 15-11 shows the application after the All On button has been clicked.

Image from book
Figure 15-10: Custom effect application
Image from book
Figure 15-11: Result of clicking the All On button


Summary

This chapter showed the many ways to customize the pieces of Flex that are used all the time. There are many built-in validators, formatters, and events, but you will definitely find occasions when you will need something that is not already covered within the built-in classes. Fortunately, the built-in validators, formatters, and effects classes are extendable, and can be customized to suit your needs. This chapter has shown you how to extend these classes and provided examples to show just how easily it can be done.

Chapter 16 delves into ActionScript 3. It covers what is new in ActionScript 3 and discusses how it has changed from previous versions.


Part IV: Programming ActionScript 3.0

Chapter List

Chapter 16: Overview of ActionScript Programming
Chapter 17: Data Types and Classes


Chapter 16: Overview of ActionScript Programming

ActionScript is the programming language used in building applications for the Adobe Flash Player. The Flash Player uses what is called the ActionScript Virtual Machine (AVM) to execute ActionScript code. Every Flex application uses the ActionScript language for the ability to handle data, user interactivity, or manipulate graphical assets. This chapter discusses the following ActionScript areas:

  • Introduction to ActionScript - With Flex 2 and Flash Player 9, a new ActionScript language and AVM were introduced. There are previous version compatibility points to be discussed.

  • Getting Started with ActionScript - ActionScript 3.0, in particular, makes up more than just Flex applications. Understanding how ActionScript is used to code for both Flex and Flash applications will enhance your development abilities.

  • Display Programming - ActionScript 3.0 introduced a new architectural hierarchy of classes where Object, Sprite, and Display Object play key roles. You learn about the display classes and how to use them.

Introduction to ActionScript

ActionScript has had a steady history throughout the 10 years of the Flash Player’s existence. As the Flash Player has progressed over the years, so has ActionScript. The current version of ActionScript, introduced along with Flex 2 is version 3.0. ActionScript 3.0 requires the Flash Player 9. The Flash Player 9 is backward-compatible with ActionScript 1 and 2 by having both virtual machines inside the Flash Player. This allows the Flash Player 9 to support ActionScript 1.0/2.0 and ActionScript 3.0.

The newer player was built to support the newer functionality required for ActionScript 3.0’s newer features.

ActionScript 3.0 as a language is similar to JavaScript. The particular specification of the ActionScript language is based on the ECMA-262 Edition 4, also known as ECMAScript.

What’s New in ActionScript 3.0

The biggest change to the ActionScript language corresponds to the new ActionScript Virtual Machine (AVM). With a more robust object-oriented ActionScript 3.0 ECMAScript–compliant language, the Flash Player received a newer ActionScript virtual machine, called AVM2, to execute the code.

Tip

In November 2006, Adobe contributed source code from the ActionScript Virtual Machine (AVM2) (which is part of Flash Player 9) to the new Mozilla project known as Tamarin. You can find the project at http://www.mozilla.org/projects/tamarin/ .

The new core language features directly relating to the new virtual machine are the basis for the Flash Player API changes. Taken together, the changes provide large performance improvements, a standards-based language, better XML support, and an event model based on the Document Object Model (DOM).

The following table lists and describes the core language features that are new to ActionScript 3.0.

Open table as spreadsheet
Feature | Description
Run-time Exceptions | ActionScript 3.0 can send run-time errors. Along with the error handling, the normal try, catch, and finally language statements are available to handle the exceptions. This helps provide better debugging workflow, and the ability to create applications that can handle errors more robustly.
Object Types | In the previous versions of ActionScript, typing or declaring variables did not actually change the object type. All variables were created dynamically at run-time. With ActionScript 3.0, that has changed. Along with strong compile-time type-checking and run-time type-checking, Flash Player can represent each specific type in a more native-specific representation. This equates to better performance and memory optimization.
Sealed Classes | Now, all classes in ActionScript 3.0 are defaulted to be sealed, meaning you cannot add properties to any object dynamically. To make a class dynamic, the keyword dynamic is used. This, along with object typing, provides for compile-time type checking and saves on memory that formerly was required to look up the references to the dynamic properties.
Method Closures | Previous ActionScript versions had method call scoping issues. The new method closure feature makes the default scope for each method the same as the original object instance. This saves you from having to use the typical "obj.owner = this;" property, or also a having to rely on a popular workaround using the mx.utils.Delegate class.
XML (E4X) | One of the standard specifications implemented inside of the ActionScript 3.0 language defines how XML is handled. The newer XML native object in ActionScript 3.0 provides a more intuitive easy-to-use dot notation approach to navigating and manipulating XML documents.
Regular Expressions | The latest version of ActionScript introduces native support for regular expressions. This provides the ability to manipulate and find patterns in strings in a very powerful and robust method. The implementation also follows ECMAScript standards.
Namespaces | A little-known addition is the new access specifier called namespaces. They act like the other access specifiers (public, private, and protected), and define custom visibility control for declarations. They are also used with XML and conform to the Universal Resource Identifier (URI) standard to avoid naming conflicts. Because the MXML pages conform to the XML standard, namespaces are used for referencing component tags.
New Primitive Types | To help with performance and memory management, new primitive types have been introduced in the ActionScript 3.0 language. The most noticeable are the wide array of numeric types, int, uint, and Number. Chapter 17 covers the ActionScript 3.0 data types in more detail.

The following table lists and describes some of the Flash Player API features that are new to ActionScript 3.0.

Open table as spreadsheet
Feature | Description
DOM3 event model | The Document Object Model (DOM) Level 3 event model defines a standardized method of creating and consuming event messages. Flash Player–related events and error messages are located in the flash.events.* packages. With the package packaged into the Flash Player, both Flex and Flash applications can use the events and errors.
Display list API | All visual building blocks for Flash objects before Flash Player 9 were based on the MovieClip class. The newer Flash Player API introduces what is known as the display list objects. The different usages of the old MovieClip class have been divided up into specific use classes like the Sprite and Shape classes. This is described in detail later in this chapter.
Accessing run-time content dynamically | Previous dynamic access and manipulation of data or content was handled very differently for each specific area (for example, XML.sendLoad, getURL(), and so on). The newer Flash Player provides a standardized mechanism for loading and handling data and content. The updated and new classes that handle dynamic content are the Loader, URLLoader, and Socket classes.
Low-level data access | The biggest part of the low-level data access updates entails raw binary data access. You can now access the binary data as the data is being loaded . The URLLoader implements the URLStream class. Also, the BtyeArray class provides the ability to manipulate binary data. Other improvements were made to the sound classes to support channels and mixers as well as new security errors.
Text Updates | Flash Player 9 continued on what was introduced in Flash Player 8 to provide better text-rendering support. Also, the searching and cursor indexing classes and methods have been created for better text navigation and replacement.

Another big part of the newer ActionScript language is syntax and class changes. The best place to start with learning the differences in classes is Adobe’s live documentation. You can find the ActionScript 2.0 Migration page at http://www.adobe.com/go/AS2toAS3. The biggest change is that everything has been restructured into packages and classes. You can find a list of all the documented classes and functions in the section “Getting Started with ActionScript” later in this chapter.

Compatibility with Previous Versions

All these newer features (both in the ActionScript language and Flash Player) show how different this version is architecturally and conceptually. With all the changes, there are a few compatibility issues or situations that must be discussed. The Flash Player has done a great job of supporting backward compatibility of content published for previous versions. The challenge for the newer Flash Player 9 is in the interoperability of running old and new content at the same time.

The interoperability issue depends on two factors. The first factor is the client’s Flash Player version, because each specific version will have different functionality available. The second factor depends on which version the content was published for.

Every version of the Flash Player can load and play content created for the same or earlier versions. As mentioned, the new Flash Player 9 introduced a newer AVM, called AVM2. The earlier AVM1 present in the Flash Player 7 (and later) supports SWFs created with AS 1.0 and 2.0. Flash Player 9 contains both AVM1 and AVM2, allowing the playing of SWFs created in all three versions of ActionScript.

The interoperability issues affecting applications using the Flash Player 9 arise in the situations where both AVM1 and AVM2 content are present. The following list describes the majority of the situations and the exceptions that are affected by this issue:

  • ActionScript 3.0–generated SWFs can load ActionScript 1.0 and 2.0 SWFs, but they cannot access any variables or methods on the loaded SWF.

    • For content created in Flash 8, you can use the ExternalInterface to communication between ActionScript 3.0 and ActionScript 2.0 SWFs.

    • For content created in Flash 8 or earlier, you can use the LocalConnection class to communicate between ActionScript 3.0 and ActionScript 2.0 SWFs.

  • SWFs generated for AVM1 cannot load AVM2 SWFs.

    • The only exception is when the AVM1 SWF replaces itself with an AVM2 SWF file. This is done by calling loadMovieNum() with a value of 0 for the level parameter.

Tip

Chapter 26 provides more information on ExternalInterface and walks you through example code using the ExternalInterface to communicate between AVM2 and AVM1 SWFs. The example is for the case of AVM2 loading AVM1 SWFs. You cannot load AVM2 SWFs inside an AVM1 SWF.


Getting Started with ActionScript

It is time to dive into the ActionScript code and explore the classes. This section rounds out with step-by-step instructions on how to build ActionScript applications with the Flex Builder and Flash authoring tool.

Tip

The Flash Professional 9 is currently available as a preview download off http://labs.adobe.com, and will be officially released in 2007. The steps in this chapter reflect the current Flash Professional 9 preview, but should work on the official release as well.

ActionScript 3.0 Is More than Flex

Why is ActionScript 3.0 more than Flex? That has to do with a large number of ActionScript 3.0 classes created specifically for the Flash Player. These classes are distinctly different from the Flex Framework. The following table lists the core documented classes found in the flash package of the ActionScript 3.0 language. The lists are separated by package names.

flash.accessibility.* | flash.display.* | flash.errors.* | flash.events.*
Accessibility | ActionScriptVersion | EOFError | ActivityEvent
AccessibilityProperties | AVM1Movie | IllegalOperationError | AsyncErrorEvent
 | Bitmap | InvalidSWFError | ContextMenuEvent
 | BitmapData | IOError | DataEvent
 | BitmapDataChannel | MemoryError | ErrorEvent
 | BlendMode | ScriptTimeoutError | Event
 | CapsStyle | StackOverflowError | EventDispatcher
 | DisplayObject |  | EventPhase
 | DisplayObjectContainer |  | FocusEvent
 | FrameLabel |  | FullScreenEvent
 | GradientType |  | HTTPStatusEvent
 | Graphics |  | IEventDispatcher
 | IBitmapDrawable |  | IMEEvent
 | InteractiveObject |  | IOErrorEvent
 | InterpolationMethod |  | KeyboardEvent
 | JointStyle |  | MouseEvent
 | LineScaleMode |  | NetStatusEvent
 | Loader |  | ProgressEvent
 | LoaderInfo |  | SecurityErrorEvent
 | MorphShape |  | StatusEvent
 | MovieClip |  | SyncEvent
 | PixelSnapping |  | TextEvent
 | Scene |  | TimerEvent
 | Shape |  |
 | SimpleButton |  |
 | SpreadMethod |  |
 | Sprite |  |
 | Stage |  |
 | StageAlign |  |
 | StageQuality |  |
 | StageScaleMode |  |
 | SWFVersion |  |
flash.external.* | flash.filters.* | flash.geom.* | flash.media.*
ExternalInterface | BevelFilter | ColorTransform | Camera
 | BitmapFilter | Matrix | ID3Info
 | BitmapFilterQuality | Point | Sound
 | BitmapFilterType | Rectangle | SoundChannel
 | BlurFilter | Transform | SoundLoaderContext
 | ColorMatrixFilter |  | SoundMixer
 | ConvolutionFilter |  | SoundTransform
 | DisplacementMapFilter |  | Video
 | DisplacementMapFilterMode |  |
 | DropShadowFilter |  |
 | GlowFilter |  |
 | GradientBevelFilter |  |
 | GradientGlowFilter |  |
flash.net.* | flash.printing.* | flash.profiler.* | flash.system.*
getClassByAlias() | PrintJob | showRedrawRegions() | fscommand()
navigateToURL() | PrintJobOptions |  | ApplicationDomain
registerClassAlias() | PrintJobOrientation |  | Capabilities
sendToURL() |  |  | IME
IDynamicPropertyOutput |  |  | IMEConversionMode
IDynamicPropertyWriter |  |  | LoaderContext
FileFilter |  |  | Security
FileReference |  |  | SecurityDomain
FileReferenceList |  |  | SecurityPanel
LocalConnection |  |  | System
NetConnection |  |  |
NetStream |  |  |
ObjectEncoding |  |  |
Responder |  |  |
SharedObject |  |  |
SharedObjectFlushStatus |  |  |
Socket |  |  |
URLLoader |  |  |
URLLoaderDataFormat |  |  |
URLRequest |  |  |
URLRequestHeader |  |  |
URLRequestMethod |  |  |
URLStream |  |  |
URLVariables |  |  |
XMLSocket |  |  |
flash.text.* | flash.ui.* | flash.utils.* | flash.xml.*
AntiAliasType | ContextMenu | clearInterval() | XMLDocument
CSMSettings | ContextMenuBuiltInItems | clearTimeout() | XMLNode
Font | ContextMenuItem | describeType() | XMLNodeType
FontStyle | Keyboard | escapeMultiByte() |
FontType | KeyLocation | getDefinitionByName() |
GridFitType | Mouse | getQualifiedClassName() |
StaticText |  | getQualifiedSuperclassName() |
StyleSheet |  | getTimer() |
TextColorType |  | setInterval() |
TextDisplayMode |  | setTimeout() |
TextField |  | unescapeMultiByte() |
TextFieldAutoSize |  | IDataInput |
TextFieldType |  | IDataOutput |
TextFormat |  | IExternalizable |
TextFormatAlign |  | ByteArray |
TextLineMetrics |  | Dictionary |
TextRenderer |  | Endian |
TextSnapshot |  | Proxy |
 |  | Timer |
Open table as spreadsheet

All classes starting with the flash package name, as shown here, are the core Flash Player classes. Along with the core classes, there are plenty of classes built with ActionScript located in the Flex Framework. These classes are used not only in Flex applications, but Flash applications as well. The Flex Framework builds on top of the core Flash Player classes to provide easy-to-use abstract components. For example, the mx.rpc.remoting.RemoteObject class is a Flex Framework ActionScript class that abstracts connecting to the RPC service by using the flash.net.NetConnection. Flash Professional 9 does not include the Flex Framework classes, but will include other custom components geared for Flash developers. When a Flex application is compiled, the classes of the Flex Framework referenced by the application are compiled into the SWF.

The main point to take out of this section is that ActionScript is the foundation language not only for Flex, but the Flash platform in general.

ActionScript 3.0 Coding Considerations

The ActionScript language can be used in many places. There are some common practices to help migrate, reuse, or port ActionScript 3.0 code from Flex to Flash, and vice versa. As of this writing, Flash Professional 9 has not yet been released, but the overall source code structure is the same. In the Flash authoring tool, there are several locations to place ActionScript code. You can put the ActionScript code in a frame, attached to an instance of an object, or in external .as files. Similarly, in Flex, you have options of placing ActionScript code inline or in external class files. Both inline code and usage of external ActionScript files are done by using the <mx:Script /> tag or the key word include.

Tip

If your external classes are generic enough, you could very possibly use the same ActionScript files for both Flex and Flash applications.

For both Flash and Flex applications, it is a good practice to store only one class per ActionScript file. With ActionScript 3.0, the name of the source file also must be the same name as the class defined within.

With every language, there are certain keywords that are either reserved and cannot be used, or that mean something in a specific context. The following lists both the reserved and special context keywords. It is good practice to not use these keywords in your code.

  • break

  • case

  • catch

  • class

  • const

  • continue

  • default

  • delete

  • do

  • dynamic

  • each

  • else

  • extends

  • false

  • final

  • finally

  • for

  • function

  • get

  • if

  • implements

  • import

  • in

  • include

  • instanceof

  • interface

  • internal

  • is

  • namespace

  • native

  • native

  • new

  • null

  • override

  • package

  • private

  • protected

  • public

  • return

  • set

  • static

  • super

  • switch

  • this

  • throw

  • to

  • true

  • try

  • typeof

  • use

  • var

  • void

  • while

  • with

Running ActionScript Applications

The ActionScript 3.0 code shown in Listing 16-1 defines a class called DrawShapes that draws a blue circle and a red square.

Listing 16-1: DrawShapes.as
Image from book

package {
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;

public class DrawShapes extends Sprite {
  private var childCount:int = 0;
  public function DrawShapes() {
    doDraw( 0x336699, "circle" );
    doDraw( 0x993333, "square" );
  }

  private function doDraw( color:uint, type:String ):void {
    var child:Shape = new Shape();
    child.graphics.beginFill( color );
    child.graphics.lineStyle( 2, 0xCCCCCC );
    if( type == "circle" )
      child.graphics.drawCircle( 30, 40, 30);
    if( type == "square" )
      child.graphics.drawRect( 10, 10, 60, 60 );
    child.graphics.endFill();
    child.x = (childCount * 65) + 10;
    child.y = 0;
    addChild(child);
    childCount++;
  }
}
}
Image from book

The following steps use the code in Listing 16-1 and demonstrate how to run the basic ActionScript application. These steps are similar to the ones found in Chapter 4, “Using Flex Builder 2.0.”

  1. Open Flex Builder and create a new ActionScript project called Chapter16.

  2. Rename the Chapter16.as file to the DrawShapes.as file that was generated by the new Flex project wizard.

  3. Open the DrawShapes.as file and copy the code from Listing 16-1 over any existing code in the file.

  4. Build the project and run the application.

To run this same application in the Flash authoring tool, follow these steps:

  1. Open Flash Professional 9 and create a new FLA file called Chapter16.

  2. Copy the DrawShapes.as file into the same folder as Chapter16.fla.

  3. Select the document class input field located in the Properties tab.

  4. Enter DrawShapes into the document class field.

  5. Publish the Flash document.

The difference between the Flex and Flash applications is in how you approach compiling the main application. The Flex application compiles the DrawShapes.as directly, but the Flash main application uses an FLA file with DrawShapes.as defined as the document class. It is also important to point out the file size difference. Even with this simple example, the Flex Builder–generated SWF is 4K, whereas the Flash Professional 9–generated SWF is only 1K. Figure 16-1 shows what the application should look like for both cases.

Image from book
Figure 16-1: How the application should look
Tip

Both the Flex and Flash project files and compiler settings use different default configurations. For instance, this example will have a white background when compiled in Flash Professional 9. You will also notice the stage align and scaling default values are different between Flex and Flash applications.

The ActionScript 3.0 language reference documentation provided by Adobe has many ActionScript code examples. Using the Flex steps outlined here, you now have a basic understanding of how to run the Adobe and other ActionScript code examples.


Display Programming

ActionScript 3.0 introduces a different concept and approach to working with objects living on the Flash Player stage. Along with the new class structure, new methods and classes have been created to program how the visual elements of an SWF application are organized and manipulated.

Understanding the Display Architecture

One of the major architectural changes in ActionScript 3.0 is the addition of non-timeline MovieClip-like class called the Sprite class. The Sprite class is the basic building block of display objects, under the assumption that most user interface components do not typically use a timeline. There is a bit that goes on structurally to get that Button on the screen, though.

Each ActionScript 3.0 application is a tree of objects that are displayed on the screen. The hierarchy of the objects is made up of DisplayObject classes and DisplayObjectContainer classes. The resulting object structure is called the display list. The DisplayObject defines methods and properties needed by leaf or parent objects on the display list. All classes that can be placed on the display list extend the DisplayObject class.

The DisplayObjectContainer is the base class for objects that can contain other objects on the display list. The Sprite class inherits from DisplayObjectContainer and provides the most basic needs of the application component display structure. Not all display objects on the tree need to have children (for example, the Shape class or the TextField class). Both the Shape and TextField class extend the DisplayObject class and not the DisplayObjectContainer.

Tip

The Sprite, DisplayObject, and DisplayObjectContainer are located in the flash.display.* package.

When using the mxmlc to create ActionScript 3.0 applications, the resulting SWF has a display list built from two basic blocks: a stage object and a main class. The stage is the root of the display list. The main class file’s constructor is called and an instance is added to the stage. All display objects and display containers then are attached to the main class’s instance, as shown in Figure 16-2.

Image from book
Figure 16-2: Display list object instantiation tree

The change of Flash Player using a display list has the following advantages:

  • Efficient rendering and memory usage - Prior to ActionScript 3.0, all objects used the MovieClip object, regardless of whether they needed all of the methods and properties of the MovieClip. For example, displaying an image on the screen does not require a timeline.

  • Depth management - Prior to ActionScript 3.0, all objects shared the same depth relationship to the stage. The linear depth relationship to the stage was counter-intuitive to the parent-child structure of nested MovieClips. ActionScript now handles the depth management automatically based on the display list. The first objects on the display list have precedence and so forth; now you only have to worry about the ordering of child objects along the display list.

  • Full access to visual elements - Each object is now available in a very fast index lookup. In an earlier ActionScript version, it was possible to have some elements such as a vector shape drawn by the Flash authoring tool inaccessible by ActionScript.

  • Nonvisual display objects - ActionScript 3.0 provides the class structure to allow for complex display object containers to use nonvisual display objects.

  • Extensibility from the start - With all the class changes, one major functional requirement adhered to was to make it easy to subclass the display objects. The core classes and Flex Framework are the fruits of this advantage. The classes cover the basic display object needs from Bitmap and Shape to containers that are used to build out the DataGrid and Panel classes.

The DisplayObject is the base of all the user interface components. The following table briefly describes the core display classes that are used to create examples in the following sections.

Open table as spreadsheet
Class | Description
Bitmap | Handles bitmap objects. ActionScript 3.0 allows for the following bitmaps to be loaded externally by using the Loader class: GIF, JPG, and PNG. The bitmap class can also be used in conjunction with the BitmapData class to manipulate images. Some of the current uses include taking pictures from a Web cam, reading bar codes from a Web cam, thumbnail application components, and many other image-related ideas.
Loader | Used to load external assets, including SWFs and images.
Shape | This object is the canvas for vector graphics.
SimpleButton | The base for most buttons in the Flex Framework. It defines three states: up, over, and down.
MovieClip | The Sprite class with an added timeline.
TextField | Found in the flash.text package, this class is the display object that handles user input and displaying text.
Video | Found in the flash.media package, all video-related functionality must use the Video class to render the media onscreen.

Working with Display Objects

A good place to start to explain how to work with display objects is to look at the DisplayObject class. Because all other objects on the display use the DisplayObject, it is important to become familiar with the methods and properties defined by the class. The functionality of both the DisplayObject and DisplayObjectContainer classes can be broken up into four loosely defined categories:

  • Manipulation of display list structure - This entails the methods and properties used to add, remove, and move display objects around the display list.

  • Appearance and spatial properties - The DisplayObject class defines a number of properties for placement, size, and other appearance-related functionality.

  • Finding display objects - There are methods relating to retrieving display objects off the display list by name, or by index, up and down the parent and child display list structure.

  • Event handling - The EventDispatcher class is inherited by all the classes to provide all display objects with access to the event model.

Manipulating the Display List

The following table shows the methods and properties that fall under this category, and are exclusive to the DisplayObjectContainer class.

Open table as spreadsheet
Method | Description
addChild() | Adds the display object to the container class, either at the end of the container’s child list or inserted at a specific index.
AddChildAt() |
removeChild() | Removes the display object from the container class, either by providing a reference to the child display object or a specific index.
removeChildAt() |
setChildIndex() | This method is used to change the index in the children list of the provided display object.
swapChildren() | Another method of changing the position of children in the container’s specific display list. The swapping can be done with two display objects or two index values.
swapChildrenAt() |

Appearance and Spatial Properties

The following table shows the methods and properties that fall under this category, and are defined in both the DisplayObject and the DisplayObjectContainer classes.

Open table as spreadsheet
Method/Property | Description
accessibilityProperties | These properties provide functionality to specific Flash Player information and capabilities. There will always be a root stage object that can be referenced here. The loaderInfo is specific to loading external resources and provides low-level information. The accessibility and cache of bitmaps are features specific to the Flash Player.
cacheAsBitmap |
LoaderInfo |
Stage |
Alpha | This group of properties covers the basic appearance features available in the Flash Player. These are some of the most powerful properties when it comes to creating custom, visually appealing components. See the Adobe documentation to learn more the specific uses of each of these properties.
BlendMode |
Filters |
Mask |
opaqueBackground |
scale9Grid |
Transform |
Visible |
Height | This group of properties defines the specific spatial characteristics of the display object. This is the basic of positioning of all display objects.
Width |
Rotation |
ScaleX |
ScaleY |
X |
Y |
ScrollRect | These methods and properties are used to retrieve rectangles that define specific bounds of the display object.
getBounds() |
GetRect() |
hitTestObject() | Determines if the specific objects intersect spatially onscreen.
hitTestPoint() |
MouseX | These methods and properties relate to specific points in pixels on the screen. Using the mouseX and mouseY values, you can move between the stage’s Point and the Point specific to the display object.
MouseY |
globalToLocal() |
localToGlobal() |

Finding Display Objects

The following table shows the methods and properties that fall under this category, and are defined in both the DisplayObject and the DisplayObjectContainer classes.

Open table as spreadsheet
Method | Description
Name | These properties define who the display object is, and also specify the relationship references to other display objects located in the display list.
Parent |
Root |
contains() | Determines if the display object is present in this container.
GetChildAt() | The get functions provide methods to retrieve the index to a display object or the objects themselves. The display objects can be retrieved by index, name, or using a Point class.
getChildByName() |
getChildIndex() |
getObjectsUnderPoint() |

Event Handling

The following table shows the methods and properties that fall under this category, and are defined in both the DisplayObject and the DisplayObjectContainer classes.

Open table as spreadsheet
Method | Description
Activate | These events are fired when the Flash Player gains and loses focus from the operating system.
deactivate |
Added | These events fire when each display object is added or removed from a display container.
Removed |
enterFrame | These two methods are events that relate to the execution cycle of the Flash Player.
Render |
Click | This long list defines all the events caused by client interaction with the application. Either through mouse or keyboard the events handle all the typical display objects’ interaction states.
doubleClick |
FocusIn |
FocusOut |
KeyDown |
keyFocusChange |
KeyUp |
mouseDown |
mouseFocusChange |
mouseMove |
MouseOut |
mouseOver |
MouseUp |
mouseWheel |
rollout |
rollover |
tabChildrenChange |
tabEnabledChange |
tabIndexChange |

Using the Core Display Classes

This section covers the usage of the core display classes through a series of code examples. Each example can be run as a stand-alone ActionScript 3.0 application, as outlined earlier in the chapter.

Following is an example of the Bitmap class that takes an image (URL provided in code) and creates a color-inverted copy. Figure 16-3 shows the result.

Image from book
Figure 16-3: Bitmap map class taking an image and creating a color-inverted copy

package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.filters.ColorMatrixFilter;

public class BitmapExample extends Sprite
{
  // Logo from http://media.wiley.com/assets/253/59/wrox_logo.gif
  [Embed(source="assets/wrox_logo.gif")]
  private var image:Class;

  public function BitmapExample() {
    if( stage != null ) {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    var filters:Array = new Array();

    var matrix:Array = new Array();
    matrix = matrix.concat( [-1, 0, 0, 0, 256] ); // red
    matrix = matrix.concat( [0, -1, 0, 0, 256] ); // green
    matrix = matrix.concat( [0, 0, -1, 0, 256] ); // blue
    matrix = matrix.concat( [0, 0, 0, 1, 0] ); // alpha

    var filter:ColorMatrixFilter = new ColorMatrixFilter( matrix );
    filters.push( filter );

    var myBitmap:Bitmap = new logoClass();
    addChild( myBitmap );

    var myBitmap2:Bitmap = new logoClass();
    myBitmap2.filters = filters;
    myBitmap2.y = myBitmap.height + 20;
    addChild( myBitmap2 );
  }
}
}

The next example uses the Loader and Shape class to load the same image used in the previous example and apply a mask so that only the Wrox logo shows. Figure 16-4 shows the result.

Image from book
Figure 16-4: Loading the same image and applying a mask so that only the Wrox logo shows

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Shape;
import flash.display.Loader;
import flash.net.URLRequest;

public class LoaderShapeExample extends Sprite
{
  public function LoaderShapeExample() {
    if( stage != null ) {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    var maskRect:Shape = new Shape();
    maskRect.graphics.beginFill( 0xFFFFFF );
    maskRect.graphics.drawRect( 10, 10, 71, 71 );
    maskRect.graphics.endFill();
    addChild( maskRect );

    var logoLoader:Loader = new Loader();
    logoLoader.mask = maskRect;
    var url:String = "http://media.wiley.com/assets/253/59/wrox_logo.gif";
    var urlReq:URLRequest = new URLRequest( url );
    logoLoader.load( urlReq );
    addChild( logoLoader );
  }
}
}

The next example builds on the Bitmap class example. This example uses the two bitmap objects from the Bitmap example to create a simple rollover image button by using the SimpleButton class.

package
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.filters.ColorMatrixFilter;
import flash.display.SimpleButton;

public class BitmapButtonExample extends Sprite
{
  // Logo from http://media.wiley.com/assets/253/59/wrox_logo.gif
  [Embed(source="assets/wrox_logo.gif")]
  private var logoClass:Class;

  public function BitmapButtonExample() {
    if( stage != null ) {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    var myButton:SimpleButton = new SimpleButton();

    var filters:Array = new Array();

    var matrix:Array = new Array();
    matrix = matrix.concat( [-1, 0, 0, 0, 256] ); // red
    matrix = matrix.concat( [0, -1, 0, 0, 256] ); // green
    matrix = matrix.concat( [0, 0, -1, 0, 256] ); // blue
    matrix = matrix.concat( [0, 0, 0, 1, 0] ); // alpha

    var filter:ColorMatrixFilter = new ColorMatrixFilter( matrix );
    filters.push( filter );

    var myBitmap:Bitmap = new logoClass();

    var myBitmap2:Bitmap = new logoClass();
    myBitmap2.filters = filters;

    myButton.upState = myBitmap;
    myButton.overState = myBitmap2;
    myButton.downState = myBitmap2;
    myButton.useHandCursor = true;
    myButton.hitTestState = myBitmap;

    addChild( myButton );
  }
}
}

The Multiple1Example example uses an SWF generated in Flash Professional 9 with three frames. The frames contain the numbers 1, 2, and 3, along with stop() ActionScript code and vector background graphics. The SWF is loaded by the Loader class and the SimpleButton’s mouseDown event-handler function tells the Multiple1Example to move to the next frame by calling the play() method. You can see the three frames of the SWF in Figure 16-5.

Image from book
Figure 16-5: Resulting three frames of the SWF

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Shape;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.display.MovieClip;

public class Multiple1Example extends Sprite
{
  private var countingSWF:Loader;

  public function Multiple1Example() {
    if( stage != null ) {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    var maskRect:Shape = new Shape();
    maskRect.graphics.beginFill( 0xFFFFFF );
    maskRect.graphics.drawRect( 0, 0, 40, 40 );
    maskRect.graphics.endFill();
    addChild( maskRect );

    countingSWF = new Loader();
    countingSWF.mask = maskRect;
    var url:String = "http://localhost/assets/ch16_counting.swf";
    var urlReq:URLRequest = new URLRequest( url );
    countingSWF.load( urlReq );
    addChild( countingSWF );

    var overSprite:Sprite = new Sprite();
    overSprite.graphics.lineStyle(2, 0x333333);
    overSprite.graphics.beginFill(0x336699);
    overSprite.graphics.drawRect(0, 0, 20, 20);

    var upSprite:Sprite = new Sprite();
    upSprite.graphics.lineStyle(2, 0x333333);
    upSprite.graphics.beginFill(0x993333);
    upSprite.graphics.drawRect(0, 0, 20, 20);

    var myButton:SimpleButton = new SimpleButton();

    myButton.upState = upSprite;
    myButton.overState = overSprite;
    myButton.downState = overSprite;
    myButton.useHandCursor = true;
    myButton.hitTestState = upSprite;
    myButton.x = 10;
    myButton.y = 50;

    myButton.addEventListener( MouseEvent.MOUSE_DOWN, countingHandler );

    addChild( myButton );
  }

  private function countingHandler( event:MouseEvent ):void
  {
    MovieClip( countingSWF.content ).play();
  }
}
}

The next example uses the TextField class to display the status of an FLV stream that is being loaded into a video object. Figure 16-6 shows the result.

Image from book
Figure 16-6: Using the TextField class to display the status of an FLV stream

package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.media.Video;

public class VideoAndTextFieldExample extends Sprite
{
  // FLV provided with sample code, or use a local flv
  private var videoURL:String = "assets/barsandtone.flv";
  private var videoStatus:TextField;
  private var nc:NetConnection;
  private var ns:NetStream;

  public function VideoAndTextFieldExample() {
    if( stage != null ) {
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
    }

    videoStatus = new TextField();
    videoStatus.autoSize = TextFieldAutoSize.LEFT;
    videoStatus.text = "Ready to connect!";
    videoStatus.y = 260;
    addChild( videoStatus );

    nc = new NetConnection();
    nc.addEventListener( NetStatusEvent.NET_STATUS, netStatusHandler );
    nc.connect( null );
  }

  private function netStatusHandler( event:NetStatusEvent ):void
  {
    switch (event.info.code) {
      case "NetConnection.Connect.Success":
          ns = new NetStream( nc );
          ns.client = this;
          var video:Video = new Video();
          video.attachNetStream( ns );
          ns.play( videoURL );
          addChild(video);
          videoStatus.text = "Connection Success";
          break;
      default:
          videoStatus.text = event.info.code;
      break;
    }
  }

  public function onMetaData( info:Object ):void
  {
    ;//
  }
}
}


Summary

This chapter covered a broad overview of ActionScript programming. ActionScript 3.0 is a new language and, along with a new Flash Player 9, there is quite a bit to learn from the core ActionScript classes. The chapter explained the steps to compile multiple AS 3.0 examples in Flex Builder and the Flash Professional 9 authoring tool.

Chapter 17 discusses the data types and basic classes that make up the ActionScript language. The data types and basic classes are the basic building blocks of the ActionScript language.


Chapter 17: Data Types and Classes

Overview

The basic building blocks of the ActionScript 3.0 language are comprised of primitive and complex data types. Each data type serves the purpose of letting the developer know what values or sets of values are, and how they act.

In this chapter’s examination of data types and classes, you learn about the following:

  • Value types

  • Dates and times

  • Strings

  • Arrays

  • Error handling

  • Regular expressions

  • XML


Value Types

There are two value types in ActionScript 3.0: primitive and complex. It’s worth noting a slight difference between primitive and complex in ActionScript 3.0 and other programming languages. In ActionScript 3.0, both primitive and complex value types behave like objects. The difference is that the Flash Player treats primitive value types differently and optimizes data access. For example, the primitive type unit memory allocation is the same for the following two lines of code:

var myColor:uint = 0x336699FF;
var myColor:uint = new uint( 0x336699FF );

The first method defines the value using a literal value and the second method uses the new operator to create the value. The way Flash Player handles the memory allocation and memory access for primitive types makes it so that there is no object creation overhead for the second line of code.

Primitive Data Types

There are seven primitive types in ActionScript 3.0: int, uint, Number, Boolean, String, Null, and void. It is important to understand the difference between each primitive type value range to better understand performance and usage. The first three primitive types are for numbers and each serve a different purpose. The int uses 32 bits to represent a signed integer, allowing for values in the range of –2,147,483,648 (–231) to 2,147,483,647 (231–1). The uint uses 32 bits to represent an unsigned integer, allowing for values in the range of 0 to 4,294,967,295 (232–1). The default value for both int and uint is 0. The Number type uses up to 53 bits to represent integer values allowing for full IEEE-754 double-precision floating-point values. The default value for Number is NaN (not a number). Following are some examples:

var myInt:int = int.MAX_VALUE;  // 2,147,483,647
var myUint:unit = 4000000;
var myNumber:Number = 123.98;

The Boolean data type can have one of two values: true or false. This type is used mostly for logical operations. The default value for Boolean is false.

var myBool:Boolean = true;

The String data type is defined by a series of 16-bit characters. The actual values of the characters conform to the Unicode character set, using the UTF-16 format. The String data type provides the basis for text manipulation and display. The default value for String is null.

var myFirstWord:String = "Hello World!";

The Null and void data types are two special cases. The Null data type has only one value, which is null. It serves as the default value for String and all other complex data types. The void data type is used in method return declarations. The void data type also has only one value, which is undefined.

private function doNothing():void {}
myFirstWord = null;

In ActionScript 3.0, a change to undefined’s meaning is important to point out. If you try to assign undefined to a variable that has a data type, it will be converted to the default value of that specific type.

Complex Data Types

The list of complex types defined in the core ActionScript 3.0 classes is Date, Array, Error, Function, RegExp, XML, and XMLList. Any custom component or class created is considered a complex data type. The following sections discuss in more depth how to use the core complex types, as well as the wrapper class for the String data type.


Dates and Times

The Date class enables the developer to manage calendar date and time values. The Date class contains methods and variables to create date values in either time-zone–specific or Coordinated Universal Time (UTC) formats. Creating, retrieving, and manipulating date and time values from a Date object are the areas explored here.

Creating Calendar Dates and Times

The Date class’s constructor is overloaded to provide four different methods of creating dates. The four ways to create Date objects are as follows:

// 1. Gets current date
var currentDate:Date = new Date();
// 2. Sets date to for X amount milliseconds since Jan 1 1970
var milliseconds:Number = 12 * 365 * 24 * 60 * 60 * 1002;
var customDate1:Date = new Date( milliseconds );
// 3. Set year, month, day, hour, minutes and seconds
var customDate2:Date = new Date( 1982, 0, 6, 10, 14, 24 );
// 4. Set date and time through a string value
var customDate3:Date = new Date( "Wed Jan 6 10:14:24 GMT-0800 1982" ) );
var customDate4:Date = new Date( "Jan 6 1982 10:14:24" ) );
var customDate5:Date = new Date( "1982/01/06 10:14:24" ) );

All four methods provide flexibility in creating dates, be it from a database or creating your own date from scratch. You can also parse a date at any time by calling customDate.parse( "2006/11/02" ). It is also good to note that in the case of the third method of creating date objects, the month value is zero-based. The best way to explore these creation methods is to see the results. Listing 17-1 shows a simple mini-application to view dates.

Listing 17-1: Methods of Creating Dates
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="vertical"
  creationComplete="getDates();">
  <mx:Script>
    <![CDATA[
    private function getDates():void
    {
      var dates:Array = new Array();
      dates.push( new Date() );
      var millSecs:Number = 12 * 365 * 24 * 60 * 60 * 1002;
      dates.push( new Date( millSecs ) );
      dates.push( new Date( 1982, 0, 6, 10, 14, 24 ) );
      dates.push( new Date( "Wed Jan 6 10:14:24 GMT-0800 1982" ) );
      dates.push( new Date( "Jan 6 1982 10:14:24" ) );
      dates.push( new Date( "1982/01/06 10:14:24" ) );

      txtDates.text += "#### ToString() ####";
      for( var a:String in dates )
        txtDates.text += "\n" + dates[ a ].toString();
      txtDates.text += "\n\n#### ToDateString() ####";
      for( var b:String in dates )
        txtDates.text += "\n" + dates[ b ].toDateString();
      txtDates.text += "\n\n#### ToLocaleString()";
      for( var c:String in dates )
        txtDates.text += "\n" + dates[ c ].toLocaleString();
      txtDates.text += "\n\n#### ToUTCString() ####";
      for( var d:String in dates )
        txtDates.text += "\n" + dates[ d ].toUTCString();
      var df:DateFormatter = new DateFormatter();
      df.formatString = "year: YYYY / month: MM / day: DD";
      txtDates.text += "\n\n#### Custom Output ####";
      for( var e:String in dates )
        txtDates.text += "\n" + df.format( dates[ e ] );
      }
    ]]>
  </mx:Script>
  <mx:TextArea
      width="80%" height="80%"
      id="txtDates">
  </mx:TextArea>
</mx:Application>
Image from book

Methods of displaying the date values include the display methods just shown, as well as toString(), toDateString(), toLocaleDateString(), toLocaleString(), toLocaleTimeString(), toTime STring(), and toUTCString(). It is also possible to create custom-formatted display dates through the DateFormatter class, as shown previously.

Retrieving Time Values by Unit

Each date is made up of a set of units: fullYear, month, day, date, hours, minutes, seconds, milli seconds, and time. The difference between day and date is that day property provides the day of the week, and date is the numeric value of the day of the month. The time property provides the number of milliseconds since January 1, 1970, midnight and zero GMT. There is also a property called timezone Offset to provide the difference in minutes between the computer’s local time and the time value. The fullYear property uses all four digits to define the value. Therefore, a value of 6 is not 2006, but the year 6. The unit’s day and month are zero-based, and day of the week starts with Sunday.

By default, the unit values of the Date object are given in local time, which is UTC time plus the time-zone offset. Most properties and methods that give the developer access to the Date object have complementary xxxxUTC assessors. This is important to note, because when you create a date from milliseconds, you will need to take into account the time zone of the local time when trying to create dates in UTC time.

To access the specific unit values of a Date object, you can use properties or methods defined in the Date class. No method is faster than the other, as the following code shows:

var d:Date = new Date();
var pDate:String = d.fullYear + "/" + d.month + "/" + d.date;
var mDate:String = d.getFullYear() + "/" + d.getMonth() + "/" + d.getDate();
var pUTCDate:String = d.fullYearUTC + "/" + d.monthUTC + "/" + d.dateUTC;
var mUTCDate:String = d.getFullYearUTC() + "/" + d.getMonthUTC() + "/" + d.getDateUTC();

The various ways of accessing the date and time unit values allow you to use the method that fits your application the best.

Date Manipulation

Time is constant, but in application development, most specifications require functionality to change time. Most often developers need to manipulate date values by adding, subtracting, or comparing dates. Listing 17-2 creates a Calendar class that provides a single method implementing date and time arithmetic. You can see that the Calendar class takes a Date object and adds year, month, date, hour, minute, or second type values to the date.

Listing 17-2: Calendar Class
Image from book

package
{

public class Calendar
{
  public static var YEAR:int = 1;
  public static var MONTH:int = 2;
  public static var DATE:int = 3;
  public static var HOUR:int = 4;
  public static var MINUTE:int = 5;
  public static var SECOND:int = 6;

  private var date:Date;

  public function Calendar( date:Date = null )
  {
    if( date != null )
      this.date = date;
    else
      this.date = new Date();
  }

  public function add( type:int, delta:int ):Date
  {
    switch( type ) {
      case Calendar.YEAR:
        date.setFullYear( date.fullYear + delta, date.month, date.date );
      break;
      case Calendar.MONTH:
        date.setMonth( date.month + delta, date.date );
      break;
      case Calendar.DATE:
        date.setDate( date.date + delta );
      break;
      case Calendar.HOUR:
        date.setHours( date.hours + delta, date.minutes, date.seconds,
date.milliseconds );
      break;
      case Calendar.MINUTE:
        date.setMinutes( date.minutes + delta, date.seconds, date.milliseconds );
      break;
      case Calendar.SECOND:
        date.setSeconds( date.seconds + delta, date.milliseconds );
      break;
    }
    return date;
  }
}

}
Image from book

By adding some code to Listing 17-2, you can see how the Calendar class provides easy-to-use date manipulation capabilities. The following example uses the current date, then runs through all the different unit types, and adds five to the current value:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="vertical"
  creationComplete="getDates();">
  <mx:Script>
    <![CDATA[
    private function getDates():void
    {
      var dates:Array = new Array();
      dates.push( new Date() );
      var millSecs:Number = 12 * 365 * 24 * 60 * 60 * 1002;
      dates.push( new Date( millSecs ) );
      dates.push( new Date( 1982, 0, 6, 10, 14, 24 ) );
      dates.push( new Date( "Wed Jan 6 10:14:24 GMT-0800 1982" ) );
      dates.push( new Date( "Jan 6 1982 10:14:24" ) );
      dates.push( new Date( "1982/01/06 10:14:24" ) );

      var cal:Calendar = new Calendar();
      dates.push( cal.add( Calendar.YEAR, 5 ) );
      var cal2:Calendar = new Calendar( new Date() );
      dates.push( cal2.add( Calendar.MONTH, 5 ) );
      var cal3:Calendar = new Calendar( new Date() );
      dates.push( cal3.add( Calendar.DATE, 5 ) );
      var cal4:Calendar = new Calendar( new Date() );
      dates.push( cal4.add( Calendar.HOUR, 5 ) );
      var cal5:Calendar = new Calendar( new Date() );
      dates.push( cal5.add( Calendar.MINUTE, 5 ) );
      var cal6:Calendar = new Calendar( new Date() );
      dates.push( cal6.add( Calendar.SECOND, 5 ) );

      txtDates.text += "#### ToString() ####";
      for( var a:String in dates )
        txtDates.text += "\n" + dates[ a ].toString();
      txtDates.text += "\n\n#### ToDateString() ####";
      for( var b:String in dates )
        txtDates.text += "\n" + dates[ b ].toDateString();
      txtDates.text += "\n\n#### ToLocaleString()";
      for( var c:String in dates )
        txtDates.text += "\n" + dates[ c ].toLocaleString();
      txtDates.text += "\n\n#### ToUTCString() ####";
      for( var d:String in dates )
        txtDates.text += "\n" + dates[ d ].toUTCString();
      var df:DateFormatter = new DateFormatter();
      df.formatString = "year: YYYY / month: MM / day: DD";
        txtDates.text += "\n\n#### Custom Output ####";
      for( var e:String in dates )
        txtDates.text += "\n" + df.format( dates[ e ] );
      }
    ]]>
  </mx:Script>
  <mx:TextArea
      width="80%" height="80%"
      id="txtDates">
  </mx:TextArea>
</mx:Application>


Strings

The String class is used throughout the Flex Framework. Understanding how to handle and manipulate string values is important.

Length Property

To obtain the length of a string, you call the length property of the String class:

var str:String = "Professional Flex 2";
trace("String Length: " + str.length );  // outputs: String Length: 19
var str2:String;
trace("String Length: " + str2.length );  // throws error (Error #1009)

If you try to call the length property on a String that has the default value of null, it will throw an error. How to handle errors is discussed later in this chapter.

Characters in Strings

The String class provides three functions related to actual characters in a string. The first two retrieve character code or string values from anywhere within a string. Both methods use a zero-based index parameter to retrieve the character value:

var str:String = "Professional Flex 2";
trace("Character: " + str.charAt( 13 ) );  // outputs: Character: F
trace("Char Code: " + str.charChodeAt( 13 ) );  // outputs: Char Code: 70

The next character-related function in the String class is a static function for creating a string from a list of character values:

var str:String = String.fromCharCode(70,108,101,120,32,50 );
trace("Value: " + str );  // outputs: Value: Flex 2

String Comparison

The comparison operators defined in ActionScript 3.0 are ==, >, >=, !=, <, <=, ===, and !==. These operators are used when comparing strings. The rules that ActionScript uses to compare strings dictate comparing characters from left to right, and using the character code value.

trace("Flex" < "flex" ); // true
trace("Professional" < "Flex" ); // false
trace( "Professional" < "flex" ); // true
trace( "flex" < "flexible" ); // true

Specific to the equality operators is the distinction between strict equality and nonstrict. The strict operators check type, as well as value.

var str:String = "2";
var num:* = 2;
trace( "T/F: " + (str == num) ); // outputs: T/F: true
trace( "T/F: " + (str === num) ); // outputs: T/F: false

The String class also provides a method to compare strings, called localeCompare(). This method returns zero, a negative number, or a positive number, depending on where the original string falls in the list order. The return value represents the character code value difference between the two characters that determine the comparison. For example, the following string comparison is determined by the second character:

var str:String = "flex";
trace( "Value: " + str.localeCompare( "fLex" ) ); // outputs: Value: 32
var str2:String = "fLex";
trace( "Value: " + str2.localeCompare( "flex" ) ); // outputs: Value: -32

Obtaining String Representations of Objects

Every class extends the Object class, and the Object class provides a common function called toString(). The toString() method returns a string representation of the specific object it is called on. When using the + concatenation operator to build a string from non-String objects, toString() is automatically called. Each object can implement the toString() method specific to its class. For example, the Date class will return a date in the format “Day Mon Date HH:MM:SS TZD YYYY.”

var num:Number = "45.23";
trace( "Value: " + num ); // outputs: Value: 45.23
var date:Date = new Date( 2006, 5, 6, 12, 12, 12 );
trace( "Value: " + date ); // outputs: Value: Tue Jun 6 12:12:12 GMT+0000 2006

Concatenation

Combining strings is called concatenation. Strings can be combined with the + concatenation operator, the += concatenation assignment operator, or using the concat() method on the String class.

var str1:String = "Professional";
var str2:String = "Flex 2";
trace( str1 + " Flex " + 2 ); // outputs: Professional Flex 2
var newStr:String = str1;
newStr += " ";
newStr += str2;
trace( newStr ); // outputs: Professional Flex 2
newStr = str1.concat( " ", "Flex", " ", 2 );
trace( newStr ); // outputs: Professional Flex 2

As seen here, the concatenation process will automatically convert nonstring objects to a string representation, and then combine the strings.

Patterns and Substrings

The String class provides nine methods to determine patterns and substrings within a string. To examine them further, the methods are discussed in four sections:

  • Finding character positions

  • Substring by character position

  • Substrings by delimiter

  • Finding patterns

Finding Character Positions

This section consists of the String class’s indexOf() and lastIndexOf() methods. Both methods take two parameters: a string to search for and the starting index to start from. The search string can be a valid string of any length.

var str:String = "Professional Flex 2 is a great Flex resource.";
trace( "Index: " + str.indexOf( "Flex" ) ); // outputs: Index: 13
trace( "Index: " + str.lastIndexOf( "Flex" ) ); // outputs: Index: 31

Substring by Character Position

The slice(), substr(), and substring() methods provide the same results but differ in how to obtain the substring. The slice() method differs from the other two methods because it can take negative values for its parameters. Like substring(), the slice() method’s parameters are the start and end indexes of the substring you want to obtain. The substr() method uses the first parameter as the start index, and the second parameter as the length of the string you want to return.

var str:String = "Professional Flex 2 is a great Flex resource.";
var index1:int = str.indexOf( "Flex" );
var index2:int = str.lastIndexOf( "Flex" );

var newStr:String = str.substr( index1, index2 - index1 - 1 ) + "!";
trace( "Value:" + newStr ); // outputs: Value: Flex 2 is great!
newStr = str.substring( index1, index2 - 1 ) + "!";
trace( "Value: " + newStr ); // outputs: Value: Flex 2 is great!

newStr = str.slice( index1 - str.length, index2 - str.length - 1 ) + "!";
trace( "Value: " + newStr ); // outputs: Value: Flex 2 is great!

Substrings by Delimiter

This section and the next allow for a search value to be any type of object value. Usually, the value will be a string or a regular expression. Regular expressions are covered later in this chapter. The following code examples use a string value object when searching for patterns.

The split() method uses a delimiter value to return an array of substrings. The split() method is similar to the methods covered in the next section, “Finding Patterns,” because it finds a pattern in a string. The difference is that split() returns an array of substrings that are not the pattern, instead of returning values that match the search pattern. The first parameter of the method is the value of the delimiter, and the second parameter defines how many matches the method will return in the array of strings.

var str:String = "Professional Flex 2 is a great Flex resource.";
var strings:Array = str.split( "Flex" );
     // ["Professional ", " 2 is a great ", " resource"]

Finding Patterns

The three methods that make up this section are match(), search(), and replace(). The first two methods use the same type of parameter: a pattern of any type of object. The match() method returns an array of substrings that match the pattern. The search() method returns the index of the first match, and restricts some functionality of regular expression search value. The replace() method returns a new string with the replace object value in place of the pattern matches found in the string. replace is very powerful when used in conjunction with regular expression search parameters.

var str:String = "Professional Flex 2 is a great Flex resource.";
var pattern:RegExp = /F[a-z]+/g;  // Find all words that start with capital F
var strings:Array = str.match( pattern );
     // ["Flex", "Flex"]

var pattern:RegExp = /F[a-z]+/g;  // Find all words that start with capital F
var num:int = str.search( pattern );
trace( "Value: " + num ); // outputs: Value: 13

var pattern:RegExp = /F[a-z]+/g;  // Find all words that start with capital F
var newStr:String = str.replace( pattern, "xelF" );
trace( newStr ); // outputs: Professional xelF 2 is a great xelF resource.

Uppercase and Lowercase Conversion

A strings’ case type is manipulated by toLowerCase() and toUpperCase() methods:

var str:String = "Professional Flex 2";
trace( str.toUpperCase() ); // outputs: PROFESSIONAL FLEX 2
trace( str.toLowerCase() ); // outputs: professional flex 2


Arrays

There are a few points to consider before discussing arrays. First, the term “array” when talking about indexed, associative, or multidimensional arrays takes on the broader definition of a single data structure that allows for storage of multiple values. Second, the Array class implements a specific array that has constraints of using a numeric index when storing the multiple data values. Lastly, the issues of making copies of arrays is touched on.

Index Arrays

This type of array is the basis for the Flex 2 Array class. Values are stored in relationship to an unsigned integer, where the values can be of any type. The Array class provides methods to add, remove, sort, and find values in the array.

Creating Indexed Arrays

There are multiple methods of creating indexed arrays. The first is through the Array class’s constructor. Another method is to create a literal array with the square bracket identifiers. Next, you can assign the value directly to a specific index. The last method shown here uses the Array class’s push method to add the items after the array has been created.

var date1:Date = new Date();
var date2:Date = new Date( 2002, 1, 2, 12, 12, 12 );
var date3:Date = new Date( "Wed Apr 4 4:04:00 GMT-0800 2004" );

var dates:Array = new Array( date1, date2, date3 );
var dates2:Array = [date1, date2, date3];

var dates3:Array = new Array();
dates3[ 0 ] = date1;
dates3[ 1 ] = date2;
dates3[ 2 ] = date3;

var dates4:Array = new Array();
dates4.push( date1 );
dates4.push( date2 );
dates4.push( date3 );

Adding and Removing Items

There are three methods for adding and removing items from an array. The Array class provides the methods push(), unshift(), and splice() to add items to an array. Similarly, the pop(), shift(), and splice() methods implement the remove item functionality. The first methods for both add and remove are the common pop and push methods that add and remove items off the top of the array. The top is defined by the highest numeric value index and can change depending on how you assign items.

var date1:Date = new Date();
var date2:Date = new Date( 2002, 1, 2, 12, 12, 12 );
var date3:Date = new Date( "Wed Apr 4 4:04:00 GMT-0800 2004" );

var dates:Array = new Array();
dates.push( date1 );
dates.push( date2 );

trace( "Value: " + dates.pop() + " length: " + dates.length );
     // outputs: Value: Sat Feb 2 12:12:12 GMT-0800 2002 length: 1

dates[ 99 ] = date2;
dates.push( date3 );

trace( "Value: " + dates.pop() + " length: " + dates.length );
     // outputs: Value: Sun Apr 4 05:04:00 GMT-0700 2004 length: 100
trace( "Value: " + dates.pop() + " length: " + dates.length );
     // outputs: Value: Sat Feb 2 12:12:12 GMT-0800 2002 length: 99
trace( "Value: " + dates.pop() + " length: " + dates.length );
     // outputs: Value: undefined length: 98

To add and remove items at the bottom (or beginning) of an array, you use unshift() and shift():

var items:Array = new Array();
items.unshift( "item1" );
items.unshift( "item2" );

trace( "Value: " + items.shift() + " length: " + items.length );
     // outputs: Value: item2 length: 1

items[ 99 ] = "item99";
items.unshift( "item3" );

trace( "Value: " + items.shift() + " length: " + items.length );
     // outputs: Value: item3 length: 100
trace( "Value: " + items.shift() + " length: " + items.length );
     // outputs: Value: item1 length: 99
trace( "Value: " + items.shift() + " length: " + items.length );
     // outputs: Value: undefined length: 98
trace( "Value: " + items.pop() + " length: " + items.length );
     // outputs: Value: item99 length: 97

The slice() and splice() methods provide some unique methods for manipulating items in arrays. The slice() method retrieves a range of items using a start and end index value. The method does not affect the original array but returns a new array of the sliced items. The splice() method has two functions.

The first is to return a sliced array like the slice() method, but using a start index and a delete count value instead of the end index. The second parameter is considered a delete count because it will delete the items out of the array. The second functionality the splice() method provides comes to light when more than two parameters are used. All values after the second parameters are values to be inserted into the array.

var items:Array = ["x","l","e","z","f"];
var slice:Array = items.slice( 0, 2 );
trace( "items: " + items ); // outputs: items: x,l,e,z,f
trace( "slice: " + slice ); // outputs: slice: x,l
var splice:Array = items.splice( 0, 4 );
trace( "items: " + items ); // outputs: items: f,d,c,x
trace( "splice: " + splice ); // outputs: splice: x,l,e,z
items.splice( 1, 0, "d", "c", "x" );
trace( "items: " + items ); // outputs: items: f,d,c,x
items.splice( 1, 2, "l", "e" );
trace( "items: " + items ); // outputs: items: f,l,e,x

Sorting and Finding Items

Sorting and finding items of an array can be very powerful, but it is also easy to lose track of the subtle details. The Array class exposes two methods for sorting the items in the array: sort() and sortOn().

The first method, sort(), if given no parameters, will try to sort based on simple data values or complex data objects’ string representation. Providing the sort() method with a compare function parameter allows more fine-grained control of how the sort will work. Passing in a compare function for the Array to sort the items on requires some basic setup and understanding of how the comparable logic works. The function will compare two objects passing back a 1, -1, or 0, whether the two objects are less than, greater than, or equal, respectively.

var items:Array = ["x","l","e","z","f"];
items.sort();
 // e,f,l,x,z
var items:Array = [100, 23, 58, 890];
items.sort();
     // 100,23,58,890
items.sort( Array.NUMERIC );
 // 23,58,100,890

items = new Array();
items.push( { label: "Button", data: 100, id: 1 } );
items.push( { label: "Panel", data: 85, id: 2 } );
items.push( { label: "List", data: 50, id: 3 } );
items.push( { label: "Button", data: 85, id: 4 } );

items.sort( sortFunction );
 // Items Order
 // { label: "Panel", data: 85, id: 2 }
 // { label: "List", data: 50, id: 3 }
 // { label: "Button", data: 85, id: 4 }
 // { label: "Button", data: 100, id: 1 }

// Function that sorts on the second character of each item's label value
private function sortFunction(a:Object, b:Object):Number {
    if(a.label.substr( 1, 1 ) > b.label.substr( 1, 1 ) ) {
        return 1;
    } else if(a.label.substr( 1, 1 ) < b.label.substr( 1, 1 ) ) {
        return -1;
    } else  {
        return 0;
    }
}

The sortOn() method allows you to define the properties of complex objects to have the array sort on. You can define any number of properties to sort on, and what type of sorting each property should use.

var items:Array = new Array();
items.push( { label: "Button", data: 100, id: 1 } );
items.push( { label: "Panel", data: 85, id: 2 } );
items.push( { label: "List", data: 50, id: 3 } );
items.push( { label: "Button", data: 85, id: 4 } );

items.sortOn( ["label","data"], [ Array.DESCENDING, Array.NUMERIC |
Array.DESCENDING ] );
 // Items Order
 // { label: "Panel", data: 85, id: 2 }
 // { label: "List", data: 50, id: 3 }
 // { label: "Button", data: 100, id: 1 }
 // { label: "Button", data: 85, id: 4 }

items.sortOn( ["data","label"], [ Array.NUMERIC, Array.DESCENDING ] );
 // Items Order
  // { label: "List", data: 50, id: 3 }
  // { label: "Panel", data: 85, id: 2 }
  // { label: "Button", data: 85, id: 4 }
  // { label: "Button", data: 100, id: 1 }

Like the String class, the Array class provides indexOf() and lastIndexOf() methods to find items in the array. The check is done with the strict equality operator. Therefore, the items must match data type and value.

var items:Array = ["100",100,23,"abc",99];
items.indexOf( 100 ); // 1
items.indexOf( "100" ); // 0

var items:Array = ["100",100,23,"abc",99,100,"100"];
items.lastIndexOf( 100 ); // 5
items.lastIndexOf("100" ); // 6

Filtering and Other Methods

Some lesser-used methods of the Array class are quite powerful for specific needs. These methods use Function objects to do an action or test on some or all the items of the array. They are used to filter out items that, for example, have the value blue. Another case to use these methods is to find out if one or all items are odd. They are not just for checking, but also for applying some kind of Function to each item that changes the item’s value (for example, multiplying each item by two).

The methods exposed by the Array class are some(), every(), forEach(), map(), and filter().

var items:Array = [1, 2, 3, 4, 5];

// Affects original items array
items.forEach( powValues );
 // items: 1,4,9,16,25

// Does not affect original items array
var newItems:Array = items.map( powValues );
 // newItems: 1,4,9,16,25

// Does not affect original items array
var filterItems:Array = items.filter( isOdd );
 // filterItems: 1,9,25

var isOneItemOdd:Boolean = items.some( isOdd );
     // isOneItemOdd = true
var isEveryItemOdd:Boolean = items.every( isOdd );
     // isEveryItemOdd = false

// Value = Value * Value
private function powValues(element:*, index:int, arr:Array):void {
    arr[ index ] = element * element;
}

// Check to see if its odd
private function isOdd(element:*, index:int, arr:Array):Boolean {
     return ( element % 2 ) != 0;
}

items.join( " ## " ); // 100 ## 100 ## 23 ## abc ## 99

One last function that is part of the Array class is join(). This function allows you to set a delimiter that will be used to create a string representation of the items in the array.

var items:Array = ["100",100,23,"abc",99];
items.join( " ## " ); // 100 ## 100 ## 23 ## abc ## 99

Associative Arrays

Associative arrays are used when numeric index values are not sufficient. There are two ways to accomplish this in ActionScript 3.0. The first is to use a dynamic Object class where each property is a key to storing a data value. The second is to use the Flex Framework’s Dictionary class. The Dictionary class is slightly different than using an Object as the associative array because it forces the use of the strict equality operator (===) when looking for a key.

Constructing Associative Arrays

Associative arrays have no wrapper class to facilitate adding items. Each item must be done by setting each key and value pair directly. Listing 17-3 shows a simple custom User class to help with the following code examples.

Listing 17-3: User Class
Image from book

package
{
public class User
{
  public var id:String;
  public var name:String;

  public function User( id:String, name:String )
  {
    this.id = id;
    this.name = name;
  }

  public function toString():String
  {
    return id;
  }
}
}
Image from book

Here is an example that shows creating associative arrays with both the Object class and the Dictionary class:

var user1:User = new User( "A456", "Bob" };
var user2:User = new User( "A134", "Sue" };
var user3:User = new User( "A863", "Joe" };

var users:Object = new Object();
users[ user1.id ] = "Item 1";
users[ user2.id ] = "Item 2";
users[ user3.id ] = "Item 3";

var usersDict:Dictionary = new Dictionary();
usersDict[ user1 ] = "Item 1";
usersDict[ user2 ] = "Item 2";
usersDict[ user3 ] = "Item 3";

var valObject:String = users[ users1 ]; // valid
var valDict:String = usersDict[ users1.id ]; // invalid
     // users1.id == users1 (users1.toString())
     // users1.id !== users1

users[ user3.id ] = null;
delete usersDict[ users3 ];

To remove items from an associative array, you use the null operator for the Object class and the delete operator for the Dictionary class. When using objects as the keys for associative arrays, there is an important memory principle to consider.

ActionScript 3.0 uses a garbage collector to reallocate memory of created objects and data values when they are not referenced anymore. The usage of an object as a key in both Object and Dictionary type associative arrays are considered a reference, and will cause the object not to be garbage-collected. The Dictionary class provides a constructor parameter that tells the instance to use weak references when objects are used as keys. You should only use weak references if you know what you are doing, because this can create side effects that are difficult to track down.

var usersDict:Dictionary = new Dictionary();
usersDict[ user1 ] = user1;

// user1 will not be collected by the garbage collector
user1 = null;

// Use weak references
usersDict = new Dictionary( true );
usersDict[ user1 ] = user1;

// user1 will be collected by the garbage collector
user1 = null;
// Problem is usersDict[ user1 ] doesn't go away, but unlikely to be accessed,
since user1 is not valid anymore.  If you understand what is going on, weak
references can work nicely.

// Approach to make sure memory collection is done
var usersDict:Dictionary = new Dictionary();
usersDict[ user1 ] = user1;

// delete and release the key and the object
delete usersDict[ user1 ];
user1 = null;

Sorting Keys or Values

Any sorting on associative arrays must be implemented by custom classes or functions. The keys are naturally sorted by the order they are assigned to the associative array. The two methods of iterating over the array do not guarantee the order of the keys or the values. The following examples use the User class from Listing 17-3:

var user1:User = new User( "A456", "Bob" );
var user2:User = new User( "A134", "Sue" );
var user3:User = new User( "A863", "Joe" );

var values:Object = new Object();
values[ user1 ] = "Any Value 1";
values[ user2 ] = "Any Value 2";
values[ user3 ] = "Any Value 3";

for( var a:String in values )
     trace( a ) ;
 // A456
 // A863
 // A134
for each( var val:Object in values )
     trace( val );
 // Any Value 1
 // Any Value 3
 // Any Value 2

The SortedMap custom class shown in Listing 17-4 facilitates the ability to sort both the keys and values of the associative array.

Listing 17-4: SortedMap Class
Image from book

package
{
import flash.utils.Dictionary;

public class SortedMap
{
  private var map:Dictionary;
  private var keys:Array;

  public function SortedMap()
  {
    map = new Dictionary();
    keys = new Array();
  }

  // add values by key
  public function addItem( key:Object, value:Object ):void
  {
    map[ key ] = value;
    keys.push( key );
  }

  // get values by key
  public function getItem( key:Object ):Object
  {
    return map[ key ];
  }

  // return keys array, used to iterator over values
  public function keySet():Array
  {
    // sort keys, use toString() on key
    keys.sort();
    return keys;
  }

  // return keys array, used to iterator over values
  public function values():Array
  {
    var values:Array = new Array();
    for each( var val:Object in map )
      values.push( val );
    return values;
  }
}
}
Image from book

The addItem(), removeItem(), and getItem() methods provide the ability to add, remove, and retrieve items from the Dictionary class instance created by the SortedMap. The keySet() method provides a sorted array of all the keys, and the values() method provides a sorted array of the items in the associative array.

var user1:User = new User( "A456", "Bob" );
var user2:User = new User( "A134", "Sue" );
var user3:User = new User( "A863", "Joe" );

var sortedMap:SortedMap = new SortedMap();
sortedMap.addItem( user1, "Any Value 1" );
sortedMap.addItem( user2, "Any Value 2" );
sortedMap.addItem( user3, "Any Value 3" );

var sortedKeys:Array = sortedMap.keySet();
for( var i:int = 0; i < sortedKeys.length; i++ )
     trace( sortedMap.getItem( sortedKeys[ i ] ) );
 // Any Value 1
 // Any Value 2
 // Any Value 3

sortedMap.removeItem( user2 );

sortedKeys = sortedMap.keySet();
for( var i:int = 0; i < sortedKeys.length; i++ )
     trace( sortedMap.getItem( sortedKeys[ i ] ) );
 // Any Value 1
 // Any Value 3

Multidimensional Arrays

Because arrays (indexed or associative) facilitate storing any data object, it is possible to have an array of arrays. This is also known more properly as multidimensional arrays. You access any array the same way, regardless of whether it’s the root data value or a subdata value as part of the array.

var twoDim:Array = new Array();
twoDim[0] = [ "one", "two", "three" ];
twoDim[1] = [ "four", "five", "six" ];
twoDim[2] = [ "seven", "eight", "nine" ];

trace( towDim[0].[1] ); // two
trace( towDim[2].[2] ); // nine

var user1:User = new User( "A456", "Bob" );
var user2:User = new User( "A134", "Sue" );
var user3:User = new User( "A863", "Joe" );

var sortedMap:SortedMap = new SortedMap();
sortedMap.addItem( user1, "Any Value 1" );
sortedMap.addItem( user2, "Any Value 2" );
sortedMap.addItem( user3, "Any Value 3" );

var rootArray:Array = new Array();
rootArray.push( sortedMap );

rootArray[0].getItem( user1 ); // Any Value 1

Cloning Arrays

Cloning objects introduces the idea of making copies. Each object has actual bytes stored in memory that variables point to. When making copies of objects, you can either copy each byte, or copy only the references to the byte locations. Deep copy and shallow copy are used to describe these two scenarios, and, in terms of an array, it determines if the item values are copied or use references. The Array class by itself has no built-in cloning methods.

To create a shallow copy of an array, you can use the concat() or slice() function with no parameters. Creating a deep copy is more involved, and is approached by writing the object to a ByteArray and then reading it back into a new Array object.

import flash.utils.ByteArray;

var user1:User = new User( "A456", "Bob" );
var user2:User = new User( "A134", "Sue" );
var user3:User = new User( "A863", "Joe" );

var values:Array = new Array();
values.push( user1 );
values.push( user2 );
values.push( user3 );

var byteArray:ByteArray = new ByteArray();
byteArray.writeObject( values );
byteArray.position = 0;
var newValues:Array = byteArray.readObject();

user2.id = "B761";
trace( values[ 1 ].id ); // B761
trace( newValues[ 1 ].id ); // A134


Error Handling

Applications are created to handle many different conditions affected by the system itself and outside players. Error handling allows applications to define the normal flow of execution and act upon exceptions.

Error Types

To understand the breadth of error handling, an outline of the error types and their functions is explored. The two main types of errors are compile-time and run-time errors. The Flash Player historically is capable of both synchronous and asynchronous method calls. There are ways to handle errors in both situations. Then, finally, the act of not catching errors is also considered a method of error handling.

Compile-time Errors

Because ActionScript 3.0 defines a more strongly typed language, the depth of compile-time exception and error handling is far greater than previous versions of ActionScript. The compile-time errors are reported when the mxmlc compiler is called and usually refer to syntax problems in the application. Some common compile-time errors can be explored by using the SortedMap class from Listing 17-4.

package
{
// comment out import line
// import flash.utils.Dictionary;
public class SortedMap
{
 // Declaring Dictionary class
     private var map:Dictionary;
     private var keys:Array;
     public function SortedMap()
     {
    map = new Dictionary();
    keys = new Array();
     }
...
...
}

This will throw a compile-time error with the code value of 1046 and message of “Type was not found or was not a compile-time constant: Dictionary.” Each class file must import class definitions before the class can be declared or instantiated. Here is another compile-time error example:

package
{
import flash.utils.Dictionary;

public class SortedMap
{
     private var map:Dictionary;
     private var keys:Array;

     public function SortedMap()
     {
    map = new Dictionary();
    // Assign map to keys, different types
    keys = map;
     }
...
...
}

This will throw a compile-time error with the code value of 1067 and message of “Implicit coercion of a value of type flash.utils:Dictionary to an unrelated type Array.” Here is another compile-time error example:

var sortedMap:SortedMap = new SortedMap();
sortedMap.addItem( user1 );

This will throw a compile-time error with the code value of 1136 and message of “Incorrect number of arguments. Expected 2.” You can find a list of compile-time errors in the Adobe Flex 2 language reference documentation.

Run-time Errors

After the application passes all compile-time errors, the generated SWF can now be played in the Adobe Flash Player. Run-time errors encompass any errors that occur when the application is running. The most common types of errors that are easily handled are synchronous errors, which happen when a line of code executes and are handled immediately. When this type of error occurs, the flow of execution tries to find the closest try…catch statement, or stops the execution stack. Most synchronous errors will be defined by the developer to conform to the state of variables and the application to the application’s specification.

package
{
import flash.utils.Dictionary;

public class SortedMap
{
     private var map:Dictionary;
     private var keys:Array;

     public function SortedMap()
     {
    map = new Dictionary();
    // Calling property of keys before keys is instantiated
    trace( keys.length );
    // Stops execution flow unless handled by try...catch statement
    keys = new Array();
     }
...
...
}

This will throw a run-time error with the code value of 1009 and message of “Cannot access a prop erty or method of a null object reference.” Trying to use an object’s methods and properties before it has been instantiated is a common run-time error. This code also exemplifies the idea of uncaught exceptions. There is no error-handling code around the trace( keys.length ) code statement or at a higher level in the execution stack to catch the run-time error. The Flash Player ignores the uncaught errors unless the error causes the SWF to stop. This is by design, because the user of the application might not know how to handle the error.

Here are some more errors:

// A Flex Framework class that throws a synchronous error
import flash.net.FileReference;
import flash.net.URLRequest;

var fileRef:FileReference = new FileReference();
fileRef.upload( new URLRequest( "" ) );
// throws IllegalOperationError – call was unsuccessful
// Stops execution flow unless handled by try...catch statement

// Developer Defined Error
var num:int = 10;
if( num < 20 )
throw new Error( "num < 20" );
// Stops execution flow unless handled by try...catch statement

This example shows the FileReference throwing a special error called IllegalOperationError. The Flex Framework supports numerous types of errors. The next example shows that custom messages can be used in developer-defined errors. The next two sections, “Custom Error Classes” and “Exception Handling,” discuss how to use the try…catch statement and custom errors to have more control over execution flow when processing synchronous errors.

The Flash Player supports asynchronous code, which means there is code executed that does not wait for a response. Event listeners are used to handle errors for these types of code execution blocks. The events return event objects containing messages or status information about the asynchronous call.

// A Flex Framework class that throws a synchronous error
import flash.net.NetConnection;
import flash.events.NetStatusEvent;

NetConnection.defaultObjectEncoding = flash.net.ObjectEncoding.AMF0;
var nc:NetConnection = new NetConnection();
nc.addEventListener( NetStatusEvent.NET_STATUS, netStatusHandler );
nc.connect( "rtmp://localhost/video_conference" );

/**
 *  Status Handler for the NetConnection class
 */
private function netStatusHandler( event:NetStatusEvent ):void
{
  trace( "netStatusHandler:code: " + event.info.code );
  switch( event.info.code ) {
    case "NetConnection.Connect.Success":
           // Connect Your Camera to the Video Conference
    break;
         case "NetConnection.Connect.Failed":
           // Connection Failed
    break;
}
}

This shows that the asynchronous events are used for both errors, but also status information about successful execution of code.

Custom Error Classes

The next two sections build upon the SortedMap class defined in Listing 17-4. The updated SortedMap class shown in Listing 17-5 consists of errors that will be thrown if a key is used twice, if a key is null, and a check for the key’s presence when retrieving an item.

Listing 17-5: SortedMap Class
Image from book

    ...
    // Sorted Map Class

// add values by key
public function addItem( key:Object, value:Object ):void
{
  // Constrain keys to be non-null
  if( key == null )
    throw new Error( "Invalid key, key can not be null.);
  // Constrained so that the value is not overridden
  if( map[ key ] != undefined )
    throw new Error( "Key " + key + " is not unique." );
  map[ key ] = value;
  keys.push( key );
}

// get values by key
public function getItem( key:Object ):Object
{
  if( map[ key ] == undefined )
    throw new Error( "Key " + key + " is not found." );
  return map[ key ];
}
   ...
Image from book

The next step is to make these errors into their own custom class. Custom error classes allow for encapsulation of error messages and error codes, making reuse much easier. The three custom Error classes are outlined in Listings 17-6, 17-7, and 17-8.

Listing 17-6: NullKeyException.as
Image from book

package
{
public class NullKeyException extends Error
{
public function NullKeyException()
{
       super( "Invalid key, key can not be null.", 3000);
}
}
}
Image from book
Listing 17-7: KeyNotUniqueException.as
Image from book

package
{
public class KeyNotUniqueException extends Error
{
public function KeyNotUniqueException( key:Object )
{
       super( "Key " + key + " is not unique.", 3001);
}
}
}
Image from book
Listing 17-8: KeyNotFoundException.as
Image from book

package
{
public class KeyNotFoundException extends Error
{
public function KeyNotFoundException( key:Object)
{
       super( "Key " + key + " is not found.", 3002);
}
}
}
Image from book

Apply the three new custom exception classes that extend the Error class to the SortedMap class, as shown in Listing 17-9.

Listing 17-9: SortedMap Class with Custom Exception Classes
Image from book

package
{
import flash.utils.Dictionary;

public class SortedMap
{
  private var map:Dictionary;
  private var keys:Array;

  public function SortedMap()
  {
    map = new Dictionary();
    keys = new Array();
  }

  // add values by key
  public function addItem( key:Object, value:Object ):void
  {
    // Constrain keys to be non-null
    if( key == null )
      throw new NullKeyException();
    // Constrained so that the value is not overridden
    if( map[ key ] != undefined )
      throw new KeyNotUniqueException( key );
    map[ key ] = value;
    keys.push( key );
  }

  // get values by key
  public function getItem( key:Object ):Object
  {
    if( map[ key ] == undefined )
      throw new KeyNotFoundException( key );
    return map[ key ];
  }

  // return keys array, used to iterator over values
  public function keySet():Array
  {
    // sort keys, use toString() on key
    keys.sort();
    return keys;
  }

  // return keys array, used to iterator over values
  public function values():Array
  {
    var values:Array = new Array();
    for each( var val:Object in map )
      values.push( val );
    return values;
  }
}
}
Image from book

Exception Handling

Because compiler errors are handled at compile time, this section focuses on how to handle exceptions at run-time. The focus is on the use of the try…catch…finally statements. Every try statement has at least one corresponding catch statement; finally is optional and defines a “catch all” type of code. The SortedMap class now throws custom errors that can be caught during execution with the try…catch…finally statements.

var user1:User = new User( "A456", "Bob" );
var user2:User = new User( "A134", "Sue" );
var user3:User = new User( "A863", "Joe" );

var sortedMap:SortedMap = new SortedMap();
sortedMap.addItem( user1, "Any Value 1" );
sortedMap.addItem( user2, "Any Value 2" );
sortedMap.addItem( user3, "Any Value 3" );
try {
     sortedMap.addItem( null, "Null Value" );
sortedMap.addItem( user1, "Any Value 1 Again" );
sortedMap.getItem( "badKey" );
} catch( nullKey:NullKeyException ) {
     trace( nullKey.toString() );
} catch( keyNotUnique:KeyNotUniqueException ) {
     trace(keyNotUnique.toString() );
} catch( keyNotFound:KeyNotFoundException ) {
     trace( keyNotFound.toString() );
}
     // outputs: NullKey(3000): Invalid key, key can not be null.
try {
sortedMap.getItem( "badKey" );
     sortedMap.addItem( null, "Null Value" );
sortedMap.addItem( user1, "Any Value 1 Again" );
} catch( nullKey:NullKeyException ) {
     trace( nullKey.toString() );
} catch( keyNotUnique:KeyNotUniqueException ) {
     trace(keyNotUnique.toString() );
} catch( keyNotFound:KeyNotFoundException ) {
     trace( keyNotFound.toString() );
}
     // outputs: KeyNotFound(3002): Key badKey is not found.

try {
sortedMap.addItem( user1, "Any Value 1 Again" );
sortedMap.getItem( "badKey" );
sortedMap.addItem( null, "Null Value" );
} catch( nullKey:NullKeyException ) {
     trace( nullKey.toString() );
} catch( keyNotUnique:KeyNotUniqueException ) {
     trace(keyNotUnique.toString() );
} catch( keyNotFound:KeyNotFoundException ) {
     trace( keyNotFound.toString() );
}
     // outputs: KeyNotUnique(3001): Key A456 is not unique.

The preceding code example shows how the exceptions are caught immediately and code execution jumps to the specific catch statement. The finally block is optional and there can be only one per try…catch statement. The code inside the finally block will be executed whether or not an exception is thrown. Handling custom errors or the Flex Framework’s built-in exception model will greatly enhance the quality of your application.


Regular Expressions

Regular expressions (also known as regexp) provide a method of finding and replacing patterns in strings. The specific implementation of regular expressions ActionScript 3.0 uses is defined in the ECMAScript Edition 3 language specification (ECMA-262). Flex 2 provides a RegExp class to help with using a regular expression’s statements and flags.

Regular Expressions and Strings

The following examples create regular expression patterns as literal values using the forward slash (/) character. Just as quotes are used to define strings, the forward slash defines a regular expression. The characters inside the two forward slashes define the pattern to be used. Just as in strings, if you need to use a special character, the backslash is used to escape the character. Regular expressions also have flags to tell the parser what or how many times to find and replace the patterns in the string.

var text:String = "Professional Flex 2 is a great Flex resource.";

// available flags: g, i, m, s, x
trace( text.match( /.l.x/ ) ); // Returns: Flex
trace( text.match( /f.e./ ) ); // Returns null (no matches)
trace( text.match( /f.e./i ) ); // Returns: Flex using ignoreCase flag
trace( text.match( /F.e./g ) ); // Returns: Flex,Flex using global flag
trace( text.match( /F[a-z]{3}/g ) ); // Returns: Flex,Flex using global flag
trace( text.match( /\d/ ); // Returns: 2

Now, to break this down, take a look at metacharacters and metasequences. There are 14 special characters (called metacharacters) used in regular expression patterns:

^ $ \ . * + ? ( ) [ ] { } |

The different metacharacters help define patterns, like matching at the start of a string (/^/) or only any character zero or one time (/?/). Along with metacharacters, there are metasequences. The metasequences special characters define patterns by sequence of characters (for example, finding the letter “a” repeated in a row three times: /a{3}/). There are many references on the Web explaining this, as well as the Flex 2 documentation itself, which goes into the detail of explaining each metacharacter and metasequence.

To illustrate some of the power of using regular expressions in Flex 2 specifically, consider the replace() method in the String class. There are a few methods that take regular expressions as parameters in the String class. In addition to the replace() method, there is match(), search(), and split(), which all were touched on earlier in the chapter.

var text:String = "Professional Flex 2 is a great Flex resource.";

// available flags: g, i, m, s, x
trace( text.replace( /(F)(l)(e)(x)/g, "$1-$2-$3-$4" ) );
// Returns: Professional F-l-e-x 2 is a great F-l-e-x resource.
trace( text.replace( /(P\w+l)(.*)F\w+x/g, "$2$1" ) );
 // Returns: Flex 2 is a great Professional resource.

Using the RegExp Class

Everything that you can do with regular expressions expressed as literal values can be done with the RegExp class. It provides a wrapper class that helps construct and retrieve information about regular expressions. For example, the five flags are defined as properties and can be read at any time. These properties are global, ignoreCase, multiline, dotall, and extended. There are two methods to create RegExp objects: using the constructor or using a literal regular expression.

// No Flags
var pattern1:RegExp = new RegExp( ".l.x" );
var pattern2:RegExp = /.l.x/;

// Assigning Flags
var pattern3:RegExp = new RegExp( "F.e.", "g" );
var pattern4:RegExp = /F.e./g;

trace( pattern1.global == pattern3.global ); // outputs: false
trace( pattern3.global == pattern4.global ); // outputs: true

// Escaping Backslashes
var pattern6:RegExp = new RegExp("(P\\w+l)(.*)F\\w+x ", "g" );
var pattern7:RegExp = /(P\w+l)(.*)F\w+x/g;

RegExp also provides two methods that execute regular expressions to find patterns on a string. The first is the exec() method, which is similar to the method match() from the String class. The difference is that the RegExp class can keep track of indexes of matches after each exec() call. You can also assign the lastIndex property to tell the RegExp object where to start its method calls. The exception is that if the global flag is set, then lastIndex is ignored, and exec() and test() methods start at the beginning of the string to do their search.

var text:String = "Professional Flex 2 is a great Flex resource.";

var pattern:RegExp = new RegExp("(\\w*)[aeiou][aeiou](\\w*)", "g" );
var result:Object = pattern.exec( text );
trace( result.index + " - " + result);
while( result != null ) {
     result = pattern.exec( text );
trace( result.index + " - " + result);
}

// Output:
// 0 – Professional,Profess,nal
// 25 - great,gr,t
// 36 - resource,res,rce

Using Groups

Some more advanced regular expression capabilities have to do with groups, including the following:

  • Backreference - A backreference tells the pattern to check for a subpattern match of the exact substring that the previous parenthetical group evaluated to. Backreferences are defined by a backslash preceded by 1–99.

  • Noncapturing group - A noncapturing group is defined such that the RegExp exec() method does not include the parenthetical group in the return value. The metacharacter for noncapturing groups is defined by (?: on the left, metacharacters or metasequences, and then a closing ). For the other metacharacter definitions, xxx is used to define the usage of metacharacters or metasequences.

  • Positive and negative lookahead groups - These provide a way to define a subpattern to allow the match to be used or not used in processing metacharacter or metasequence definitions in the regular expression. The metacharacter for positive and negative groups is (?= xxx ) and (?! xxx ), respectively.

  • Named groups - The named groups functionality provides a means to force the exec() methods to return the parenthetical group matches as properties with the name value on the return object. It uses (?P<name> xxx ).

var text:String = "Professional Flex 2 is a great Flex resource.";
var result:Object;

// Backreference \1 Looks for (F\we\w) match, which evaluates to Flex
var pattern:RegExp = /(F\we\w).*(\1)/ig;
result = pattern.exec( text );
trace( result.index + " - " + result);
// outputs: 15 - Flex 2 is a great Flex,Flex,Flex

// Noncapturing Group assigned to first group
pattern = new RegExp( "(?:\\w*)[aeiou][aeiou](\\w*)", "ig" );
result = pattern.exec( text );
trace( result.index + " - " + result);
// outputs: 0 - Professional,nal

pattern = /(?P<left>\w*)(?P<v1>[aeiou])(?P<v2>[aeiou])(?P<right>\w*)/ig;
result = pattern.exec( text );
trace( "left: " + result.left );
trace( "v1: " + result.v1 );
trace( "v2: " + result.v2 );
trace( "right: " + result.right );
// Outputs:
// left: Profess
// v1: i
// v2: o
// right: nal


XML

The Extensible Markup Language (XML) is being used more and more all around us. You can find XML in programming languages (MXML, XAML), in object transfer protocols (SOAP, XML-RPC, BXXP, XMLP), or in plain-text files for data storage, to name just a few. This discussion quickly examines the basics of XML, and then proceeds to more specific XML functionality new to ActionScript 3.0 and Flex 2.

Introduction to XML

XML is a specification that defines a standard way of marking up documents. These documents are usually made up of structured information. Like the structure of a tree data structure, parts of an XML document are commonly referred to as nodes (or elements). Each node can have other nodes as children and can have attributes attached to the node. Each XML document contains a top node (or root node) where the namespace is usually defined as an attribute called xmlns. Namespaces provide readers of the XML document with the blueprints to be able to read the document correctly. A basic MXML application is a valid XML document, as shown here:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:Button label="My Button" />
</mx:Application>

The first line states that the document conforms to the XML 1.0 specification and the document encoding type. The root node is defined as <mx:Application/>, where the mx namespace is defined in the root node. The root node has a child called <mx:Button />, which has an attribute of the name label and value of "My Button". Listing 17-10 shows an XML document outlining a list of users that will be used for the examples in the rest of the chapter.

Listing 17-10: Users.xml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<users>
 <user department="IT">
          <userid>145</userid>
          <firstname>Bob</firstname>
          <lastname>Weston</lastname>
          <phones>
               <phone>(545) 234-4523</phone>
               <phone>(400) 879-5116</phone>
          </phones>
     </user>
     <user department="Sales">
          <userid>3654</userid>
          <firstname>Tim</firstname>
          <lastname>Kimber</lastname>
          <phones>
               <phone>(774) 684-1616</phone>
               <phone>(400) 999-5465</phone>
          </phones>
     </user>
     <user department="HR">
          <userid>823</userid>
          <firstname>Susan</firstname>
          <lastname>Johnson</lastname>
          <phones>
               <phone>(123) 456-7891</phone>
          </phones>
     </user>
     <user department="IT">
          <userid>6355</userid>
          <firstname>Jerry</firstname>
          <lastname>Yassou</lastname>
          <phones>
               <phone>(334) 774-1224</phone>
               <phone>(423) 858-4244</phone>
               <phone>(633) 223-8994</phone>
          </phones>
     </user>
     <user department="Sales">
          <userid>95</userid>
          <firstname>Anna</firstname>
          <lastname>Fairworth</lastname>
          <phones>
               <phone>(667) 552-4499</phone>
               <phone>(871) 257-9080</phone>
          </phones>
     </user>
</users>
Image from book

E4X Introduction

The first item of business is to define E4X. The ActionScript 3.0 language is based on ECMAScript edition 4 draft language specification (note the draft 4). The new ECMAScript for XML specification defines classes and functionality for working with XML data; between ECMAScript, draft 4, and XML, you get E4X. In other words, E4X is the term to describe the classes and functionality that support XML data manipulation in ActionScript 3.0. This is a big change from previous ActionScript languages in which a lot of the heavy lifting had to be created each time. The goals of E4X are to make XML data simpler to handle, consistent with other parts of ActionScript, and familiar with other operators and language syntax (specifically, using the dot operator).

The four new classes created in ActionScript 3.0 to support E4X specifications are XML, XMLList, QName, and Namespace. These classes and E4X operators provide standard methods of creating, navigating, defining, and converting XML data. The common operators that will be used when manipulating and searching XML documents are the dot (.), name qualifier (::), attribute identifier (@), brackets ([]), and descendant accessor (..).

E4X Classes

The section discusses how to work with E4X classes, including the following:

  • Creating and destroying XML

  • Navigating XML

  • XML namespaces

  • XML type conversion

Creating and Destroying XML

You can create XML documents using many methods: inline in the code, static text/XML files, dynamic Web pages, or programmatically. The following shows some of these methods in action:

// static text/xml file
<mx:XML source="users.xml" />

// MXML inline code using users.xml XML
<mx:XML format="e4x">
<?xml version="1.0" encoding="utf-8"?>
<users>
     <user department="IT" active="true">
          <userid>145</userid>
          <firstname>Bob</firstname>
          <lastname>Weston</lastname>
          <phones>
               <phone>(545) 234-4523</phone>
               <phone>(400) 879-5116</phone>
          </phones>
     </user>
     ...
</users>
</mx:XML>
// AS inline code using users.xml XML
var users:XML = <users>
     <user department="IT" active="true">
          <userid>145</userid>
          <firstname>Bob</firstname>
          <lastname>Weston</lastname>
          <phones>
               <phone>(545) 234-4523</phone>
               <phone>(400) 879-5116</phone>
          </phones>
     </user>
     ...
</users>;
var users2:XML = XML( "<users><user department=\"IT\">...</user>...</users>" );
var users3:XML = new XML( "<users><user department=\"IT\">...</user>...</users>" );

// AS URLRequest
var users4:XML = new XML();
var request:URLRequest = new URLRequest( "http://localhost/users.xml" );
var loader:URLLoader = new URLLoader( request );
loader.addEventListener("complete", onComplete );

private function onComplete( event:Event ):void {
     users4 = XML( loader.data );
}

// AS Using Class Functions
var users5:XML = <users></users>;
users5.appendChild( <user department="IT"></user> );
users5.user.appendChild( <userid>145</userid> );
users5.user.appendChild( <firstname>Bob</firstname> );
users5.user.appendChild( <lastname>Weston</lastname> );
users5.user.appendChild( <phones></phones> );
users5.user.phones.appendChild( <phone>(545) 234-4523</phone> );
users5.user.phones.appendChild( <phone>(400) 879-5116</phone> );
...

This example introduces the appendChild() method, one of the methods of the XML class that allows for creation of XML objects. There are other methods exposed by the XML class to manipulate XML objects, including insertChildAfter(), insertChildBefore(), prependChild(), and replace().

This next example shows the power of dynamically creating an example. The field names are hard-coded in an Array called p, but you could use similar methods to create XML from objects through class introspection.

// AS Programmatically with Dynamic Arguments
var userArray:Array = new Array();
var user:Object = new Object();
user.department = "IT";
user.userid = 145;
user.firstname = "Bob";
user.lastname = "Weston";
user.phones = new Array();
user.phones.push( "(545) 234-4523" );
user.phones.push( "(400) 879-5116" );
userArray.push( user );

var user1:Object = new Object();
user1.department = "Sales";
user1.userid = 823;
user1.firstname = "Tim";
user1.lastname = "Kimber";
user1.phones = new Array();
user1.phones.push( "(774) 684-1616" );
user1.phones.push( "(400) 999-5465" );
userArray.push( user1 );

var u:String = "users";
var p:Array = ["user","department","userid","firstname","lastname",
"phones","phone"];
var users6:XML = <{u}></{u}>;

for( var i:int = 0; i < userArray.length; i++ ) {
     var curUser:Object = userArray [ i ];
     users6.appendChild( <{p[0]} {p[1]}={curUser[ p[1] ]}></{p[0]}> );
     users6[ p[0] ][i].appendChild( <{p[2]}>{curUser[ p[2] ]}</{p[2]}> );
     users6[ p[0] ][i].appendChild( <{p[3]}>{curUser[ p[3] ]}</{p[3]}> );
     users6[ p[0] ][i].appendChild( <{p[4]}>{curUser[ p[4] ]}</{p[4]}> );
     users6[ p[0] ][i].appendChild( <{p[5]}></{p[5]}> );

     for( var j:int = 0; j < curUser[ p[5] ].length; j++ )
          users6[ p[0] ][i][ p[5] ].appendChild( <{p[6]}>{curUser[ p[5]
][j]}</{p[6]}> );
}
trace( users6.toXMLString();
/*
Outputs:
<users>
  <user department="IT">
    <userid>145</userid>
    <firstname>Bob</firstname>
    <lastname>Weston</lastname>
    <phones>
      <phone>(545) 234-4523</phone>
      <phone>(400) 879-5116</phone>
    </phones>
  </user>
  <user department="Sales">
    <userid>823</userid>
    <firstname>Tim</firstname>
    <lastname>Kimber</lastname>
    <phones>
         <phone>(774) 684-1616</phone>
         <phone>(400) 999-5465</phone>
    </phones>
  </user>
</users>
*/

To remove nodes from an XML object, you use the delete operator:

// using users6 xml from above
delete users6.user[ 1 ];
trace( users6.toXMLString();

/*
Outputs:
<users>
  <user department="IT">
    <userid>145</userid>
    <firstname>Bob</firstname>
    <lastname>Weston</lastname>
    <phones>
      <phone>(545) 234-4523</phone>
      <phone>(400) 879-5116</phone>
    </phones>
  </user>
</users>
*/

One thing about inline XML that can be executed at compile time is that the MXMLC compiler will check for basic malformed XML issues. The preceding examples use the XML class to create XML objects. The other three E4X classes provide support in navigating XML objects, which is examined next.

Navigating XML

This is where E4X really shines over the previous methods of handling XML in ActionScript. The XML objects are commonly navigated by the following operators:

  • Dot (.)

  • Attribute identifier (@)

  • Brackets ([])

  • Descendant accessor (..)

With the help of the E4X operators or the XML class methods, you can get a list of the users, or the list of phone numbers, or even filter all the users from IT into a list. The following example uses the users.xml in Listing 17-10 and outlines how to find different sets of data from the XML document:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="init()">

// static text/xml file
<mx:XML id="usersXML" source="users.xml" />
<mx:Script>
  <![CDATA[
    private function init():void
    {
      // List Users using the dot operator
      var userList:XMLList = usersXML.user;
      trace( userList.toXMLString() );

      // List Users using the XML children() method, same result
      userList = usersXML.children();
      trace( userList.toXMLString() );

      // List Phone Numbers using the descendant operator
      var phoneList:XMLList = usersXML..phone;
      trace( phoneList.toXMLString() );

      // List Phone Numbers using the XML descendants() method, same result
      phoneList = usersXML.descendants( "phone" );
      trace( phoneList.toXMLString() );

      // List Users in IT using the attribute operator
      var phoneList:XMLList = usersXML.user.(@department == "IT" );
      trace( phoneList.toXMLString() );

      // List Users in IT using the XML attribute() method, same result
      phoneList = usersXML.user.(attribute( "department" ) == "IT" );
      trace( phoneList.toXMLString() );
         }
  ]]>
     </mx:Script>
</mx:Application>

To walk through the tree structure of the XML objects, you can combine the previous list-filtering capability with the bracket operator ([]) or specific XML class methods.

// Find First User
trace( usersXML.user[0] == usersXML.child( 0 ) ); // true
trace( usersXML..phone[1] == usersXML.descendants("phone" )[1] ); // true
trace( usersXML.user.phones.phone[0] == usersXML..phone[0] ); // true

The QName class provides functionality to represent qualified names of XML elements and attributes. The QName objects can be used to search XML objects and require a local name and a namespace URI. The following example will search through the XML looking for all elements called phone with the namespace of c:

// users.xml with a namespace
var usersXML:XML = <users
 xmlns:c="http://domain.com/cell/number"
 xmlns:w="http://domain.com/work/number"
 xmlns:h="http://domain.com/home/number">
  <user department="IT">
    <userid>145</userid>
    <firstname>Bob</firstname>
    <lastname>Weston</lastname>
    <phones>
      <c:phone>(545) 234-4523</c:phone>
      <w:phone>(400) 879-5116</w:phone>
      <h:phone>(123) 533-0023</h:phone>
    </phones>
  </user>
  <user department="Sales">
    <userid>3654</userid>
    <firstname>Tim</firstname>
    <lastname>Kimber</lastname>
    <phones>
      <c:phone>(774) 684-1616</c:phone>
      <w:phone>(400) 999-5464</w:phone>
    </phones>
  </user>
</users>;

// Namespace Object
var c:Namespace = new Namespace( "http://domain.com/cell/number" );
var phoneQName:QName = new QName( c, "phone" );

// Returns all user children in the XML object
var numbers:XMLList = usersXML.descendants( phoneQName );
for each( var phone:XML in numbers )
     trace ( "Phone: " + phone );
}

/*
Outputs:
Phone: (545) 234-4523
Phone: (774) 684-1616
*/

XML Namespaces

The Namespace class defines namespaces for XML objects. Namespaces can be used for associating a name space prefix to a Uniform Resource Identifier (URI), prefix methods with the same name, and group properties and methods for access control. The name qualifier operator (::) is used in connection to the namespace object, as shown in this example:

// users.xml with a namespace
var usersXML:XML = <users
 xmlns:c="http://domain.com/cell/number"
xmlns:w="http://domain.com/work/number"
 xmlns:h="http://domain.com/home/number">
  <user department="IT">
    <userid>145</userid>
    <firstname>Bob</firstname>
    <lastname>Weston</lastname>
    <phones>
      <c:phone>(545) 234-4523</c:phone>
      <w:phone>(400) 879-5116</w:phone>
      <h:phone>(123) 533-0023</h:phone>
    </phones>
  </user>
  <user department="Sales">
    <userid>3654</userid>
    <firstname>Tim</firstname>
    <lastname>Kimber</lastname>
    <phones>
      <c:phone>(774) 684-1616</c:phone>
      <w:phone>(400) 999-5464</w:phone>
    </phones>
  </user>
</users>;

// Namespace Objects
var c:Namespace = new Namespace( "http://domain.com/cell/number" );
var work:Namespace = new Namespace( "w", "http://domain.com/work/number" );
var home:Namespace  = new Namespace( "h", "http://domain.com/home/number" );

// Returns all user children in the XML object
var users:XMLList = usersXML.user;
for( var i:int = 0; i < users.length; i++ ) {
     trace ( "Userid: " + users[i].userid );
     trace( "Cell: " + users[i].phones.c::phone );
     trace( "Work: " + users[i].phones.work::phone );
     trace ( "Home: " + users[i].phones.home::phone );
}
/*
Outputs:
Userid: 145
Cell: (545) 234-4523
Work: (400) 879-5116
Home: (123) 533-0023
Userid: 3654
Cell: (774) 684-1616
Work: (400) 999-5464
Home:
*/

XML Type Conversion

XML elements and attributes inherently do not have any knowledge of data typing. The basic representation of XML is String (for example, toString() and toXMLString()). When navigating to a specific element or attribute value, you can cast the value to the appropriate data type. For example, the following code will return the userid value from the users.xml as a Number:

// usersXML contains users.xml data
var num:Number = Number( usersXML.user[0].userid );
trace( num ); // 145


Summary

This chapter included the basic overview of data types and the classes that support them. The examples covered classes that manipulate date, time, strings, arrays, and XML. An important section regarding error handling provided examples of how to handle data-execution exceptions. The introduction of regular expressions includes methods for filtering and replacing string values. Lastly, the ActionScript 3.0 XML classes implemented to E4X specification to provide the means to handle any XML data easily.

Chapter 18 is the beginning of a whole part on how to build and deploy Flex applications. The chapter discusses deployment and build file structure, compiling methods, and creation component options to consider when building a Flex application.


Part V: Building and Deploying Flex 2.0 Applications

Chapter List

Chapter 18: Building and Deploying Flex Applications
Chapter 19: Debugging and Testing
Chapter 20: Deploying Flex Applications


Chapter 18: Building and Deploying Flex Applications

This chapter takes a more in-depth look at the building and deploying process for your Flex application. It discusses Flex directory structure, development concerns, the basics of developing and deploying a Flex application, and ways to improve security and startup performance of your application. It is assumed that you have at least some understanding of how to create a Flex application, as discussed in the previous chapters. Many topics discussed throughout this chapter are covered in more detail throughout this book.

All developers have a structure in which they execute a project. Many start with discovery, and then move on to planning, development, debugging, and, finally, deployment. As you develop your own preferred process, this chapter will aid in moving from one stage to the next. However, before jumping into the building of an application in Flex, this chapter starts with a brief explanation of the Flex directory structure and what security and deployment concerns you should consider throughout the process.

Flex Framework and Application Directory Structure

As you work through the creation of your first application, it will be helpful to know where Flex, by default, stores everything on your development machine. Because there are multiple ways to install the Flex 2 Framework, it is important to mention that each type of installation has an independent directory structure. This section takes a quick look at the directory structure of Flex Builder (Flex 2 plugin for Eclipse), the Flex 2 SDK, and FDS2.

Throughout all three installations, you will be using the following executables. If you are using the Flex 2 SDK with a third-party editor, you will be more familiar with these executables than if you were using Flex Builder or the Flex Builder 2 plugin for Eclipse 3.1 (which, by default, is configured to use these executables without you having to access them yourself):

  • mxmlc.exe - Launches both MXML and ActionScript 3 compilers. This executable is discussed later in this chapter.

  • compc.exe - Compiles SWC files that are used for distributing components.

  • fdb.exe - Command-line debugger.

The following table describes the Flex 2 SDK installation directory structure.

Open table as spreadsheet
Directory | Description
/ | The root directory. You can specify where you would like the SDK to be installed when you decompress the SDK package.
/bin | The location of the mxmlc.exe, compc.exe, and fdb.exe executables.
/frameworks | The root directory of the framework. This is where flex-config.xml (configuration file for the compiler) resides, as well as defaults.css (default styles for the base Flex 2 components).
/frameworks/libs | The location of the base SWC files (component packages).
/frameworks/locale | The location of the localization files. If you’ve installed the English version, there will be an /en_US subdirectory containing the U.S. localization SWCs and property files.
/frameworks/source | The location of the core Flex Framework classes. When you import mx.events.FlexEvent into your application, you are referencing /frameworks/source/mx/events/FlexEvents.as.
/frameworks/themes | The location of the style and component files that are the default for the Flex 2 components.
/lib | The location of the JAR files used by the compiler.
/player | The location of the installers of Flash Player 9 for different operating systems, as well as the SAFlashPlayer.exe (stand-alone Flash Player).
/resources | The location of the default template HTML wrappers.
/samples | The location of sample Flex applications created by Adobe.

The following table describes the Flex Builder installation directory structure.

Open table as spreadsheet
Directory | Description
/ | The root directory of the Flex Builder installation. By default, on a Windows machine, this is located in /Program Files/Adobe/Flex Builder 2/.
/configuration | The location of the Eclipse config.ini file, as well as additional configuration files used by Eclipse and the Flex Builder plugin.
/features | The location of the Flex Builder plugin files for Eclipse.
/Flex SDK 2 | The location of the SDK, framework, compilers, and so on.
/jre | The location of the Java Runtime Environment (JRE) used by Flex Builder.
/Player | The location of the different Flash Player installation files that are packaged with Flex Builder.
/plugins | The location where Eclipse looks for default plugins, as well as custom installed plugins.
/Uninstall * | In addition to the directories mentioned, you may also see different uninstall directories, such as /Uninstall Adobe Flex Builder 2. These are used by Eclipse to uninstall different modules. It is not recommended, however, that you tamper with the default uninstall files.

The Eclipse Flex Builder 2 Plugin installation directory structure is almost the same as the Flex Builder 2 directory structure, illustrated previously. The only difference is that the Flex Builder 2 installation includes the Eclipse-specific subdirectories (features, plugins, and configuration). Eclipse-specific files are located within your Eclipse installation.

The following table describes the FDS2 installation directory structure.

Open table as spreadsheet
Directory | Description
fds2/ | The location of the root directory. Typically, it is located in fds2/, but you can specify any chosen location.
/flex_sdk_2 | The location of the Flex 2 SDK. This is almost the same as your base Flex 2 SDK installation, though it only has the bin, lib, and frameworks directories.
/jrun4 | The location of the JRun 4 application files. This isn’t completely necessary if you already have an instance of JRun 4 installed on your server.
/resources | The location of everything fun that FDS2 comes with, including configuration files, Flash Player installation files, sample applications, and security settings for popular J2EE-compatible applications.


Flex and Flash Player Security and Technology Concerns

Before jumping into a discussion of the design and development phases, it is important to consider how your Flex application will be viewed by the end users and how it affects security. Because your Flex application is compiled to a Flash SWF file and usually (though not in every case) deployed over a network, the majority of security concerns lie on the Flash Player itself. With this in mind, it is important to mention that there are ways to structure your data and work with the Flash Player that will help you create a more secure application. This section takes a look at network security concerns, open technology concerns, and what security features are available to you through the Flash Player.

Network Security Concerns

When building an Internet application in Flex (or any API, for that matter), network security shouldn’t be overlooked. Your goal is to keep sensitive data out of the public view. This may sound easy, because the average user would never be able to see how you’re loading data from XML or through AMF, but third-party tools have made eavesdropping easier for even your basic user. This is called a “man-in-the-middle attack.” The user is able to read and possibly modify data being sent from the server to the Flash Player client (in other words, your application). The following paragraphs discuss two common methods of reading data and their respecitive vulnerabilities.

You will more than likely use (or have used) XML to store data for a Flash or Flex application. Once it is up and running, it is a very convenient way to store groups of data that can be easily updated. However, XML is not a good place to store sensitive data, because XML is transferred over HTTP/SOAP and is encoded as Unicode or ASCII. This makes it immensely vulnerable.

Using your preferred browser, type in the URL to the location of your XML file (such as http://myserver/assets/myXML.xml). With any luck, your Web browser will display your XML, and some browsers will show you if your XML is malformed. If it didn’t display it immediately, but did load the XML file, go to View Image from book Source within the Web browser’s menu. If you can view your XML that is stored on the server, so can anyone else. You’d like to think most people would never try to look through your XML, but people are curious and sometimes malicious. Using a third-party program such as Sothink SWF Decompiler, someone could easily peek under the hood of your SWF and copy the URL to your XML. Even easier, someone could use a third-party HTTP header viewer such as the Tamper Data add-on for Mozilla Firefox to see what files are being requested. Such methods would give away the precise location of your XML file, allowing anyone to view its contents.

Flash Remoting and other remoting services that use Action Message Format (AMF) are a little more secure, but not a perfect solution. “Secure” is probably not the best term. Because AMF is a binary format, it is harder for the average user to view and interpret. Many developers, however, use middleware programs such as Charles by xk72 (http://www.xk72.com/charles/) or Service Capture by Kevin Langdon (http://kevinlangdon.com/serviceCapture/). Both programs act as a proxy between the server and the application. They parse data formatted in AMF and display it in their GUI. Such programs are convenient for developers, and are often lifesavers during the development process. But because the developer can view the data, so can anyone else who happens to be running these programs. Again, your average user probably is not running programs like these, but because they exist, you have to assume someone probably does.

So how do you avoid this? The safest route is to limit sensitive data altogether. If you are developing an application that requires large amounts of sensitive data to be passed to and from your application, it is recommended that you use encryption, such as Secure Socket Layer (SSL), through the browser. Using SSL encrypts the SWF file as well as data being sent over HTTPS, ensuring both the host and the client that their data is secured.

The other option for encryption is to use a cryptographic algorithm, such as MD5 or SHA-1. Flex does not natively support cryptographic encryption, but MD5 and SHA-1 libraries are available on Google Code as part of the AS3 Corelib, by Adobe (http://code.google.com/p/as3corelib/).

Open Technology Concerns

As with any open Web technology such as HTML and JavaScript, there is a certain degree of sacrifice that you must understand before deploying your application. Web applications that use server technologies, such as ASP, J2EE, or PHP, have an extra level of security that Flash lacks. When the user queries an application created in ASP or something similar, the server interprets the script and displays only the HTML necessary for the user to operate the application. The server hides all sensitive code from the user, and it is virtually impossible to view, unless you have the authorization to do so.

In the case of applications created in Flex or Flash and deployed as SWFs, clients download the application SWF directly onto their computers. This allows users complete access to your SWF, and it also allows them access to download any additional SWFs and supporting media that are called by your application. The redeeming part of using SWFs is that it takes third-party software to view your source, making it more difficult for most users.

Because your SWF is downloaded to the users’ machines, it is recommended that you rely on the server to validate sensitive information such as usernames and passwords. It is all right to check character length and integrity from within Flash, but as far as encryption and validation go, it’s better to store this on the server using a server-side technology, making it more difficult for people to gain access to that information.

Flash Player Security Features

As mentioned earlier in this section, Flash Player handles the bulk of the security for your Flex application.

Flash Player’s main mode of security is through sandboxes. A sandbox is a security grouping that limits the Flash Player’s access to certain resources. The following table describes the four types of sandboxes.

Open table as spreadsheet
Sandbox | Description
Remote | By default, when a user downloads an SWF from a Web site, it can only access SWFs within the parent domain, or domains specified within the Security.allowDomain() or crossdomain.xml file.
Local-with-filesystem | This allows an SWF executed in Flash Player locally to access the local filesystem. However, because the SWF is not trusted, it cannot communicate over a network.
Local-with-networking | This allows an SWF executed in Flash Player locally to access a designated Internet URL. However, because it’s not trusted by the user, it cannot read from the local filesystem.
Local-trusted | The local-trusted sandbox allows users or administrators of a machine to place an SWF into the “trusted” sandbox. When an SWF is trusted, it can access data over the network and on a local machine. Again, this must be set by the user or the machine’s administrator.

Flash Player’s method of security is fairly straightforward. When users access a site that contains a Flex application, they are downloading the SWF onto their computer. At that point, Flash Player sets up a security sandbox that limits the data being sent and received to only media that is within the domain of origin. For example, if you, as the developer, would like to access and manipulate an external SWF from your application using <mx:SWFLoader>, you can do so if it fits the following criteria:

  • The SWF was created for Flash Player 9, meaning it is coded in ActionScript 3 and not ActionScript 2 or below.

  • The SWF is within the same domain as the parent SWF trying to access it. If your application is at the domain http://www.domainA.com/, it can access child SWFs contained within that domain (such as http://www.domainA.com/swfs/SWF_2.swf).

However, both rules can be broken. If you need to load legacy content, such as content created in Flash 8, you can use the LocalConnection class. If you need access to an SWF outside of your domain, you can grant access to it using Security.allowDomain() or by editing the cross-domain policy within the crossdomain.xml file.

Another security sandbox feature is that once an SWF is downloaded onto the user’s machine, it has limited access to the local hard drive. “Limited” means that it pretty much has no access whatsoever, except for data being stored in a SharedObject. A SharedObject is a file stored locally on the machine running the SWF that created it. It is available only to the parent SWF, or allowed SWFs within the sandbox boundary. As the developer, you can store client-specific data to the clients’ machines, but you are limited to only 100KB of space per domain. The shared object file itself is stored in a pseudo-random directory path in order to avoid outside tampering. See Chapter 8 for details on how to use shared objects.

Flash Player 9 offers garbage collection that clears the Player’s memory each time the Player is accessed. This will assure the developer that the memory is completely wiped clean so that no application will have access to data stored from prior sessions.

Lastly, Flash Player offers a time-out on procedures that are stuck in recursion loops. For example, if you have a for loop that continues to be executed, eventually the Player will acknowledge this process as potentially harmful, and will prompt the user either to break the execution of the script or allow it to continue. This is particularly useful in ensuring that an SWF cannot execute a denial-of-service attack.


Building and Deploying Applications

The first step in building an application using any IDE (Flex included) is to start off with a plan. Although you could dive right into building out your application with a predetermined goal in mind, chances are that you will encounter problems throughout the build phase that you never considered. With a little planning, you will be able to minimize those unforeseen problems. Following are a few things to consider before you open up your preferred Flex editor and dive into the building phase:

  • Code for reusability - Your goal as a developer should be to create reusable code through inheritance, polymorphism, and abstraction. Reusability will save you development time. Although this discussion does not address the basics of object-oriented programming (OOP), a good place to start with code planning is to outline your application using a Unified Modeling Language (UML) diagram. Because Flex 2 MXML components are essentially classes, you can outline them in the same fashion as you would a standard class. As you map out your application using UML, you will see where inheritance may provide an easier solution. Following are some useful online UML resources:

    • http://www.eclipseplugincentral.com/ - If you’re using Flex Builder or the Flex plugin for the Eclipse SDK, look into different UML plugins. Several popular UML tools for Eclipse are available for free or for a small fee. You should look at the user comments for each plugin before downloading and installing.

    • http://www.gskinner.com/gmodeler/app/run.html - gModeler is a Flash-based UML diagramming tool created by Grant Skinner. It’s easy to use and it’s free. Although it was originally created for ActionScript 2, it is possible to also lay out ActionScript 3 classes.

    • http://www.sparxsystems.com/ - Sparx Systems offers a product called Enterprise Architect specifically for UML modeling. You can download a free, limited-access demo of the program. Enterprise Architect allows you to forward- and reverse-engineer ActionScript 3 as well as other object-oriented languages.

  • Choose a design pattern(s) - Choosing the right pattern fits into “coding for reusability,” but it’s worth mentioning on its own and isn’t completely necessary for all applications. A design pattern is a prebuilt solution to recurring problems in application design. If a design pattern fits in well with your application design, it could save you valuable development time. The Model View Controller (MVC) pattern is an excellent place to start and works well with the Flex Framework. For example, in the MVC pattern, the model will contain data provided by XML files or remote services, the view is any interface component that may include Flex components, and the controller is the logic that interfaces with the model and the view. As with all design patterns, the MVC pattern deserves more understanding and explaining than this overview chapter will allow. For more information on design patterns, refer to the following books:

    • Design Patterns: Elements of Reusable Object-Oriented Software (Upper Saddle River, NJ: Addison-Wesley Professional Computer Series, 1995), by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides - Also referred to as the “Gang of Four” book and considered to be the source of design patterns. Though this book covers design for Java and C++, the structure of each pattern can translate to ActionScript 3.

    • Head First Design Patterns (Sebastopol, CA: O’Reilly, 2004), by Elisabeth Freeman, Eric Freeman, Bert Bates, and Kathy Sierra - This is a terrific place to start, especially if programming is new to you. It’s written for Java, but can translate to ActionScript 3.

    • Advanced ActionScript 3 with Design Patterns (Berkeley, CA: Adobe Press, 2006), by Joey Lott and Danny Patterson - This book is great if you have had prior experience with ActionScript and would like to know more about ActionScript 3 while learning about design patterns.

  • Plan for the deployment environment - Consider where your finished application is going to reside when you’re done. Will you be using any data services, such as ASP.NET, PHP, or a J2EE-compliant technology? Will you be using any Web services, such as XML? Does your application have rich media like audio or video and, if so, will the server be able to handle the bandwidth? Does your project require declarative or programmatic security? Planning for your deployment server may require some homework on your behalf, but it will greatly decrease the odds of a development bottleneck at the tail end of your project.

  • Determine a good directory structure for both development and deployment - If you’re using Flex Builder and you’ve started a new project from within the project navigator, by default, Flex Builder will set up a basic /bin directory for the deployable SWFs, HTML files, and whatever else may be associated with your project. Source files will be placed in the root directory of your new project. Although this is fine for small applications that do not require many custom classes and components, you may find that the project calls for more of a development and deployment folder approach, where /src (source) is your development folder and /bin is your deployment folder. As an application grows, it will become clear how important setting up a directory structure can be. Directory structure is discussed in more detail later in this chapter.

Building for Flex 2 SDK

When building for the Flex 2 SDK, it is helpful to understand the process in which your application will be built, compiled, and distributed.

If you have had prior experience with building projects and applications with Adobe Flash Professional 8, or one of the previous versions of Flash, this process will seem familiar. Both Flash and the Flex 2 SDK compilers build a single SWF file that is run through Flash Player. The key difference (at least as far as development is concerned) is that the Flex 2 Framework includes packages not available through Flash.

Hopefully, you have decided on whether you will be using Flex Builder, the Flex 2 plugin for Eclipse, or a third-party editor with the free Flex 2 SDK. Differences between the software configurations were discussed in Chapter 1. Differences aside, all three configurations have the same single resulting SWF that will be deployed on your Web server.

In a typical development environment, you will be developing and testing the SWF locally as you go. Figure 18-1 illustrates a common deployment environment. However, if you are developing a secured, nonpublic application, or an application with a large development group, you may want to mirror your server setup so that you are not interacting with the live servers, or secure the outgoing and incoming traffic.

Image from book
Figure 18-1: Flex 2 SDK deployment environment

As you can see in Figure 18-1, when you’re developing your application, you must keep in mind that your server (or the client’s machine) may be behind a firewall, limiting access. Also, during development, you may be able to interact with all of the development servers, but when deployed, the client’s interaction should be limited through a server proxy. Lastly, when development is completed, the end SWF will be uploaded to the Web server, which is within the same domain as the other servers (application server and Web services server, if any are used), and downloaded through HTTP by the client.

Now that you have an idea of how the deployment structure could work, it will be easier to proceed with the rest of the development of your application. As mentioned in the previous section, you will want to consider security and optimization. Both will rely heavily on the type of application you are building and how you deploy it. These topics are discussed in more detail throughout the chapter.

Building for Flex Data Services 2

Earlier chapters have discussed what Data Services are (Chapter 3) and how to configure and manipulate data using the Flex Data Services 2 (Chapter 11). This section discusses the building and deployment concerns when dealing with Flex 2 Data Services (FDS2). This section requires that you have FDS2 installed on your development machine.

Important

If you do not have an external development server, or have not yet installed FDS2, Adobe offers FDS2 Express, which is free and nonexpiring if installed on a single, noncommercial CPU. FDS2 Express includes an optional JRun4 Java 2 Enterprise Edition (J2EE) application server installation, as well as sample applications to explore. You can download FDS2 free at http://www.adobe.com/products/flex/.

Developing with FDS2 is a lot like developing with the Flex 2 SDK. In both environments, you will be creating applications using ActionScript 3 and MXML, and your end product will be a single SWF that is downloaded to the end user’s machine. However, there are many important differences between the two.

The main, critical difference between the two is that FDS2 gives you the option of either precompiling locally in the IDE and uploading a single SWF to a hosting server that will interact with the FDS2 services, or uploading your uncompiled ActionScript and MXML source to the J2EE-compatible server, and allowing FDS2 to compile your application SWF on the fly when the first HTTP request is made to the application’s root MXML file.

Figure 18-2 illustrates the FDS2 deployment environment, which is much like that of a Flex 2 SDK deployment. Compare Figures 18-1 and 18-2. In both setups the developer uploads a compiled SWF to the deployment server, which is, in turn, downloaded by the end user when it is requested over HTTP. However, Figure 18-2 uses FDS2, which allows the SWF to utilize the FDS2 messaging architecture. Once the users download the SWF onto their machines, they are able to asynchronously communicate directly with the server running FDS2 through the server’s J2EE application using ActionScript Message Format (AMF)/HTTP.

Image from book
Figure 18-2: FDS2 precompile deployment environment

Figure 18-3 illustrates a deployment structure of an FDS2 application using server-side compiling. In this configuration, the developer uploads the Flex 2 application source directly to a server running a J2EE application and FDS2. When the first HTTP request is sent to the server, FDS2, through your J2EE application, compiles the application source to an SWF using the mxmlc.exe compiler. After the SWF is compiled, the end users download it to their machines. When the source has been modified, FDS2 will notify the J2EE application to recompile the SWF on the server. Otherwise, it is cached on the server for future requests. Once the end users have received the SWF, like the configuration in Figure 18-2, they are able to asynchronously communicate directly with the server using AMF/HTTP.

Image from book
Figure 18-3: FDS2 integrated Web-compiling deployment environment

The FDS2 application structure is shown in Figure 18-4. Although it is discussed in more detail in the next section, it is helpful to understand that, in this context, your J2EE server (this example uses JRun4) looks for the mxmlc.exe in a specified location (/bin) and compiles the SWF to the deployment directory (/servers/default/flex/).

Image from book
Figure 18-4: FDS2 directory structure

Application development and deployment structure aside, other differences between FDS2 and the Flex 2 SDK are, for the majority, configuration- and security-related. If your application relies on utilizing the FDS2 messaging architecture and compiling features, you will want to set aside more time for planning and configuration. Server-side application configurations tend to be more complex and will slow down development if they are not properly considered ahead of time. Likewise, because you are working with a J2EE server, you will want to ensure that, along with securing your Flex application, you take the appropriate steps to secure the J2EE application, as well as the data being sent and received through AMF.

Compiling an Application

How you compile your Flex application will rely greatly on which installation method you chose for the Flex 2 SDK. If you chose to install Flex Builder 2 or the Flex 2 Eclipse plugin, compiling is as simple as clicking the Run button. Other installations (such as the Flex 2 SDK) will require that you use mxmlc.exe to compile your application. This section discusses the basics of compiling.

Each example uses a very simple Flex test application called CompileTest.mxml. Here is how the file appears:

<?xml version="1.0" encoding="utf-8">
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
     <mx:Text text="EVERYTHING WORKS" size="30" />
</mx:Applcation>

If you compile successfully, the resulting SWF should look like Figure 18-5.

Image from book
Figure 18-5: The compiled Flex application

Compiling with mxmlc.exe

If you’re using the Flex 2 SDK without the Eclipse plugin or Flex Builder 2, you must use the mxmlc.exe compiler. The mxmlc.exe compiler is a free compiler by Adobe that compiles MXML and ActionScript 3 files. Therefore, you can create both applications using the Flex Framework, as well as Flash modules that are independent of the Flex Framework. The difficulty level in using the mxmlc.exe method of compiling ranges from extremely easy to moderately complicated, depending upon the flexibility you would like to have during the compile.

Drag-and-Drop Compiling with mxmlc.exe

The easiest method to compile an application is to drag your application MXML file to the mxmlc executable. Figure 18-6 illustrates dragging an MXML file. In this case, it’s the CompileTest.mxml file mentioned at the beginning of this section, and you dragged it onto mxmlc.exe icon located in {Flex 2 SDK Root}/bin/. If you’re using a Windows operating system, you will see that an instance of the command shell pops up for a second during the compiling. If the compiler finishes successfully, your compiled SWF will be located in the same directory as your MXML file.

Image from book
Figure 18-6: Drag-and-drop MXML compiling

Command-line Compiling with mxmlc.exe

If you’re looking for flexibility and options, using the command line to compile your application is the way to go. This example compiles the CompileTest.mxml file that was mentioned at the beginning of this section. If things go well and it compiles, your SWF should look like Figure 18-5. This example is Windows-specific, but you can compile from using the Terminal in Apple OS X.

In Windows, open up the command line by clicking Start Image from book Run. When Run opens, type cmd in the Open field to open the command shell. At this point, it’s good to get acclimated to the options that mxmlc.exe has available for you to use.

Locate the mxmlc.exe file on your hard drive. For this example, mxmlc.exe is located in C:\Flex\bin\mxmlc.exe, although it may not be located in this location on your computer. Now that you know where on your computer the mxmlc.exe is installed, using the command shell, navigate to your project. This example uses the CompileTest.mxml project example from the previous section. Once you’ve located your project, type the following at the command prompt:

C:\WROX_FLEX\COMPILE_TEST> C:\Flex\bin\mxmlc.exe CompileTest.mxml

At this point, the mxmlc.exe will load your flex-config.xml file, and it will compile your SWF. If you are following the example, the end SWF should look like Figure 18-5.

Many more options are available to you when compiling. If you are interested in these options, Chapter 19 discusses command-line compiling and debugging in more depth.

Additionally, as you develop your project and it becomes increasingly more complicated, it is recommended that you use a build tool to help automate the compiling process. Although there are many different build tools out there, one of the more popular is Apache Ant. When you tell Ant to compile, it looks for a build.xml file that contains instructions for how to compile your Flex application. For more information on Apache Ant, please refer to http://ant.apache.org. If you are interested in other build tools aside from Apache Ant, Wikipedia is a terrific place to start (http://en.wikipedia.org/wiki/Build_tool).

Compiling when Using Flex Builder 2, or the Flex Builder 2 Plugin

Compiling using Flex Builder and Eclipse with the Flex Builder plugin is the simplest way to compile your application. After you have created your project and have created at least one MXML application, you can click the Run icon, or the Debug icon if you are choosing to debug your application. Both icons are highlighted in Figure 18-7.

Image from book
Figure 18-7: Flex Builder Run and Debug buttons

Another option for compiling is to right-click an MXML application file within the Eclipse Navigator panel and select Run Application, as shown in Figure 18-8.

Image from book
Figure 18-8: Right-clicking an MXML application to compile and run

One thing to keep in mind when compiling with Flex Builder is that you do not have to use the default wrappers. This is discussed in more detail in the next section.

Deployment Directory Structure

With the exception of the FDS2 deployment that was discussed earlier, the deployment of a Flex 2 application is very similar to Flash deployment. Flex Builder, by default, sets up a deployment directory that is used when debugging, although you can customize your deployment as you see fit. The only thing to keep in mind when customizing a deployment is that you must keep your pathing correct - meaning that, if you nest your XML files in an /xml folder for run-time parsing, you must ensure that your Flex application is pointing to that /xml folder. This applies to any external, nonembedded assets.

The following table shows a basic customized deployment directory structure.

Open table as spreadsheet
Directory/File | Description
deploy/ | The location of the root directory. Many developers choose a /source, /deploy directory structure, although you can use whatever you’d like.
/images | The location of any nonembedded images such as PNG, JPG, and GIF.
/xml | The location of any nonembedded, run-time–specific data that is wrapped in XML.
/swfs | The location of any nonembedded SWFs used by your application.
/js | The location of any JavaScript files.
myApp.swf | Your application.
myApp.html | Your application’s HTML wrapper.

Deployment with Flex Builder 2

If you are using Flex Builder 2 or the Flex Builder plugin for Eclipse, as mentioned before, both create a deployment directory for you. Located in your application project’s root directory is a /bin directory. This is where all of the wrappers are kept. The following table describes this structure.

Open table as spreadsheet
Directory/File | Description
{appName}/bin/ | Your application deployment root directory
AppName.swf | The default SWF file for your application
AppName.html | The default HTML wrapper for your application
AppName-debug.swf | The default debugger SWF for your application that is used by the debugging version of Flash Player 9
AppName-debug.html | The default HTML wrapper for your application’s debug file
history.htm | The default wrapper for the history-management SWF
history.swf | The history-management SWF
history.js | The history-management JavaScript file
playerProductInstall.swf | The Flash player detection/installation SWF for Express install

As you can see, by default, Flex Builder’s deployment isn’t very organized, but it works well for testing. However, if you’re going to use your own wrappers and directory structure with Flex Builder, keep in mind that you have to tell Flex Builder to not build out the wrappers by default, and redirect Flex Builder’s RUN and DEBUG commands to your custom wrappers.

Figure 18-9 illustrates how to disable HTML wrapper generation within the properties of your application. To do so, uncheck “Generate HTML wrapper file.”

Image from book
Figure 18-9: Flex compiler / HTML wrapper preferences

After you have disabled the wrapper generation, reassign the RUN and DEBUG directives within Flex Builder. To do so, go to Run Image from book Run Image from book Other. The Run configuration panel will appear (Figure 18-10). You must create a new configuration by clicking New. Once the new configuration is created, ensure that Flex is pointing to the right application by selecting the correct MXML file under “Application file.” Next, uncheck “Use defaults” under “URL or path to launch.” You should now be able to browse for your custom wrappers. If you intend to continue to debug your application, you must create two wrappers. The first should embed the deployable version of your application (myApp.swf), and the other should embed the debug version of your application (myApp-debug.swf).

Image from book
Figure 18-10: Run configuration panel
Important

If you’d rather get away from Adobe’s wrappers and the methods it uses to embed SWFs, there are alternatives that may be more flexible or easier to use. One example of an alternative to Adobe’s embedding method is to use SWF Object by Geoff Stearns. Although the logistics of it cannot be addressed here, feel free to check it out at http://blog.deconcept.com/swfobject/.


Applying Flex Security

As your Flex 2 application is developed, security should be considered. The level of security will depend greatly on the type of application you are developing. For example, a stand-alone application with little-to-no dynamic data will require less security than an application that relies on Web services, such as XML, or dynamic data served through data services. This section provides a brief overview of each type of security measure.

Flex Security Features

A Flex application consists of one SWF that is deployed from the server to the clients’ machine. Because of this, most of the security is handled by the Flash Player or by the server itself. Regardless, there are things that you can do within the Flex Framework to ensure that your application is as secure as you need it.

Disabling viewSourceURL

First and foremost, you should disable the viewSourceURL property of your application, if you have enabled it. The viewSourceURL property adds the View Source option to the application’s context menu. Allowing clients to snoop around your code isn’t necessarily a good thing.

<mx:Application viewSourceURL="http://myDomainURL/source/">
</mx:Application>

MXML Request Restrictions

Certain MXML tags such as <mx:SWFLoader> may need additional security settings. <mx:SWFLoader>, in particular, loads SWFs into your application. Typically, you will either be embedding additional SWFs or loading them from a directory local to your application’s domain. If you are loading an SWF that is outside of your domain, you will need to use Security.allowDomain() or create a crossdomain.xml file. Additionally, if your SWF is served by a secured server (HTTPS), you cannot retrieve data from outside of the secured server.

Other restricted tags include <mx:DataService>, RPC (Remote Procedure Call) components such as <mx:HTTPService>, <mx:WebService>, and <mx:RemoteObject>, and messaging tags such as <mx:Producer> and <mx:Consumer>.

In addition to restricted tags, there are classes that may require additional security, such as Channel, ExternalInterface, NetStream, URLRequest, SoundMixer, URLLoader, and Loader.

Keep in mind, though, that when using restricted tags, some have events that are specific to procedures and data failing due to security errors. An example of this is the securityError event within the <mx:SWFLoader> tag. You can use this event to then disable the action that caused the security error, or to throw an alert window warning the user of the complication in the application.

Handling Errors and Validate User Input

When a user has the opportunity to input information, your application should check the data to see if it is valid. When passed to the server, invalid data could fail silently, or could redirect the user to an error page, depending on how the server is set up. In both cases, the user’s data will not be received by the server. In the second case, the user could be redirected out of the application entirely. By setting up validation, you can reassure the user that data is correct, while making sure it is exactly what the server will allow. Chapters 5, 9, and 15 discuss data validation in more detail.

If you are sending and receiving data from a server, loading external SWFs, or loading external media (such as mp3s or flvs), you will want to set up error handling. In most cases, when Flex cannot find a file or cannot connect to a server, it will fail silently, leaving the user confused and probably uninterested in using your application. Components and classes that deal with sending and receiving external data will have events that will let you, the developer, know whether or not it’s doing its job. You can listen for these events and either prompt the user with an error window, or maybe disable the process that causes the event. Chapter 5 discusses event handling in more detail.

Cleaning Up Your Code and Deleting trace() Methods

As you develop your application, you will be adding in trace() methods and other blocks of code that will allow you to debug. While your application is becoming more solid and indestructible, your code may be filling up with forgotten code and stray trace() methods. After your application is ready to be deployed, you should clean house. Go through your code and delete trace() methods and blocks of commented code that might be dangerous if viewed by the wrong person. Your everyday user cannot view the contents of an SWF, but there are a couple of decompilers (such as Sothink SWF Decompiler) that can decompile your SWF and show what makes it tick.


Improving Startup Performance

As the development on your Flex application nears its completion, some unforeseen problems you may run into are poor startup times, lags in your application, and errors thrown by components being created before data is available for them to utilize on instantiation. This section will help improve your startup time and give a brief understanding on how Flex 2 treats data being served to each separate component in an application.

Startup Order

When you’re creating your application, it is helpful to understand when each object is created. Each Flex component and container has events that are triggered throughout the startup phase. For example, when the application is first instantiated, it dispatches a preinitialize event, as does anything that is a subclass of UIComponent. Once the preinitialize event is dispatched, the application then creates any containers, which, in turn, create any components that are nested within.

This creation process is a bit more complex than this. To get a better sense of what’s going on with your Flex application’s startup order, it’d be helpful to list all of the startup events that are dispatched as the application is created.

Listing 18-1 is a small application that traces out each startup event, while adding a string to an array that is eventually listed out in a list component. As each event is dispatched, the variable counter is incremented and added to the string that populates the list. Also added to the string is the event’s target (what’s calling the event) and the type of event (initialize, preinitialize, add, and so on). When the final event, applicationComplete, is called, the dataProvider of the list component named COMPONENT is set to the array. This is assurance that the List will be populated after all events are dispatched. The end result will be a numbered listing of all of the events.

Listing 18-1: StartUpOrder.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  preinitialize="applicationPreInitHandler(event)"
  initialize="applicationInitHandler(event)"
  childAdd="applicationChildAddHandler(event)"
  applicationComplete="applicationCompleteHandler(event)"
  layout="absolute">
  <mx:Script>
    <![CDATA[
      private var counter:Number = 0;
     [Bindable] private var eventLogArray:Array;

      /** application event handlers **/
      private function applicationPreInitHandler(event:Event):void
      {
        eventLogArray = new Array();
        var eventString:String = counter++ +" APPLICATION ("+ event.target +"): "+
event.type;
eventLogArray.push(eventString);
        trace(eventString);
      }

      private function applicationInitHandler(event:Event):void {
        var eventString:String = counter++ +" APPLICATION ("+ event.target +"): "+
event.type;
eventLogArray.push(eventString);
        trace(eventString);
      }

      private function applicationChildAddHandler(event:Event):void
      {
        var eventString:String = counter++ +" APPLICATION ("+ event.target +"): "+
event.type;
        eventLogArray.push(eventString);
        trace(eventString);
      }

      private function applicationCompleteHandler(event:Event):void
      {
        var eventString:String = counter++ +" APPLICATION ("+ event.target +"): "+
event.type;
        eventLogArray.push(eventString);
        // assign array to component dataprovider after array is full
        COMPONENT.dataProvider = eventLogArray;
trace(eventString);
      }

      /** event handler **/
      private function eventHandler(event:Event):void
      {
        var eventString:String = counter++ +" "+ event.target +" : "+ event.type;
        eventLogArray.push(eventString);
        trace(eventString);
      }

      ]]>
  </mx:Script>
  <mx:Canvas id="CONTAINER" width="100%" height="100%"
    preinitialize="eventHandler(event)"
    initialize="eventHandler(event)"
    creationComplete="eventHandler(event)"
    childAdd="eventHandler(event)"
    add="eventHandler(event)" >
      <mx:List id="COMPONENT" width="500" height="300"
        preinitialize="eventHandler(event)"
        initialize="eventHandler(event)"
        creationComplete="eventHandler(event)"
        add="eventHandler(event)" />
    </mx:Canvas>
</mx:Application>
Image from book

Notice how the application is preinitialized, but then immediately after, the CONTAINER is added. After the CONTAINER is preinitialized, the child components are added (COMPONENT). After the component has preinitialized and there are no children of the component, it then is initialized, as is the CONTAINER, and then the application. After all items are initialized, a creationComplete event is dispatched by each, starting with the furthest nested child and ending with the application. In most cases, containers are initialized after the child components are added to them. The only time this doesn’t apply is when using multiview containers such as <mx:TabNavigator>. Flex only instantiates the components that are visible to the user. If a user navigates to another view, the items contained in that view are then instantiated and events are dispatched, after applicationComplete has been dispatched.

By understanding when these items are created and when the events are dispatched, you will be able to create a more robust application and avoid the possibility of assigning data to a component before it is instantiated.

Using Deferred Creation

After the previous example, you should have a good understanding of how Flex instantiates an application and the order in which all of the descendants of the application are created.

As mentioned, Flex instantiates a container and all of its children at run-time for the user to view the contents of that container. Certain multiview containers such as <mx:TabNavigator>, <mx:ViewStack>, and <mx:Accordian> use deferred creation in order to optimize startup time. In the case of navigator containers, deferred creation means that only the container and its children, visible to the user, are instantiated. The children of other hidden containers have yet to be instantiated, until the user sets focus on the hidden container.

Listing 18-2 shows a simple application that, like Listing 18-1, traces out the events of each container and component as it is instantiated, as well as assigning a number value to each event to better understand the creation order. This example creates a two-panel tab navigator that has a single button component in each panel. As you execute the application, you will see that only the component in Panel 1 is instantiated - that is, until you click Panel 2. When Panel 2 is focused, the button component for that panel is instantiated.

Listing 18-2: CreationPolicyExample.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  preinitialize="applicationPreInitHandler(event)"
  initialize="applicationInitHandler(event)"
  childAdd="applicationChildAddHandler(event)"
  applicationComplete="applicationCompleteHandler(event)" >
  <mx:Script>
  <![CDATA[
    private var counter:Number = 0;
    private var initProcessString:String = "";

    private function applicationPreInitHandler(event:Event):void
    {
      var eventString:String = counter++
        +" APPLICATION ("+    event.target +"): "+ event.type;
      initProcessString += eventString +"\n ---------- \n";
    }

    private function applicationInitHandler(event:Event):void
    {
      var eventString:String = counter++
        +" APPLICATION ("+ event.target +"): "+ event.type;
      initProcessString += eventString +"\n ---------- \n";
    }

    private function applicationChildAddHandler(event:Event):void
    {
      var eventString:String = counter++
        +" APPLICATION ("+ event.target +"): "+ event.type;
      initProcessString += eventString +"\n ---------- \n";
    }

    private function applicationCompleteHandler(event:Event):void
    {
      var eventString:String = counter++
        +" APPLICATION ("+ event.target +"): "+ event.type;
      initProcessString += eventString +"\n ---------- \n";
    }

    /** event handler **/
    private function eventHandler(event:Event):void
    {
      var eventString:String = counter++ +" "+ event.target +" : "+ event.type;
      if(TEXTAREA) {
        TEXTAREA.text = initProcessString += eventString +"\n ---------- \n";
      } else {
        initProcessString += eventString +"\n ---------- \n";
      }
    }

    /** handle string after complete **/
    private function textCreationCompleteHandler(event:Event):void
    {
      TEXTAREA.text = initProcessString;
    }
  ]]>
  </mx:Script>

  <mx:Panel title="creationPolicy Example"
    paddingBottom="10"
    paddingLeft="10"
    paddingRight="10"
    paddingTop="10">

    <mx:HDividedBox>
      <mx:TabNavigator id="NAVIGATOR"  width="250" height="150"
        preinitialize="eventHandler(event)"
        initialize="eventHandler(event)"
        creationComplete="eventHandler(event)"
        add="eventHandler(event)"
        added="eventHandler(event)">

        <mx:VBox id="CONTAINER1" label="PANEL SET 1"
          verticalAlign="middle" horizontalAlign="center">

          <mx:Button id="COMPONENT1"
            label="PANEL ONE BUTTON"
            preinitialize="eventHandler(event)"
            initialize="eventHandler(event)"
            creationComplete="eventHandler(event)"
            add="eventHandler(event)" />

        </mx:VBox>

        <mx:VBox id="CONTAINER2" label="PANEL SET 2"
          verticalAlign="middle" horizontalAlign="center">

          <mx:Button id="COMPONENT2"
            label="PANEL TWO BUTTON"
            preinitialize="eventHandler(event)"
            initialize="eventHandler(event)"
            creationComplete="eventHandler(event)"
            add="eventHandler(event)" />

        </mx:VBox>
      </mx:TabNavigator>

      <mx:VBox>
        <mx:Label text="RESULTS:" />
        <mx:TextArea id="TEXTAREA" width="600" height="300"
          creationCompleteEffect="textCreationCompleteHandler(event)" />
      </mx:VBox>
    </mx:HDividedBox>
  </mx:Panel>
</mx:Application>
Image from book

Working with creationPolicy

Any component that is a subclass of Container inherits the creationPolicy property. creationPolicy tells Flex when you would like the descendants of the container to be instantiated. By default, creation Policy is set to "auto". In Listing 18-2, because you didn’t assign a value to creationPolicy, it was set to "auto", meaning that only the components of the container in view were instantiated. The creation of Panel 2 components were deferred until you clicked the panel tab.

Now, take a look at what happens when you set creationPolicy to "all". Add creationPolicy="all" to the <mx:TabNavigator> tag in Listing 18-2.

<mx:TabNavigator id="NAVIGATOR"
  creationPolicy="all"
  width="350" height="150"
  preinitialize="eventHandler(event)"
  initialize="eventHandler(event)"
  creationComplete="eventHandler(event)"
  add="eventHandler(event)"
  added="eventHandler(event)">

When you debug the application, you will see that both panels and their components were instantiated at run-time. This is useful if you are assigning data to (or manipulating components in) a hidden panel. Normally, because the hidden components have yet to be instantiated, you would not be able to access them.

Keep in mind, though, if you are setting creationPolicy to "all", startup performance will suffer if there are a lot of components instantiated within the navigator container.

Other options are creationPolicy="queued" and creationPolicy="none".

If the policy is "queued", the container is added to the creation queue based on the value assigned to its creationIndex. If a creationIndex is not assigned, the container is added to the queue in the order in which it appears in the MXML file. If a subsequent container does have a creationIndex assigned, it will be added to the queue before those without. Once Flex instantiates and adds the containers to the DisplayList, it then advances to the next container in the queue and repeats the process. creation Index and creation order are discussed in more detail later in this chapter.

If the policy is "none", Flex does not instantiate any of the containers’ components, and it is your responsibility to instantiate each container by calling createComponentsFromDescriptors.

Deferring Component Creation

As your application becomes larger and more complex, you may see that the initialization of your application is becoming timelier and processor-intensive. By deferring component creation, you will be able to finely tune the performance of your application. The next two sections take a look at using create ComponentFromDescriptor and createComponentsFromDescriptors to defer and control component creation.

Deferring Creation with createComponentsFromDescriptors

First, take a look at the createComponentsFromDescriptors (plural) method of a container. To use this method, you must first set the container’s creationPolicy to “none”. This tells Flex that you do not want any of the components contained inside of the container to be instantiated at run-time. At runtime, Flex will add an object describing the component typed ComponentDescriptor to an array while awaiting instantiation. By calling the createComponentsFromDescriptors method, Flash Player will run through the array and instantiate each component and any children of the component while adding them to the DisplayList.

Listing 18-3 shows an application that uses createComponentsFromDescriptors to instantiate a button that is contained inside of an <mx:HBox> container. When the user clicks the CREATE COMPONENTS button, Flash Player runs through the array containing the ComponentDescriptor objects and builds out the components. Once the components are built, it then runs through the array of component descriptors and populates an <mx:TextArea> component with the properties of each ComponentDescriptor object.

Listing 18-3: DeferringComponents.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
      import mx.core.ComponentDescriptor;

      private function createComponents(event:Event):void
      {
        CONTAINER.createComponentsFromDescriptors();

        for(var i:int = 0 ; i < CONTAINER.childDescriptors.length; i++)
        {
          var mDescriptor:ComponentDescriptor = CONTAINER.childDescriptors[i];
          var mObj:Object = mDescriptor.properties;
          TEXTAREA.text += String("ID:"+ mDescriptor.id +"\nTYPE:"+
mDescriptor.type +"\n");
          for(var j:String in mObj)
          {
            TEXTAREA.text += String("PROPERTY "+ j +"= "+ mObj[j] +"\n");
          }
          TEXTAREA.text += String("-------------\n");
        }
      }

      private function componentCreationHandler(event:Event):void {
         TEXTAREA.text += String("NOTE: creationComplete on "+event.target.id+" was
 called\n");
      }

    ]]>
    </mx:Script>
    <mx:Button label="CREATE COMPONENTS" click="createComponents(event);" />
    <mx:HBox id="CONTAINER" creationPolicy="none" creationComplete=
"componentCreationHandler(event)">
      <mx:Button id="ADDED_BUTTON_1"
        label="BUTTON COMPONENT 01"
        alpha=".5"
        creationComplete="componentCreationHandler(event)"/>
      <mx:Button id="ADDED_BUTTON_2"
        label="BUTTON COMPONENT 02"
        alpha=".3"
        creationComplete="componentCreationHandler(event)"/>
      <mx:Button id="ADDED_BUTTON_3"
        label="BUTTON COMPONENT 03"
        alpha=".2"
        creationComplete="componentCreationHandler(event)"/>
    </mx:HBox>
    <mx:TextArea id="TEXTAREA" width="350" height="300" />
</mx:Application>
Image from book

The alpha of the button is changed merely to add properties to the textarea list. After all components are instantiated, a creationComplete event calls the componentCreationHandler method, which lets you see the order in which the components were added to the DisplayList and completed.

Deferring Creation with createComponentFromDescriptor

If you are looking for more control over deferred creation than what createComponentsFromDescriptors will allow, the Container class has another method, called createComponentFromDescriptor (singular).

As in createComponentsFromDescriptors, at run-time, Flex adds a ComponentDescriptor typed object to a childDescriptors array. Unlike its counterpart, createComponentFromDescriptor does not run through the entire array when it is called; instead, it looks for a parameter that specifies which child in the array will be instantiated. Here is an example of the method syntax:

createComponentFromDescriptor(obj:ComponentDescriptor, recursion:Boolean);

Also, unlike createComponentsFromDescriptors, once a child has been instantiated, it is not added to the DisplayList. Therefore, the parent container is not recognized as being complete and will not dispatch a creationComplete event. Instead, you must call the validateNow method of the Container class each time the createComponentFromDescriptor method is called.

Listing 18-4 shows a edited version of the existing code from Listing 18-3 to use the createComponent From Descriptor method. Once you click the CREATE COMPONENT button, you call the custom method, createComponent, which will pass a location in the container’s childDescriptors array to the createComponentFromDescriptor method. The childDescriptors array position will refer to the ComponentDescriptor object that will be instantiated.

Listing 18-4: DeferringComponents_2.mxml
Image from book

< <?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
  <mx:Script>
    <![CDATA[
      import mx.core.ComponentDescriptor;

      private var count:int = 0;

      private function createComponent(event:Event):void
      {
        CONTAINER.createComponentFromDescriptor(CONTAINER.childDescriptors[count],
true);
        CONTAINER.validateNow();

        var mDescriptor:ComponentDescriptor = CONTAINER.childDescriptors[count];
        var mObj:Object = mDescriptor.properties;
        TEXTAREA.text += String("ID:"+ mDescriptor.id +"\nTYPE:"+ mDescriptor.type
+"\n");
        for(var j:String in mObj)
        {
          TEXTAREA.text += String("PROPERTY "+ j +"= "+ mObj[j] +"\n");
        }
        TEXTAREA.text += String("-------------\n");

        if(count < CONTAINER.childDescriptors.length - 1) {
          count++;
        } else {
          CREATE_COMPONENTS_BUTTON.alpha = .1;
           CREATE_COMPONENTS_BUTTON.enabled = false;
         }
       }

       private function componentCreationHandler(event:Event):void {
         TEXTAREA.text += String("NOTE: creationComplete on "+event.target.id+" was
called\n");
      }

    ]]>
    </mx:Script>
    <mx:Button id="CREATE_COMPONENTS_BUTTON" label="CREATE COMPONENTS" click=
"createComponent(event);" />
    <mx:HBox id="CONTAINER" creationPolicy="none" creationComplete=
"componentCreationHandler(event)">
      <mx:Button id="ADDED_BUTTON_1"
        label="BUTTON COMPONENT 01"
        alpha=".5"
        creationComplete="componentCreationHandler(event)"/>
      <mx:Button id="ADDED_BUTTON_2"
        label="BUTTON COMPONENT 02"
        alpha=".3"
        creationComplete="componentCreationHandler(event)"/>
      <mx:Button id="ADDED_BUTTON_3"
        label="BUTTON COMPONENT 03"
        alpha=".2"
        creationComplete="componentCreationHandler(event)"/>
    </mx:HBox>
    <mx:TextArea id="TEXTAREA" width="350" height="300" />
</mx:Application>
Image from book

As mentioned previously, you must call the validateNow method of the parent container after the create ComponentFromDescriptor method runs in order to add the newly instantiated child to the DisplayList. Once the specified child is added to the DisplayList, notice that the creationComplete event is called by both the child component and the parent container, even though the other two children have yet to be instantiated. The parent container is considered complete, so you must manually instantiate the remaining children. The createComponent method has been modified to also advance the variable count after each child is instantiated and added to the DisplayList. By clicking the CREATE COMPONENT button again, you will build the next child and advance the variable, count, once more. If there are no more children left, the CREATE COMPONENT button will fade out and be disabled.

Using Ordered Creation

As discussed previously, Flex has a particular way it deals with the creation of an application and its descendants. Typically (meaning without changing any of the defaults), a Flex application will display a load progress bar as it downloads the SWF onto the client’s machine and instantiates all of the viewable containers and components. After the application has loaded and everything has been instantiated, the user will be able to interact with the application.

This will be okay for small, noncomplex applications, but as an application grows in both size and complexity, you may want to consider using creation queuing.

creationIndex

As mentioned previously in this chapter, if a container’s creationPolicy is set to “queue”, it is added to a creation queue before being instantiated and added to the DisplayList. Once the first container in the queue and its children have been successfully instantiated and added to the DisplayList, the next container in the queue begins to instantiate. You can control the creation order in the queue by using the creationIndex property to specify when you would like the particular container to be instantiated. Listing 18-5 builds out three numbered boxes created using the <mx:HBox> tag. As each box is created, a creationComplete event will be dispatched, announcing the box has been created. You can view the results in your debugging console because they are traced.

Listing 18-5: CreationIndexExample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
  <mx:Script>
    <![CDATA[
      private function traceEventHandler(event:Event):void
      {
        trace(event.target.id +" has been created");
      }
    ]]>
  </mx:Script>
  <mx:HBox>
    <mx:HBox id="box1"
      creationPolicy="queued"
      creationIndex="3"
      backgroundColor="0xFF0000"
      width="100" height="100"
      horizontalAlign="center"
      verticalAlign="middle"
      creationComplete="traceEventHandler(event);">
      <mx:Text color="0xFFFFFF" text="1" fontSize="30" />
    </mx:HBox>
    <mx:HBox id="box2"
      creationPolicy="queued"
      creationIndex="2"
      backgroundColor="0x0000FF"
      width="100" height="100"
      horizontalAlign="center"
      verticalAlign="middle"
      creationComplete="traceEventHandler(event);">
      <mx:Text color="0xFFFFFF" text="2" fontSize="30" />
    </mx:HBox>
    <mx:HBox id="box3"
      creationPolicy="queued"
      creationIndex="1"
      backgroundColor="0x00FF00"
      width="100" height="100"
      horizontalAlign="center"
      verticalAlign="middle"
      creationComplete="traceEventHandler(event);">
      <mx:Text color="0xFFFFFF" text="3" fontSize="30" />
    </mx:HBox>
  </mx:HBox>
</mx:Application>
Image from book

addToCreationQueue

One other option for controlling creation order through the creationPolicy is to use the addToCreation Queue method in connection with dynamically created UIComponents through ActionScript. Because you are going to control the instantiation completely by code, you will have to set the creationPolicy to "none" on the container that you want to queue. Once you have set the creationPolicy, you will manually set the creation order inside of a method using addToCreationQueue. Here is an example of the syntax of the addToCreationQueue method:

addToCreationQueue(id:Object, preferredIndex:Int);

Listing 18-6 modifies Listing 18-5 to work with addToCreationQueue. The id attribute of the addTo CreationQueue method will be the id property of the container you want to add. The preferred Index attribute will be the order number in which you want the container to be created. You have also added a button that, when clicked, will call the createContainers method, which will, in turn, run through the queue array and instantiate each container.

Listing 18-6: AddToCreationQueueExample.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
  <mx:Script>
    <![CDATA[
      private function traceEventHandler(event:Event):void
      {
        trace(event.target.id +" has been created");
      }

      private function createContainers(even:Event):void
      {
        addToCreationQueue("box1", 2);
        addToCreationQueue("box2", 1);
        addToCreationQueue("box3", 3);
      }
    ]]>
  </mx:Script>
  <mx:VBox>
    <mx:HBox>
      <mx:HBox id="box1"
        creationPolicy="none"
        backgroundColor="0xFF0000"
        width="100" height="100"
        horizontalAlign="center"
        verticalAlign="middle"
        creationComplete="traceEventHandler(event);">
        <mx:Text color="0xFFFFFF" text="1" fontSize="30" />
      </mx:HBox>
      <mx:HBox id="box2"
        creationPolicy="none"
        backgroundColor="0x0000FF"
        width="100" height="100"
        horizontalAlign="center"
        verticalAlign="middle"
        creationComplete="traceEventHandler(event);">
        <mx:Text color="0xFFFFFF" text="2" fontSize="30" />
      </mx:HBox>
      <mx:HBox id="box3"
        creationPolicy="none"
        backgroundColor="0x00FF00"
        width="100" height="100"
        horizontalAlign="center"
        verticalAlign="middle"
        creationComplete="traceEventHandler(event);">
        <mx:Text color="0xFFFFFF" text="3" fontSize="30" />
      </mx:HBox>
    </mx:HBox>
    <mx:Button label="CREATE CONTAINERS" click="createContainers(event);" />
  </mx:VBox>
</mx:Application>
Image from book

Using the callLater() Method

The callLater() method doesn’t really improve startup performance as much as it offers reassurance that methods are called after a component is instantiated and its properties are available. As your Flex applications grow in size and complexity, you may find that certain processes will throw Null Object Reference errors. This may be because you are trying to access a property of a component that is not yet available. The callLater() method will help reassure you that the component is available before a process tries to access it.

The callLater() method looks like this:

callLater(method: function, arguments: array = null):void

callLater() works by deferring your method to a queue that is accessed on the next screen refresh. The reason why this is sometimes necessary is because Flash Player executes code first and the UI after. By using callLater(), Flash Player will wait until after the component has been created before it tries to interact with it.

If you’re familiar with working with components in Adobe Flash 8, you may have used the doLater() method. The callLater() method replaced doLater() in ActionScript 3, and as doLater() was only available to components that extended mx.core.UIObject, callLater() is only available to components that are a subclass of UIComponent.

Listing 18-7 shows an example of one of the possible ways to use callLater(). The application is a first name and last name data grid entry. When the user submits a first and last name, the values of the input components are passed into an object called nameObject, which is then added into an ArrayCollection called gridArrayCollection. The gridArrayCollection is bindable and referenced by the data grid, nameGrid. callLater(), then assures that nameGrid is completely updated and calls the method, selectNewRow(), which sets the selectedIndex property of the nameGrid to the last entered row. Without callLater(), selectedIndex might be called before nameGrid had a chance to fully update. This would throw an error and break your application.

Listing 18-7: CallLaterExample.mxml
Image from book

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  initialize="applicationInit(event)">
  <mx:Script>
    <![CDATA[
      import mx.collections.ArrayCollection;

      [Bindable] private var gridArrayCollection:ArrayCollection;

      private function applicationInit(event:Event):void
      {
        gridArrayCollection = new ArrayCollection();
      }

      private function addGridItem(event:Event):void
      {
        var nameObject:Object = new Object();
        nameObject.firstName = FirstNameInput.text;
        nameObject.lastName = LastNameInput.text;
        gridArrayCollection.addItem(nameObject);
        callLater(selectNewRow);
      }

      private function selectNewRow():void
      {
        nameGrid.selectedIndex = nameGrid.rowCount;
      }

    ]]>
  </mx:Script>

  <mx:Panel title="callLater Grid Example" width="50%" height="50%"
    paddingTop="10" paddingLeft="10"
    paddingRight="10" paddingBottom="10">
    <mx:HDividedBox width="100%" height="100%">
      <mx:Canvas width="100%" height="100%">
        <mx:DataGrid id="nameGrid" dataProvider="{gridArrayCollection}"
          width="100%" height="100%">
          <mx:columns>
            <mx:DataGridColumn dataField="firstName"
              headerText="First Name"/>
            <mx:DataGridColumn dataField="lastName"
              headerText="Last Name"/>
          </mx:columns>
       </mx:DataGrid>
      </mx:Canvas>

      <mx:VBox width="70%" height="100%">
        <mx:Label text="First Name:" />
        <mx:TextInput id="FirstNameInput" />
        <mx:Label text="Last Name:" />
        <mx:TextInput id="LastNameInput" />
        <mx:Button label="Enter New Item" click="addGridItem(event)"/>
      </mx:VBox>
    </mx:HDividedBox>
  </mx:Panel>
</mx:Application>
Image from book


Summary

This chapter discussed the basics of developing and deploying a Flex application from start to finish. It is important to keep in mind that the steps you take in developing an application will change from project to project, but nevertheless, you should follow each step through. Do not hesitate to read through this chapter and other chapters within this book during your development phase. With a good understanding of proper planning, and the deployment environment, security, and performance optimization of your application, you will be able to build secured, robust applications without many of the headaches that may have developed in a project that has been poorly thought out.

Chapter 19 discusses logging, compiling, and debugging your Flex application.


Chapter 19: Debugging and Testing

Testing and debugging an application go hand in hand. The basic requirement to debug is to receive or view in real time messages from the system regarding the state of the execution stack. From logging simple messages to viewing the state of the execution stack, this chapter will help you debug and test both on the client side and the server side of development.

Logging Overview

There are two areas of logging in an application’s life cycle. The first is application- and compiler-generated messages, and the second is developer-created messages. To be effective in debugging and testing, you need to learn both areas and how they overlap. Most logging is something that is done during development, and should be disabled when put into production, but that doesn’t mean certain critical messages shouldn’t be taken out of live production applications.

If you are using the Flex server for compiling Flex applications, the compile-time errors will be output to the server’s standard out stream, either a console or log file, depending on your J2EE application server. The Flex server uses a specific version of the Apache Group’s log4j tool, which can cause errors if another log4j is found in the classpath. To debug, and not just watch log messages line by line for a Flex application, the Flex Builder or fdb debugger is required.

Tip

A common problem is defined in the “Log4j error on Flex startup” Adobe Flex TechNote, located at http://www.adobe.com/go/tn_19249.

It is important to note that if you deploy an application with standard Flash trace() method calls, anyone who views your SWF application with a Flash Debug Player can view the log messages.

The following sections touch on what, when, and how logging works for Adobe Flex applications.

Flash Debug Player

All Flex applications are compiled into SWF files. These files run in the Flash Player, which is known to have a small footprint. In the cases of debugging, the Adobe team has chosen to make two versions of the Flash Player to keep the size and optimization separated between debug and live SWFs. The Flash Debug Player has extra special debugging capability built into the Flash Player that helps with logging, real-time exceptions, and integration to debugging tools, command-line debugger fdb, or the Flex Builder debugging tools.

The Flash Debug Player is provided in the Flex SDK, Flex Builder, and Flex Data Services installers. It will be located in either <install_dir>/player/debug or <install_dir>/resources/player/debug. You will want to follow the install instructions to install the Flash Debug Player correctly. Most notably, a common problem is solved by ensuring all browsers are closed, and performing a clean uninstall and then install.

Tip

While installing the Flex Builder, you will be presented with an option to install the Flash Debug Player.

There are a few options that configure the Flash Debug Player located in a file called mm.cfg. This file is found in different places in different operating systems. The following table shows a short list of possible locations.

Open table as spreadsheet
Operation System | File Location
Macintosh OS X | MacHD:Library:Application Support:macromedia:mm.cfg
Microsoft Windows XP | C:\Documents and Settings\user_name\mm.cfg or %HOMEDRIVE%%HOMEPATH%\mm.cfg
Windows 2000 | C:\mm.cfg

There are four properties you can set in the mm.cfg file, as shown in the following table.

Open table as spreadsheet
Property | Description
ErrorReportingEnable | Set to 1 to tell Flash Debug Player to write error messages to a log file. The default value is 0.
MaxWarnings | Set the max number of error messages written to file. The default is 100. A value of 0 removes the limit of error messages written.
TraceOutputFileEnable | Set to 1 to tell Flash Debug Player to write trace messages to a log file. The default value is 0.
TraceOutputFileName | Property to specify the full path and filename where trace output messages will be logged. The default is a file named flashlog.txt, written in the same directory as mm.cfg.

If TraceOutputFileName is not set and TraceOutputFileEnable is set when the log file is created, it will be called flashlog.txt. Use these two parameters to log debugging messages to a file.

Logging API

The Flex logging API is made up of basic logging functionality called loggers and targets. The loggers send the actual messages and are constrained by category at instantiation. The static Log class is used to instantiate loggers, through the getLogger() method, and to add the newly created loggers to the target’s logger collection. An example of using the static Log class or manually doing the linking is demonstrated in the following paragraphs.

A target defines a specific logging mechanism such as the trace() method or sending a message through LocalConnection. Targets are Flex classes that implement the specific code to send out the log message. There are three default targets found in the Flex Framework: the MiniDebugTarget, the LineFormatted Target, and the TraceTarget (which inherits LineFormattedTarget).

The target has two methods of filtering logging messages: level and category. The level filter is more common, and there are six predefined levels: fatal, error, warn, info, debug, and all. These are all defined as static properties in the LogEventLevel class. The actual numeric values are arbitrary, and you could use your own levels by calling the logger object’s log() method with any level value. When creating an instance of a logging target, the level property defines which messages the target handles.

var logTarget:TraceTarget = new TraceTarget();
logTarget.filters = [ "*" ];
logTarget.level = LogEventLevel.ALL;

// Same level of message
Log.getLogger( "" ).info( "my message" );
Log.getLogger( "" ).log( LogEventLevel.INFO, "my message" );

The target can also define which categories the target will accept messages for. Categories are a newer filtering mechanism within the logging framework of ActionScript 3.0. The target object provides the filters property to define which categories will be used.

var logTarget:TraceTarget = new TraceTarget();
logTarget.filters = [ "mx.controls.Button", "com.mycompany.logging.*" ];

The category values are preferred to reflect the fully qualified name of the class the logger is logging. Even though you can set the value to anything you prefer (such as grouping loggers by different kinds of categorization), using the fully qualified class name will work nicely for most logging needs. The categories are linked to the loggers at the time of creation, either through the LogLogger class constructor or through the Log.getLogger() method.

// Target is created and waits for Log class to add loggers
var logTarget:TraceTarget = new TraceTarget();
logTarget.filters = [ "mx.controls.Button", "com.mycompany.logging.*" ];
// Log class handles creating an instance of a logger, and linking it to the target
var clickLogger:ILogger = Log.getLogger( "click" );
// Since the Log class did not handle the creation, a manual link
//  is required
var textChangeLogger:ILogger = new LogLogger( "textChange" );
// Add logger to target manually, first method is preferrable
logTarget.addLogger( textChangeLogger );

Compiler Logging

The messages that the Flex compiler provides when compiling applications can be controlled through an XML configuration file or command-line compile arguments. The default flex-config.xml is located in the <installation path>/Flex SDK 2/frameworks/ folder of your Flex Builder or Flex SDK installation. To obtain a list of all the compiler message filtering options, open a prompt and run the following commands:

// Lists all options
C:\>mxmlc -help advanced

// Lists all options with "warn" in it
C:\>mxmlc -help advanced warn
// Others related to setting compiler logging options
C:\>mxmlc -help advanced warn show strict verbose

The most common options that might be used are turning off warnings. Discussing each option specifically is outside the scope of this book. Refer to the mxmlc compiler help or the flex-config.xml file itself. The flex-config.xml is used in Web-tier compiling. When using Flex Data Services to compile applications on the Web server, the flex-config.xml provides the compiler on the server with the compiler arguments. In such a deployment, the flex-config.xml is found in the <app root>/WEB-INF/flex/ folder.

Web-tier Logging

Flex applications that run on a Web application server use the Web-tier compiler to be compiled. The life cycle of a Web-tier application begins with a FlexMxmlServlet that loads itself into the application server and handles initialization messages. As an application server running Flex Data Services executes the Web requests of MXML files, the Web-tier compiler errors and warnings will be sent to the Web application logging mechanism. The flex-Webtier-config.xml is used in connection to Flex Data Services to configure the Web-tier compile logging. The file is located in the same place as flex-config.xml, but is only present in Flex Data Services deployments.


Client-side Logging

Client-side debugging has the potential for requiring different approaches in how the messages of the application will be received. This section touches on using the basic trace() method and creating a custom target class, using the Flex 2 Logging API, to show different methods of displaying the message. The trace() method requires the debugging version of the Flash Player to write the message out to the output log file. By implementing a custom target class, you can also implement similar trace() method functionality without the need for the debugging version of the Flash Player. The following section uses a custom target class to send messages to a custom in-application trace panel. In Chapter 26, the example custom class created in this section is extended to work with outside third-party applications.

Using the Logging API

The trace() method is a global method provided by Flash to output messages to the default system output stream. This output stream can be configured to point to a log file, or be used in connection to the Flex Builder debugging tools, which are outlined later in this chapter. The Logging API is not specific to the trace() method and provides an abstract layer of functionality for encapsulating any specific logging mechanism through defined specific targets.

To further the understanding of the Logging API, a discussion of why and how the Logging API can be used is warranted. With the separation of the actual logging and targets telling the output where to go, the developer has full control of the messaging process. With a simple change in the target definition, the debugging messages can change from outputting to messages through the trace() statement to sending messages to a remote Web service. The loggers also provide the ability to classify the messages by level and category. This level of classification of messages provides far more advanced target filtering. The message can be defined down to the specific output object information an application will receive and display.

Take a look at an example to better understand this. To do this, the following example will create a custom logging class and display messages in Flex popup panel for the Flex application itself.

Custom Logger

The goal of the custom logger will be to provide an in-application, easy-to-use trace panel. The trace panel will need to be reusable in multiple applications and need to not affect performance drastically. Another feature proposed for the custom logger is the ability to turn logging on and off for the whole application or by specific level and category. The rest of this section shows through code how this is accomplished.

The CustomLoggerMain class in Listing 19-1 defines the basic application wherein the custom logger can be tested.

Listing 19-1: CustomLoggerMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:logger="*"
  layout="vertical">

  <logger:LoggerButton id="btnLogger" />

</mx:Application>
Image from book

The application shell has a custom button component called LoggerButton. The custom button will provide the mechanism to pop up the application trace panel. Listing 19-2 shows the LoggerButton popup implementation, along with actual logger message info() and debug() method calls.

Listing 19-2: LoggerButton.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Button
  initialize="init()"
  label="Trace Panel"
  xmlns:mx="http://www.adobe.com/2006/mxml">

  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.managers.PopUpManager;

      private function init():void
      {
        this.addEventListener( MouseEvent.CLICK, viewTracePanel );
      }

      [Bindable]
      public var tracePanel:TracePanel ;
      private function viewTracePanel( event:MouseEvent ):void
      {
        Log.getLogger( "LoggerButton" ).info( "viewTracePanel" );
        if( !tracePanel )
          tracePanel = new TracePanel();

        if( !tracePanel.isOpen ) {
          Log.getLogger( "LoggerButton" ).debug( "Trace panel is added to popup
manager." );
          tracePanel.isOpen = true;
          PopUpManager.addPopUp( tracePanel,
                                 DisplayObject( this.parentApplication ) );
          PopUpManager.centerPopUp( tracePanel );
        }
      }
    ]]>
  </mx:Script>
</mx:Button>
Image from book

Listing 19-3 shows the TracePanel class, which displays the logging messages, as well as providing a method of filtering the messages and turning off the logger object. As in the LoggerButton class, the logger objects are created with the "LoggerButton" category. The TracePanel will implement logger object calls specific to its own category name, "TracePanel". These two category values are what can be filtered. Included in the TracePanel class is a reference to the TracePanelTarget class shown in Listing 19-4.

Listing 19-3: TracePanel.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
  title="Trace Panel"
  paddingBottom="10" paddingLeft="10"
  paddingRight="10" paddingTop="10"
  minHeight="320"
  minWidth="360"
  initialize="init()"
  showCloseButton="true"
  close="close()"
  layout="vertical">
  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.logging.LogEventLevel;
      import mx.collections.ArrayCollection;
      import mx.managers.PopUpManager;

      public var isOpen:Boolean = false;

      [Bindable]
      private var targets:ArrayCollection;

      private var target:TracePanelTarget;
      private function init():void
      {
        target = new TracePanelTarget( txtOutput );
        target.filters=["*"];
        target.level = LogEventLevel.ALL;
        target.includeDate = true;
        target.includeCategory = true;
        target.includeLevel = true;
        Log.getLogger( "TracePanel" ).debug( "initilization" );
      }

      private function close():void
      {
        isOpen = false;
        PopUpManager.removePopUp( this );
      }

      private function changeTarget():void
      {
        if( !chkFlag.selected ) {
          Log.addTarget( target );
          Log.getLogger( "TracePanel" ).info( "Turned logging on!" );
        } else {
          Log.getLogger( "TracePanel" ).info( "Turning logging off!" );
          Log.removeTarget( target );
        }
      }

      private function filterTarget():void
      {
        Log.getLogger( "TracePanel" ).info( "Filter change!" );
        Log.removeTarget( target );
        target.filters = idFilter.text.split( "," );
        if( target.filters == null )
          target.filters = ["*"];
        Log.addTarget( target );
      }

    ]]>
  </mx:Script>

  <mx:HBox>
    <mx:Label text="Filter Categories:" />
    <mx:TextInput id="idFilter" text="*" change="filterTarget()" />
  </mx:HBox>
  <mx:HBox>
    <mx:Label text="Turn Logging Off" />
    <mx:CheckBox id="chkFlag" selected="false" change="changeTarget()" />
    <mx:Button label="Clear Output" click="txtOutput.text = ''" />
  </mx:HBox>
  <mx:Label text="Output Console" />
  <mx:TextArea id="txtOutput"
     updateComplete="txtOutput.verticalScrollPosition =
txtOutput.maxVerticalScrollPosition + 1;"
     width="100%" height="100%" />
</mx:TitleWindow>
Image from book
Listing 19-4: TracePanelTarget.as
Image from book

package
{

import mx.core.mx_internal;
import mx.controls.TextArea;
import mx.logging.targets.LineFormattedTarget;

use namespace mx_internal;

public class TracePanelTarget extends LineFormattedTarget {

    public function TracePanelTarget( console:TextArea ) {
    super();
    this.console = console;
    }

    private var console:TextArea;

  override mx_internal function internalLog(message:String):void
  {
      console.text += message + "\n";
    }
}
}
Image from book

The TracePanelTarget class extends the LineFormattedTarget class, which is the basis for most text targets in the Logging API. When a target object is created, it is automatically added to the list of targets in the Log class. This works fine for initialization, but every time some attribute on the target is changed, code must implement the removal and adding of the target back onto the Log class. Put it all together and run the application, and you can see the results in Figure 19-1.

Image from book
Figure 19-1: The results of CustomLoggerMain.mxml

Anywhere you use Log.getLogger( "someCategory" ).log(), you can bring up the simple custom logger TracePanel popup window and view the output. To make the insertion of the trace panel capability even more transparent, you can replace the LoggerButton with the LogController.mxml component shown in Listing 19-5. The LogController.mxml component implements a listener to listen for the keypress sequence of Ctrl+Shift+L, and then will pop up the TracePanel popup window.

Listing 19-5: LogController.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:UIComponent
  initialize="init()"
  xmlns:mx="http://www.adobe.com/2006/mxml">

  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.managers.PopUpManager;

      private function init():void
      {
        // Add the listener as a weak reference
        parentApplication.addEventListener( KeyboardEvent.KEY_UP,
keyUpEventHandler, false, 10, true );
        if( !tracePanel )
          tracePanel = new TracePanel();
      }

      private function keyUpEventHandler( event:KeyboardEvent ):void {
          if( event.ctrlKey && event.shiftKey && event.charCode == 76 ) {
            Log.getLogger( "LogController" ).info( "CTRL-SHIF-L has been pushed!" );
            viewTracePanel();
          }
      }

      [Bindable]
      public var tracePanel:TracePanel ;
      private function viewTracePanel():void
      {
        Log.getLogger( "LogController" ).info( "viewTracePanel" );

        if( !tracePanel.isOpen ) {
          Log.getLogger( "LogController" ).debug( "Trace panel is added to popup
manager." );
          tracePanel.isOpen = true;
          PopUpManager.addPopUp( tracePanel,
                         DisplayObject( this.parentApplication ) );
          PopUpManager.centerPopUp( tracePanel );
        }
      }
    ]]>
  </mx:Script>
</mx:UIComponent>
Image from book

A modified CustomLoggerMain.mxml is shown in Listing 19-6 with the LogController.mxml component.

Listing 19-6: Modified CustomLoggerMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:logger="*"
  creationComplete="init()"
  layout="vertical">

  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.managers.FocusManager;
      private function init():void
      {
        this.focusEnabled = true;
        this.focusManager.setFocus( btnTrace );
      }
    ]]>
  </mx:Script>

  <mx:Panel id="pnlApp" title="Sample Application"
    paddingBottom="10" paddingLeft="10"
    paddingRight="10" paddingTop="10"
    layout="vertical" horizontalAlign="center">
    <mx:Label
      text="Hit CTRL-SHIFT-L at the same time to view the TracePanel!" />
    <mx:Label
      text="Make a Trace by click on the button below!" />
    <mx:Button id="btnTrace" label="Click Me!"
      click="Log.getLogger( 'event' ).info( 'You clicked on ' + event.target )" />
  </mx:Panel>

  <logger:LogController id="ctlLogger" />

</mx:Application>
Image from book

Figure 19-2 shows the modified CustomLoggerMain.mxml with messages from clicking the button and pressing Ctrl+Shift+L. All it takes to integrate the custom logger TracePanel into all of your applications is to insert the LogController.mxml component and use Log.getLogger().log() anywhere you want to log a message.

Image from book
Figure 19-2: The results of the modified CustomLoggerMain.mxml with the LogController.mxml component


Flex Builder Debugging Tools

Chapter 2 provides an overview of the Flex Builder and debugging perspective. This section is meant to show in more depth how to debug an application using the Flex Builder debugging tools. You must install the debugging version of the Flash Player to work through the following examples.

Invoking

Open your Flex Builder and bring up the CustomLoggerMain.mxml file. It will be used in this section to demonstrate how to debug in Flex Builder. There are a couple methods to start a debugging session for a currently selected application file, two of which are using the shortcut key F11 or clicking the green bug-like icon, as shown in Figure 19-3.

Image from book
Figure 19-3: Debug application toolbar icon

You can also right-click any application file in a Flex project and select the Debug As context menu item. If you have multiple applications in your project you can also select the drop-down arrow next to the green bug-like icon to select from the list of applications. The application at the top of the list is defined as the last launched application. This also is the application used when pressing the F11 shortcut.

With the CustomLoggerMain.mxml file open, click line 29, then press Ctrl+Shift+B, or double-click the gray margin to the left of the text. You should see a breakpoint icon appear to the left of line 29, as shown in Figure 19-4. Run a debug session for the CustomLoggerMain application by clicking the green bug icon. The browser comes up the same as if you had run the application normally. The difference is that the application is running with the debug option turned on. If you are not in the Debugging perspective already, it will ask to switch to the Debugging perspective upon executing the first breakpoint or runtime exception code.

Image from book
Figure 19-4: Breakpoint on line 29 of CustomLoggerMain.mxml

Once the window is open, click the Click Me! button and switch to the Flex Builder Debugging perspective. You should find that the application stopped and the Flex Builder highlighted code for the breakpoint on line 29. The next step is to configure how to view the state to make it easier to find.

Configuring

The Debugging perspective provides a few views: the Variables view, the Breakpoints view, the Debug view, and the Expressions view. The Debug view allows you to play, pause, and stop the current debug session, which will be touched on more in a little bit. The views bunched together to the right (by default) provide the ability to see the state of the application at each breakpoint or suspended execution block. Figure 19-5 shows the Breakpoint view. The Breakpoint view lists all breakpoints in the application. You can double-click the breakpoint and it will take you to the breakpoint location in the code.

Image from book
Figure 19-5: Breakpoint view

The Variables view (Figure 19-6) shows all the properties with graphic indications of which one is private, public, protected, constant, static, or uses a getter.

Image from book
Figure 19-6: Variables view
Tip

The Variables view actually makes a call to each property to obtain the current value. This can have a side effect if the getter has code that modifies values each time it is called (that is, count++ in a getter). This can be turned off by choosing Windows Image from book Preferences Image from book Flex Image from book Debug and unchecking “Automatically invoke getter functions.”

To configure the Variables view, click the white down triangle located third from the right of the top icons. By clicking the icon, you will get a context menu that allows for various view layouts, variable specifics, and other available pane options.

Right-clicking any variable in the Variables view allows for you to choose Find Variable… (you can optionally press Ctrl+F). This will open a dialog box, as shown in Figure 19-7.

Image from book
Figure 19-7: Find Variable dialog box

Another available right-click context menu option is Watch. Selecting a variable for watching automatically creates an expression in the Expressions view. This is the easiest way to add a collection of specific variables that you want to watch. You can also create actual expressions in the watch expression values not only to watch a value, but also how it equates in an expression. In Figure 19-8, the watch expression this.height > 200 = true is shown.

Image from book
Figure 19-8: Expressions view

Breakpoints and Stepping

In the main Debug view in the Flex Debugging perspective, you will find a row of buttons. These buttons provide the ability to resume, suspend, terminate, step into, step over, and step return. Breakpoints provide single points in the code to automatically stop when debugging. The question is what to do when you need to continue. This is where you have multiple options, especially the stepping functionality.

Each step represents an execution of one line of code. You can step into and return from a single point, or, if you want to skip a line of execution, you can also skip it with step over (meaning that it executes the code but does not follow any stack executions down the tree). The power comes in by watching your variables and expressions in the Expressions view while executing a line at a time or between breakpoints.

The Flex Builder provides a nice UI to view the state of the application. Breakpoints and stepping are integral parts of the debugging process, regardless of whether you are using the Flex Builder debugging tools or the command-line debugger.


Command-line Debugger

Developers using the Flex SDK can also debug using the command-line debugger called fdb. Like the debugger tool built into Flex Builder, you can capture trace() statements, step through running code, watch variables, or set breakpoints.

Tip

There is a limitation of the fdb that does not allow the setting of breakpoints in MXML script code blocks. You can set breakpoints for event handlers in MXML tags.

Invoking

There are multiple ways to start a debugging session with fdb. All methods of starting a debug session require an SWF compiled with the –debug=true argument. If Flex Data Services Web compiler finds the ?debug=true present as an argument, the returned SWF will be compiled with the –debug=true argument. You can run the debug session in the stand-alone Flash Player, through the Flex Data Services server, or through a Web browser.

Follow these steps to start a debug session with the stand-alone Flash Player:

  1. Compile the application:

    mxmlc –debug=true CustomLoggerMain.mxml

  2. Type fdb into the command line and press Enter.

  3. Type run CustomLoggerMain.swf at the fdb prompt and press Enter.

Follow these steps to start a debug session through the Flex Data Services server:

  1. Type fdb http://localhost:8100/CustomLoggerMain.mxml in a command prompt.

  2. Press the Enter key.

Follow these steps to start a debug session with fdb and a Web browser:

  1. Compile the application:

    mxmlc –debug=true CustomLoggerMain.mxml.

  2. Create an HTML wrapper for the generated SWF.

  3. Copy the HTML wrapper and SWF to your Web server.

  4. Type fdb into the command line and press Enter.

  5. Type run in the fdb prompt and press Enter. You should see the message, “Waiting for Player to connect.”

  6. Open up the browser and point the URL to the HTML location.

Configuring

As in the Flex Builder debugging tools, you can configure certain specific aspects of how the debugger will act. This includes invoking getters for displaying the value. (Note the side effect mentioned earlier.) To find a list of the configurable values, use the following code:

>fdb
Adobe fdb (Flash Player Debugger) [build 143452]
Copyright (c) 2004-2006 Adobe, Inc. All rights reserved.
(fdb) help set
Set the value of a variable or a convenience variable.
Convenience variables are variables that exist entirely
within fdb; they are not part of your program.
Convenience variables are prefixed with '$' and can
be any name that does not conflict with any existing
variable.  For example, $myVar.  Convenience variables
are also used to control various aspects of fdb.

The following convenience variables are used by fdb.
$listsize - number of source lines to display for 'list'
$columnwrap - column number on which output will wrap
$infostackshowthis - if 0, does not display 'this' in stack backtrace
$invokegetters - if 0, prevents fdb from firing getter functions
$bpnum - the last defined breakpoint number

Examples:
  set i = 3
    Sets the variable 'i' to the number 3.
  set employee.name = "Susan"
    Sets the variable 'employee.name' to the string "Susan".
  set $myVar = 20
    Sets the convenience variable '$myVar' to the number 20
(fdb)

You’ll find in the list what are called convenience variables, including $listsize, $columnwrap, $info stackshowthis, $invokegetters, and $bpnum.

Debugger Commands

To get a list of debugger commands, simply type help and press Enter at the fdb prompt. The main difference in the fdb command-line debugger is that everything must be done explicitly. You must list your files and set breakpoints through the fdb prompt.

The easiest way to explain this is to show you a real fdb session. The following fdb session uses the CustomLoggerMain.mxml application and assumes you have started the debug session already:

(fdb) cf
IFlexModuleFactory.as#1:1
(fdb) continue
(fdb) cf
IFlexModuleFactory.as#1:1
(fdb) info sources
CustomLoggerMain.mxml#45
LogController.mxml#103
TracePanel.mxml#158
TracePanelTarget.as#210
(fdb) info functions CustomLoggerMain.mxml
Functions in CustomLoggerMain.mxml#45
 CustomLoggerMain$iinit 5
 ___Application1_creationComplete 5
 __btnTrace_click 29
 global$init 6
 init 12
(fdb) b #45:29
Breakpoint 1 at 0x4db07: file CustomLoggerMain.mxml, line 29
(fdb) continue

... click on the "Click Me!" button in the SWF

Breakpoint 1, __btnTrace_click() at CustomLoggerMain.mxml:29
 29                     click="Log.getLogger( 'event' ).info( 'You clicked on '
+ event.target )" />
(fdb) list #158:25
 20
 21                     [Bindable]
 22                     private var targets:ArrayCollection;
 23
 24                     private var target:TracePanelTarget;
 25                     private function init():void
 26                     {
 27                             target = new TracePanelTarget( txtOutput );
 28                             target.filters=["*"];
 29                             target.level = LogEventLevel.ALL;
(fdb) b #158:44
Breakpoint 2: file TracePanel.mxml, line 44
(fdb) commands
Type commands for when breakpoint 5 is hit, one per line.
End with a line saying just 'end'.
>print chkFlag.selected
>end
(fdb) continue

...press Ctrl-Shift-L in the SWF, and then on the Turn Logging Off check box

Breakpoint 2, changeTarget() at TracePanel.mxml:44
 44                             if( !chkFlag.selected ) {
$1 = true
(fdb) print chkFlag.selected
$2 = true
(fdb) kill
Kill the program being debugged? (y or n) y
(fdb) quit

The following code demonstrates how to restart an fdb session:

(fdb) kill
Kill the program being debugged? (y or n) y
(fdb) run
Waiting for Player to connect

Restart the Web browser serving the application and it will connect again at the beginning. Each command is further explained by typing help <command> (for example, help info). In the following code example, you’ll see that there are shortcuts for each command, too:

(fdb) help info
Generic command for showing things about the program being debugged.
List of info subcommands:
info arguments (i a)    Argument variables of current stack frame
info breakpoints (i b)  Status of user-settable breakpoints
info display (i d)      Display list of auto-display expressions
info files (i f)        Names of targets and files being debugged
info functions (i fu)   All function names
info handle (i h)       How to handle a fault
info locals (i l)       Local variables of current stack frame
info scopechain (i sc)  Scope chain of current stack frame
info sources (i so)     Source files in the program
info stack (i s)        Backtrace of the stack
info swfs (i sw)        List of swfs in this session
info targets(i t)       Application being debugged
info variables (i v)    All global and static variable names
Type 'help info' followed by info subcommand name for full documentation.

Although the command-line debugger is not quite the same as the Flex Builder’s debugging tools, it is a handy tool to understand when Flex Builder is not an option.


Summary

The full breadth of debugging was covered in this chapter. Starting with basic logging to output files or output messages in a custom Flex trace panel, you learned how to leverage the debugging tools that come with Flex 2. Details of the Flex Builder debugging tools, as well as the command-line tool, showed you how to view the internal state of an application through defining breakpoints and watching variables.

In Chapter 20, you learn how to take your application to the Web. The specific Flex application deployment considerations are covered in depth.


Chapter 20: Deploying Flex Applications

Analysis of the requirements and of the functionality, implementation and development, testing, and debugging are, without a doubt, the activities that require the most time in the production cycle of an application. However, to make the application function perfectly on your machine or on a production server, the deployment of the application must be carried out.

Application deployment can be defined as the series of activities necessary to make an application or piece of software available for use. A standard procedure for deployment of a software system that is valid for all types of software neither exists nor is possible. In fact, it depends strictly on how the application has been created, and from the role that it will have in the production phase.

Indeed, in the application itself, different methodologies can be applied in the deployment phase. One methodology may be used to deploy the application to a public server, whereas a different may be needed for the same application to be deployed to a private internal server.

This chapter discusses all of the topics usually involved in the deployment phase of a Flex Web application.

Deployment Considerations

Each application is unique and, therefore, the deployment should be intended as a generic process to be personalized according to the relevant contexts, characteristics, and requirements.

The definition of an application deployment is a series of activities that are carried out to render the application available to users. These include the following:

  • Release - An activity that includes all the operations necessary to prepare the system for the transfer and installation of the necessary files. In this phase, it is also determined if the resources of the system on which the deployment will be carried out correspond to the requirements laid out at the beginning of the project.

  • Install - The phase in which the organization of the production environment begins and in which the deployment, with the necessary software required for the functionality of the final application, is carried out. At this point, the software (Web server, database engine, firewall, and so on) is installed and the necessary files are copied from the development environment to the deployment environment, and, finally, configured.

  • Activate - All of the activities that render the final application installed in the new functioning environment are included in this phase.

  • Deactivate - Includes the closure of services (Web server, application server, and so on) that make the application function. This is a phase of testing, the purpose of which is to see the behavior of the application after the shutdown and restart of the services.

  • Update - The process that allows for the installation of a new version of the application without repeating the entire process of installation. For a Flex application, this activity could be translated into the simple transfer of files from the production environment to the production environment.

  • Uninstall - Consists of the removal of the application and eventually of all of the software installed on the production environment that is no longer deemed necessary. The process of uninstall, even if it can seem quick and pain free, sometimes requires a lot more time than foreseen. If a clean and precise installation phase was not followed, it could be difficult to recover the list of dependent files resident in the system.

For Flex applications that do not use Flex Data Services (FDS), the deployment process can be reduced to a simple transfer of SWF files from the development server to the deployment server. When a project is created in the Flex Builder 2, the bin folder will contain the completed SWF file and the HTML file that are automatically created. You can access the folder’s structure of your Flex project under the Navigator view in the Flex Builder IDE, as shown in Figure 20-1.

Image from book
Figure 20-1: The Navigator view of the Flex project

By transferring these files onto a production server with public access, users will have complete access to the application. It goes without saying that they must have Flash Player 9 installed on the client to be able to use the contents.

Often, however, especially if you work in a medium-to-large company, the deployment process can involve different tasks and different people who have the duty of following the company procedures to guarantee the security of the systems. In the case of Flex applications that use files outside of the compiled SWF, it is also necessary to transfer all these files necessary to the production environment.

Images, audio, video, font, and Runtime Shared Libraries (RSLs) are all examples of external files that must exist on the production machine and must follow the eventual relative reference used for their recall by the application.

The History Manager allows the user to use the Back and Forward buttons on the browser to navigate inside the application. This feature is very useful, because it permits the user to navigate through different states of the application, as the user would usually do when navigating with a traditional HTML application.

The History Manager is comprised of two files inserted in the application’s wrapper HTML file, which is discussed later in this chapter. It is natively supported by Accordion and Tab navigator containers, which will track the state of the application and communicate these changes to the History Manager JavaScript classes. It is these classes that communicate with the browser controls and allow the browser’s Back and Forward buttons to control the state of the Flex application.

It is possible to disable the History Manager, and, therefore, remove the need to transfer the history.swf and history.js files. The Flash Player detection feature makes up part of the Detection Kit created by Macromedia (now Adobe) to detect (on the client) the correct version of Flash Player required to allow the application to run. Different techniques exist to detect the player. Among the most famous of these is the Unobstrusive Flash Objects, called UFO (http://www.bobbyvandersluis.com/ufo/), a DOM script that detects the Flash plugin and embeds Flash objects, and the SWFObject (http://blog.deconcept.com/swfobject/), which is a small JavaScript file used for embedding Adobe Flash content.

In the deployment phase, aside from paying attention to the transfer of all the dependent files and to all that they refer to, it is also necessary to consider the access to the data services. During the development of an application, the access to data services can have different security restrictions than when the application is moved to a production server. This could cause a failure of the deployed application to access external data. For this reason, during the “Activate” step described earlier, it is necessary to simulate the loading of the application outside the firewall and test all the run-time data access required to run.


Server-side and Client-side Caching

Before the deployment, it is necessary to clearly understand what happens at the moment when a request is made on the part of the client to an SWF file published on the server. The Web server returns the application to the client, which from that moment on resides locally on the client. It is for this reason that, when discussing Flex applications, developers should consider all ramifications of developing a desktop application. Even if you find yourself in the browser, the Flash Player plugin completely downloads all the contents of the SWF file locally.

Likewise, the Web server does not just respond to the request of the client. In fact, a Flex application can be made up of many files, which become involved during the development phase (images, SML data, RSLs) and that are all returned to the client in the form of a single SWF file. In fact, a single HTTP request made by the client for an HTML page will generate multiple HTTP requests, depending on all files that the application is made up of.

Therefore, giving priority to the HTTP responses, the contents of the HTML wrapper are first returned to the client, which loads the SWF file, then the references to the various JavaScript files (for example, History Manager). Following this, the contents of the MXML file using the FlexMxmlServlet (in the case in which the FDS is used and, therefore, the file becomes compiled by the server) are loaded. It accesses all of the resource files called by the main application that define and permit Flash Player to draw the graphic interface of the application and to load all of the data.

Following are the HTTP headers returned for the call of a simple Flex application:

 ACTION 1: User requests
http://www.comtaste.com/mp/mediaportal.html

*HTTP Request:*
GET /samples/test/source/tabnav_test.mxml HTTP/1.1
*HTTP Response:*
HTTP/1.0 200 OK, The HTML wrapper is returned

*HTTP Request:*
GET /samples/flex-internal?action=js HTTP/1.1
*HTTP Response :*
HTTP/1.0 200 OK, History manager JavaScript code is returned

*HTTP Request:*
GET /samples/test/source/tabnav_test.mxml.swf HTTP/1.1
*HTTP Response :*
HTTP/1.0 200 OK, The primary swf for the application is returned (~130 kb)

*HTTP Request:*
GET /samples/flex-internal?action=swf HTTP/1.1
*HTTP Response :*
HTTP/1.0 200 OK, A small history manager swf is returned (2.6 kb)

The FlexMxmlServlet defines the servlet wrapper for the Web.tier compiler. It is possible to change the settings at the servlet mappings inside the _app_root/WEB-INF/flex/web.xml file:

<servlet-mapping>
    <servlet-name>FlexMxmlServlet</servlet-name>
    <url-pattern>*.mxml</url-pattern>
</servlet-mapping>

The concept of a servlet was introduced by Sun. A Java servlet is a technology that provides Web developers with a simple, consistent mechanism for extending the functionality of a Web server and for accessing existing business systems. A servlet can almost be thought of as an applet that runs on the server side - without a face (http://java.sun.com/products/servlet/). In practice, a servlet is an object that receives requests and generates a response based on the request. Remember that FDS is, in effect, a Java application.

In this scenario, there are two methods of caching Flex utilities: server-side caching and client-side caching.

The SWF returned by the Web server to the client, by default, is cached at the first request and remains in the cache of the browser until the browser is closed. This feature could change, depending on the settings of the browser. Only in the reopening of the browser and, therefore, the successive request of the application, is the SWF file then reloaded by the server. This is the context for client-side caching.

Similarly, the context for server-side caching is when the Web server of the application server caches the SWF file on the first request. Caching is a feature enabled by default from Flex applications.

The advantage of inheriting this feature of caching is that it reduces the time required to download the application. However, it is often inconvenient (particularly in the testing phase) to obtain a version of the application from the local Flash Player cache.

The SWF file is loaded by the browser from the cache if the comparison between the date and time of the If-Modified-Since request header is the same as the Last-Modified response header.

In this case, the server believes that there are no changes within the application, and so it loads it from the cache. But what happens in the case in which updates have been carried out on the embedded images or on the Runtime Shared Libraries (RSLs) or on the external files? In these cases, on the browser, a version of the file with the references to the old images will be loaded.

Fortunately, it is possible to disable the client-side caching using various techniques. One of these is to set the HTTP header to prevent caching:

header("Expires: Mon, 29 Jul 1997 05:00:00 GMT");    // set date to a past date
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");  // always modified

header("Cache-Control: no-store, no-cache, must-revalidate");  // set the
Cache-Control to no-cache
header("Cache-Control: post-check=0, pre-check=0", false); // set the Cache-Control
to no-cache
header("Pragma: no-cache");                          // no proxy caching

These few lines of PHP code make it possible to prevent caching of the SWF file on the client machine.

Furthermore, it is possible to do the following:

  • Add the recompile=true querystring parameter to your request to force a recompilation of the application for FDS server-side compiling

  • Manually delete the SWF file from the browser’s cache directory because Flex caches generated SWF files and other assets

Tip

Using parameters in querystrings or changing the Flash Vars variables in the Flex wrapper does not recompile the FDS application.

On the other hand, as far as the configuration of the server-side caching is concerned, it is necessary to understand the mechanism that FDS uses on the server to determine if a more recent version of the file exists. FDS checks (at regular intervals) if the MXML file must be recompiled and, in such cases, substitutes the old file in the cache with the new SWF file. The information relative to the cache is contained in the flex_root/WEB-INF/flex/cache.dep file, which is checked by a file-watcher that monitors all dependent files defined in it. The file-watcher interval time is contained into the flex-webtier-config.xml file:

<file-watcher-interval>1</file-watcher-interval>

The value contained in this node is expressed in seconds. It determines the time that Flex waits before assessing the changes contained in the MXML file and in the correlated files. When FDS notices changes in the file, it recompiles the SWF of the application and, therefore, substitutes the cached SWF with the one that has just been created.

Having resolved matters on the side server of Flex, it is possible to use techniques to prevent server-side caching in FDS:

  • Configure server-side caching in the Web server or application server

  • Delete the cache.dep file in the /WEB-INF/flex/ directory

  • Set the value of the content-size property on code line 43 in the flex-webtier-config.xml (in the \flex\WEB-INF\flex\ directory) file to 0:

<cache>
<!-- content cache for SWFs, number of entries -->
<content-size>0</content-size>

<!-- force a check for validation of page freshness every XX seconds -->
<http-maximum-age>1</http-maximum-age>

<!-- check for changes to dependent files on disk if it hasn't been checked in XX
seconds -->
<!-- when production-mode is true, the dependent files are only checked once -->
<file-watcher-interval>1</file-watcher-interval>
</cache>

The content-size node contains the maximum number of files that FDS puts in the cache. When the set limit is reached (which is, by default, 10), FDS removes the least recently used files from the cache.

An important issue to remember about caching in Flex is the value assigned to the production mode. In fact, by setting the production mode as enabled, changes to compiled files are only recognized at server startup.

In the file flex-webtier-config.xml, it is possible to modify the value of the production-mode property:

<production-mode>true</production-mode>

When the production-mode is set to true, the FDS does not automatically recompile the application when the source files become updated or changed. Furthermore, not all the debug activities are flagged by the compiler. It is for this reason that, by default, the production-mode is set to false.

Ample space is dedicated to this topic later in this chapter.

To conclude the discussion of the caching of Flex, it is necessary to also consider fonts and glyphs. To reduce the loading time required, it could be useful to force the caching on the part of Flex to asset as fonts and glyphs on a Flex Data server.

By default, Flex puts a maximum number of fonts in the cache, but it is possible to check and change this value in the flex-config.xml file:

<fonts>
        <!-- The number of embedded font faces that are cached -->
        <max-cached-fonts>20</max-cached-fonts>
        <!-- The number of character glyph outlines to cache for each font face -->
        <max-glyphs-per-face>1000</max-glyphs-per-face>
        <!-- Defines ranges that can be used across multiple font-face
declarations. -->
      .... cut by author ....

      </fonts>

This value is to be used cautiously, because by setting a high value number of fonts that can be loaded in the cache, it is possible to occupy a lot of space on the disk, which, of course, depends on the dimension of every single TrueType Font (TTF) file.


Deployment Options

There is no option of standard deployment that could be applied indifferently to any Flex application. In fact, deployment options depend on the version of Flex that you have used in the creation of the application, and they vary from a Web application written using only Flex 2 SDK to an enterprise application that instead uses FDS.

Using Flex 2 SDK, it could be sufficient to migrate the SWF, HTML, and the dependent files from the development server or staging to that of production, to verify the functioning of the application and, therefore, render it publicly accessible to the final user.


RSL Deployment

In the case in which the application uses an RSL, it is necessary to copy the library to the deployment server and to use its RSL parameters on the Flex compiler to specify the directory that will contain the RSL at compilation time. The location that is specified is relative to the deployment location of the application:

  • web_root/myApp.swf - The Flex application is found in the root of the server.

  • web_root/assets/runtimeLibraries - This is the directory where you store the RSL file.

The parameter to pass from RSLs to the compiler is assets/runtimeLibraries/myFile.swf:

mxmlc -runtime-shared-libraries=assets/runtimeLibraries/myFile.swf

Or, you can directly input the parameter in the options of the internal compiler of Flex Builder, as shown in Figure 20-2.

Image from book
Figure 20-2: Flex Compiler property settings

If you prefer, in the flex-config.xml file, it is possible to indicate the path of the RSLs that are compiled from inside the application:

<!-- A list of runtime shared library URLs to be loaded before applications start.
-->
   <runtime-shared-libraries>
      <url> assets/runtimeLibraries/myFile.swf </url>
    </runtime-shared-libraries>

The RSL’s default node is obviously noted. This is also valid for the external-library-path option that permits you to specify the location of the SWC file:

mxmlc -external-library-path=assets/runtimeLibraries/myDataGrid

In this case, on the deployment server, a myDataGrid.swc must exist within the following path (assuming that the application is located in Web root):

web_root/assets/runtimeLibraries

In the flex-config.xml file, this option is found in the external-library-path node:

<external-library-path>
         <path-element>libs/playerglobal.swc</path-element>
         <path-element> assets/runtimeLibraries/myDataGrid .swc</path-element>
</external-library-path>
Tip

The playerglobal.swc file represents the external library that defines the base classes made available by Flash Player.

If, on the deployment server, the application you launch cannot find the folder or directly access the RSL file that will be used, you receive an error that blocks the application from compiling. For this reason, it is important to pay maximum attention to the paths inside the production server.

Flash Player Sandbox and Cross-Domain Consideration

Another delicate aspect for the deployment of an application that uses Flex 2 SDK is that of the target domain. The Flash Player sandbox does not permit for the loading of data from a different domain respective to that on which the SWF of the application is published. In this case, it is necessary to use the crossdomain.xml policy file. This file is XML-formatted and simply contains a list of domains that indicates to the server which could be used.

The crossdomain.xml file must be copied onto the root directory of the server that is serving the data. In the following scenario, the cross-domain file is located in the root directory of http://www.comtaste.com/crossdomain.xml and allows for access to Flash documents that originate from casario.blogs.com and www.augitaly.com:

<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="www.augitaly.com"/>
<allow-access-from domain=" casario.blogs.com "/>
</cross-domain-policy>

It is also possible to specify the IP address and the ports such as the domain in the <allow-access-from> node.

In some cases, it is necessary to be able to load assets that reside on the client’s local file system. To guarantee that a Flex application can access the assets in the local sandbox, the application must be in local-with-filesystem or local-trusted. It is, therefore, necessary to set a false option for the use-network compiler (which, by default, is set to true):

mxmlc use-network =false

The use-network option can also be set in the flex-config.mxml configuration file in the following node:

<!-- Enables SWFs to access the network. -->
<use-network>false</use-network>

However, the generic rule is that remote SWF files cannot load local SWF files, and local SWF files cannot load remote SWF files.


Deploying a Flex 2 SDK Application that Uses RSL

A scenario that you may come across in the deployment of an application that uses Flex 2 SDK is that of an application using an image reference relative to the application and to an RSL.

Let’s now reproduce this scenario, starting at the very beginning of the creation of a Flex Library Project in the Flex Builder 2. Select File Image from book New Image from book Flex Library Project (Figure 20-3). Create a new project to which you assign the name Flex_2_RSL.

Image from book
Figure 20-3: Creating a Flex Library Project in Flex Builder 2

Now create an MXML component with the name myVideo.mxml, with a VideoDisplay control setting the following properties:

source="http://88.149.156.198/develop/mediaportal/upload/videos/test.flv"
autoPlay="false" bufferTime="0.5"
maintainAspectRatio="false"
click="myVid.play();"
width="100%" height="100%"
x="0" y="0"

The final code for myVideo.mxml will be the following:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Panel title="Video killed the Radio star"
  width="285" height="222" layout="absolute">

   <mx:VideoDisplay id="myVid"
           source="http://88.149.156.198/develop/mediaportal/upload/videos/test.flv"
           autoPlay="false" bufferTime="0.5"
            maintainAspectRatio="false"
            click="myVid.play();"  width="100%" height="100%" x="0" y="0"/>
</mx:Panel>
 </mx:VBox>

To export the library as an SWC file, you must add and define the elements that will be included in the compilation phase of the project (custom components, ActionScript classes, and other assets) by selecting them from the Flex Library Build Path window, which is reachable from Project Image from book Properties Image from book Flex Library Build Path.

As shown in Figure 20-4, in the Tab classes, you select the checkbox of the component myVideo.mxml, because this is the only element that you want to include in the SWC file.

Image from book
Figure 20-4: Adding and defining elements for the compilation phase

Before having it compile the SWC file set the Output Folder to assets. Therefore, the structure of the Flex Library Project is the following:

Flex_2_Deploy_Rsl
        |
        |--.     settings
        |--     assets
        |.actionScriptProperties
        |.flexLibProperties
        |.project
        |myVideo.mxml

Click OK, and Flex Builder automatically compiles the library within the assets folder (Figure 20-5). This operation takes place automatically because the Build Automatically option of Flex is active.

Image from book
Figure 20-5: Compiling the library within the assets folder

You have created an RSL to import into a Flex project. At this point, you create the application by defining a new project in the Flex Builder workspace:

  1. Create a Basic Flex Project: File Image from book New Image from book Flex Project.

  2. Assign a name of Flex_2_Deploy.

  3. Terminate the operation by clicking Finish.

At this point, you import the SWC file that you intend to use in the project, adding it to the library path. Flex provides you with three different methods of importing an SWC in a project:

  • Add SWC - Directly adds the SWC file.

  • Add SWC Project - Adds an SWC Library Project.

  • Add SWC Folder - Allows a folder containing SWC files to be added.

For this example, you will use the Add SWC Project method. Therefore, from the Project Image from book Properties Image from book Flex Build Path menu, you add a library project by clicking the Add Project button. You select a single listed Library Project (the just-created Flex_2_Deploy_Rsl) and click OK (Figure 20-6). The Library Project is added in the Library Path.

Image from book
Figure 20-6: Selecting the Library Project

There are different options for the method with which an SWC should be used by the application:

  • Merge into Code - In the compilation phase, the SWC library is added to the SWF file. This, however, involves an increase in size of the final application.

  • External - This allows you to maintain the SWC file outside of the compiled SWF file.

  • Runtime Shared Library - The SWC file is used at run-time like a shared library, which is a useful option when more projects will be used by that library component.

From the Project Image from book Properties Image from book Flex Build Path menu, you select the Library tab and expand the Flex_2_Deploy_Rsl project. Double-click the Link Type option and set the following options:

  • Link Type - Runtime Shared Library (RSL)

  • RSL URL - Assets/Flex_2_Deploy_Rsl.swf

Select the “Auto Extract SWF to RSL URL” option.

The importation method of the SWC file that you have used is, therefore, Runtime Shared Library. This method is also called dynamic linking.

You leave the options of Flex Builder for extracting the SWF file in the defined folder in the RSL URL selected. With these simple operations, your library will be automatically included in the View Component (visible when Flex Builder is in Design mode).

In this view, a custom folder will exist that, when opened, will contain the Library Component my Video. You also import the images that have intentionally been put in the assets folder, using relative reference for the property source:

<mx:Image source="assets/logo.gif" width="96" height="96" horizontalCenter="0"
verticalCenter="-124"/>

You import the library into the main application by dragging it from the Component panel and obtaining the following code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
     xmlns:mx="http://www.adobe.com/2006/mxml"
     layout="absolute"
     xmlns="*">
     <mx:Image source="assets/logo.gif" width="96" height="96" horizontalCenter="0"
verticalCenter="-124"/>
     <myVideo verticalCenter="0" horizontalCenter="0" />

</mx:Application>

Once the project has run, the Flex_2_Deploy.mxml becomes compiled in the bin folder, together with the RSL compiled as Flex_2_Deploy_Rsl.swf in the assets folder.

The files to be transferred are those indicated in the table that follows. However, the structure of the folders on the deployment server, as shown in Figure 20-7, must be respected.

Image from book
Figure 20-7: Folder structure on the deployment server

Now comes the deployment phase of the application on the production server, during which you transfer the SWF file and all of the dependent files.

The following table lists all of the standard files that usually must be deployed on the server for the applications that use Flex 2 SDK.

Open table as spreadsheet
Application | Files | Description
History Manager | history.swf, history.js | Handles the Back button of the browser
Player Detection | playerProductInstall.swf, AC_OETags.js | Detects client browser type
Main Application | myApp.html, myApp.swf | Files containing the application itself


Compiling for Deployment

Compiling for the deployment is different from compiling for the developing and testing phase. Many options and characteristics of compilation are very useful in the development phase of a Flex application, but lose significance in the production phase of the application. Flex makes three different application compilers available:

  • Flex Builder project compiler - This is the compiler used in Flex Builder.

  • MXMLC command-line compiler - This is the compiler that is followed by using the command line and to which various parameters become passed for the compilation.

  • Web-tier compiler - This is a set of servlets that are followed by the J2EE application server, which passes the requests to the MXML file at the servlet container, which compiles SWFs on the fly, which is then sent back to the application.

All three of the application compilers use a set of options that are very similar, and, for this reason, the compilation options for the deployment phase are also very similar.

Because the compilation options for the deployment are often used for many projects, it is possible to save time by using a configuration file to apply to each deployment. The configuration file is an XML file containing the options that can be passed to the various application compilers (MXMLC command-line compiler, Flex Builder project compiler, and Web-tier compiler).

Flex uses the flex-config.xml default configuration file that has been discussed previously.

This section contains just a few of the options made available by the compiler. This discussion concentrates on the options that usually come into play in the deployment phase, and that are summarized in the following table.

Open table as spreadsheet
Options | Description
accessible | Accepts true and false values. Allows you to enable or disable the accessibility features of the Flex application. Default value: false.
benchmark | Accepts true and false values. Prints the compilation time. Default value: true.
contributor | Accepts a string. Sets the metadata in the SWF file.
creator | Accepts a string. Sets the metadata in the SWF file.
date | Accepts a string. Sets the metadata in the SWF file.
title | Accepts a string. Sets the metadata in the SWF file.
description | Accepts a string. Sets the metadata in the SWF file.
language | Accepts a string. Sets the metadata in the SWF file.
publisher | Accepts a string. Sets the metadata in the SWF file.
debug | Accepts true and false values. Generates a debut file in SWF format. Default value: true (false for the mxmlc compiler).
headless-server | Accepts true and false values. Allows you to set the headless implementation of the compiler.
default-script-limits | Accepts the values max recursion depth and max recursion time. Indicates the depth of the Flash Player call stack and the time in seconds before the Flash Player stops.
incremental | Accepts true and false values. Allows for the incremental compilation, which reduces the compilation time.
production-mode | Accepts true and false values. Used for Flex Data Services when the application is live on a public-facing server. Default value: false.

Creating a custom configuration file means writing an XML block using tags that are used by the compiler. Every configuration file must begin by defining an XML declaration tag and a root tag, <flex-config>, followed by a <compiler> tag, which contains the options that you intend to send to the compiler.

Begin by writing the file in the program that you created earlier in this chapter. Assign to that file the name Flex_2_Deploy-config.xml.

The frame of the configuration file is as follows:

<?xml version="1.0"?>
<flex-config xmlns="http://www.adobe.com/2006/flex-config">
   <compiler>

</compiler>
</flex-config>

You begin by defining the values for accessibility, the benchmarks, and the metadata, useful for the search of search engines:

<accessible>true</accessible>
<benchmark>false</benchmark>

<metadata>
  <title>Flex 2 Professional</title>
  <description>Compiling for deployments</description>
  <date>Dicembre 2006</date>
  <publisher>Comtaste</publisher>
  <creator>Marco Casario</creator>
  <language>EN</ language>
</metadata>

You insert the settings for the debug options and the default-script-limits:

<debug>false</debug>
<default-script-limits>
     <max-recursion-depth>1200</max-recursion-depth>
     <max-execution-time>40</max-execution-time>
</default-script-limits>

You must now deal with the incremental option, which allows you to check (through the compiler) the changes to byte code between the different revisions of the re-compiler (therefore, only the sections that are changed). Considering that the default option is set to true, you will often want to disable this option in the deployment phase. You write it in the configuration file as follows:

<incremental>false</incremental>

In this way, you also obtain a reduction of the memory used by the FDS Web-tier compiler. If the Web-tier complier incremental option is used, it is found in the flex-webtier-config.xml file.

Finally, you should consider the properties of the headless server and production mode.

A headless server is a server that doesn’t have a graphical subsystem (that is, a graphics card and monitor). Usually, these are servers that allow you to maximize the use of memory and of the system itself (Unix or Linux).

When you follow the deployment of a Flex application on a server of this type, it is necessary to set a true option:

<headless-server>true</ headless-server>

This communicates to the Flex server that SVG fonts and images in a nongraphical system should be used. If you want to delve deeper into this argument, you should read following TechNote from Adobe: “Configuring non-graphics-enabled servers TechNote” (http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=tn_19252).

The production-mode option operates exclusively like a Web-tier compiler and compiles an FDS application like MXML and ActionScript files. Setting production-mode to true will automatically set all of the debugging options to false and the compiler will, therefore, not generate any information from the debug:

<production-mode>true</production-mode>

The configuration file, in the end, will look as follows:

<?xml version="1.0"?>

<flex-config xmlns="http://www.adobe.com/2006/flex-config">
<compiler>
<accessible>true</accessible>
<benchmark>false</benchmark>
<metadata>
<title>Flex 2 Professional</title>
<description>Compiling for deployments</description>
<date>Dicembre 2006</date>
<publisher>Comtaste</publisher>
<creator>Marco Casario</creator>
<language>EN</ language>
</metadata>

<debug>false</debug>
<default-script-limits>
     <max-recursion-depth>1200</max-recursion-depth>
     <max-execution-time>40</max-execution-time>
</default-script-limits>
<incremental>false</incremental>
<headless-server>false</ headless-server>
<production-mode>true</production-mode>
</compiler>
</flex-config>

To be able to send the file to the compiler, you can simply add the following parameters to the command line of the compiler:

-load-config+=Flex_2_Deploy-config.xml

Using the += operator, the configuration file is loaded in addition to the flex-config.xml file and not in its place.

The mxmlc compiler can use a local configuration file. This is a configuration file that resides in the same folder as the application and that shares with it the same name. If, for example, the Flex application is named myCoolFlexApp.swf, Flex will automatically search for a configuration file with the name myCoolFlexApp-config.xml.

Tip

The Flex Builder project compiler does not use the configuration file flex-config.xml, but instead uses internal settings. It is possible, however, to send a custom configuration file to the compiler using the load-config option sent to the Additional Compiler arguments field.

To conclude the discussion on the compilation phase of deployment, it is certainly necessary to mention the possibility of yielding the source code of the application itself, which is also available in the deployment phase. You will be able to share and render as Open Source the source code of your application to the community. To render this feature active, simply set (from code) the property viewSourceURL and send the URL that will contain the source code for the application.

In Flex Builder the Publish Application Source is set from the Project Image from book Publish Application menu.


Troubleshooting Tips and Common Deployment Problems

At this point, it should be apparent that no fixed steps apply in the deployment phase of an application.

It is possible, however, to outline the guidelines to follow for different types of application that will be developed. This section provides a checklist of problems that can be encountered in the migration of a development project to the deployment environment.

Asset and Dependent Files

A Flex application can be modularized in multiple MXML files, ActionScript classes, and RSLs. Further more, images and audio and video elements loaded in run-time can be used. In these scenarios, it is essential to respect the structure of directory of the application, replicating exactly the one that is used in the development environment.

Errors in loading the RSL, of images, or of ActionScript classes not found can be resolved by paying attention to the transfer of the files.

To reduce the possibility of error, make a list of all the external resource files and the path in which they should be found, as shown in the following table.

Open table as spreadsheet
Name | Type | Location
logo.gif | Image | assets/logo.gif
myVideo | RSL | Assets/ Flex_2_Deploy_Rsl.swf
History.js | Wrapper | Web_root

This type of table allows you to have a reference of all the external resources used in the application and how they can be found.

Run-time Data Access

In the building and testing phase of an application, you may come across a corporate firewall, which, of course, has its own security restrictions.

These settings can be much more restricting to the final user who is outside the firewall. This common change of location could cause more than a few problems for the project. It could make that part of the application impossible to access from the outside, causing the access attempts (to data services, to resources found on the application server, or the readdressing on the part of the proxy server) to fail.

Therefore, it is fundamental to test all of the run-time data access functions once the deployment phase has been carried out. It can also be useful to make a list of the following:

  • All the IP addresses of the server that the application can access

  • IP and DNS of the Web service proxy of FDS

Proxy Server

The definition given by Wikipedia of proxy server (http://en.wikipedia.org/wiki/Proxy_server) is simple and effective:

A proxy server is a computer that offers a computer network service to allow clients to make indirect network connections to other network services. A client connects to the proxy server, then requests a connection, file, or other resource available on a different server. The proxy provides the resource either by connecting to the specified server or by serving it from a cache. In some cases, the proxy may alter the client’s request or the server’s response for various purposes.

When the Flex applications or the proxy of the FDS handle a request to data services, it is necessary to ensure that, in the future, it will be possible to access the same data services of the deployment environment through the proxy.

The proxy service contains a list of the destinations of the Web service and the HTTP service. The file in which these options are configured is the flex-proxy-service.xml file.

The following are two examples of a configuration to declare an HTTP and a SOAP proxy adapter destination:

<destination id="myHTTP">
    <properties>
        <!-- The endpoint to the http proxy service -->
        <url>http://www.comtaste.com/com/services/myservlet</url>

        <!-- http endpoints -->
        <dynamic-url>http://www. comtaste.com/com/services/*</dynamic-url>
    </properties>
</destination>

<destination id="myWebService">
    <properties>
        <!-- The location of the wsdl -->
        <wsdl>http://{server.name}/flex/myService.cfc?wsdl</wsdl>

        <!-- The soap endpoints -->
        <soap>http://{server.name}:*/flex/echo</soap>
    </properties>

 <adapter ref="soap-proxy"/>
</destination>

It is also possible to define an external proxy before accessing the Internet by defining the IP of the server, the username, and the password:

<external-proxy>
            <server>10.10.10.10</server>
            <port>3128</port>
            <nt-domain>mycompany</nt-domain>
            <username>flex</username>
            <password>flex</password>
 </external-proxy>

Accessing Server-side Resources from Different Domains

Flash Player 7 introduced a security sandbox that implemented rigid restrictions on loading data accessed via the exact same domain from which a movie was loaded. If a Flex application tries to access a URL from outside of the exact residence domain of the SWF, the request will fail.

A practical example might be that an application published on www.domainA.com requests data or an RSL from an SWF on the www.domainB.com domain. In this case, the operation would fail.

Fortunately, however, by creating a cross-domain policy file and copying it onto the destination server (www.domainB.com), it is possible to indicate to the server which data and assets may be needed by the SWF caller. A cross-domain policy file is an XML file that allows access from your application’s domain and is installed on the Web server hosting the RPC service.

Follow these steps to create a crossdomain.xml file:

  1. With Flex Builder 2 (or any other text editor) create a new file.

  2. Assign to it the name crossdomain.xml and pay attention to also declare its XML extension. Add the following XML code to the file:

    <?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="www.yoursite.com" />
<allow-access-from domain="*.yoursite.com" />
</cross-domain-policy>

The file is ready to be transferred to the root directory of yoursite.com (that is, the root directory of the server that is serving the data). It is also possible to insert IP addresses in the allow-access tag:

<allow-access-from domain="190.216.1.20" />

Or you can use the * symbol in the domain attribute to allow every domain.

Tip

Flash Player does not perform DNS resolution.

The Flash Player ignores any policy file that is served using a cross-domain redirect. For example, if a Flash Player request for http://www.mysite.com/crossdomain.xml redirects to http://elsewhere.mysite.com/crossdomain.xml, Flash Player ignores that policy file. Ensure that you do not use cross-domain redirects to serve policy files. (You can use redirects within the same domain.)


Deploying a Flex Data Service Application Under Tomcat

Developing and deploying an application using Flex Data Services (FDS), to a large extent, is very similar to developing and deploying applications that use Flex 2 SDK. However, FDS offers greater functionality to the developer, and being a server-side application, it must be installed under a Java 2 Enterprise Edition (J2EE) application server. This involves a more complicated development phase, because it involves the use of more advanced and complex functions and a deployment phase that involves more tasks.

For example, FDS offers two different methods for the deployment of an application. One method is common to the projects that use Flex 2 SDK: the deployment of a single compiled SWF file. The second method instead uses the Web-tier compiler, and deploys all the MXML and ActionScript files that together form the application.

At each HTTP request, the Web-tier compiler will recompile the application.

Furthermore, for projects that use FDS in the deployment phase, two delicate aspects (which can take up a lot of time) are those relative to configuration and to security.

Being large applications (enterprise applications) that use remote data services, the security aspect can be crucial.

During the installation phase, FDS offers the option of using the JRun Web server (Figure 20-8). Adobe advises that this Web server should be used, installed by default as a development server, and not as a production server. In the case in which JRun is used as a Web server, the context root will have the following URL:

http://localhost:8700/flex/
Image from book
Figure 20-8: Selecting the J2EE Web application option

However, usually in the deployment phase, a compliant Web server J2EE (on which FDS and the application to be run will be installed) should also be installed on the production machine, as shown in Figure 20-8.

In this section, you see how to carry out the deployment of an application using the FDS under Tomcat. Tomcat is a servlet container. A servlet container controls the servlets that are deployed within the Web server. It is also responsible for forwarding the requests and responses for them.

Tomcat is part of the Jakarta project and is Open Source. You can find more detail on this topic by visiting the Jakarta site (http://jakarta.apache.org) and the Tomcat site (http://tomcat.apache.org/).

This discussion does not go into the installation of Tomcat. For this, you can refer directly to the official documentation (http://tomcat.apache.org/tomcat-5.5-doc/index.html) and follow the instructions. However, some advice should be followed to ensure the correct functioning of FDS.

First, Tomcat is, in effect, a Java application and, for this reason, you must have the Java Development Kit (JDK) installed on the machine. You can download this from the Sun Web site (http://java.sun.com/j2se). Note that it is not sufficient to have Java Runtime Edition (JRE) installed on the machine. To process the Java Server Pages (JSPs), Tomcat requires a compiler that is included only in the JDK.

The Windows operating system should automatically define the environment variable %JAVA_HOME% during the installation of the JDK.

The path contained in %JAVA_HOME% is required to load the Java SDK executable files from any directory without referring to the complete path. You can refer to the installation procedure, as illustrated on the Sun Web site:

http://java.sun.com/j2se/1.4.2/install-windows.html

To install Tomcat, leave the options as default. For extra security, you could change the installation path from drive:\Program Files\Apache Software Foundation\Tomcat 5.5 a to drive:\ProgramFiles\Apache Software Foundation\Tomcat_5_5, because the spaces can cause problems in some plugins.

Once the installation is completed, you can start the Web server and test that everything functions by launching the following URL, as shown in Figure 20-9:

http://127.0.0.1:8080/
Image from book
Figure 20-9: Starting the Web server

The directory structure of Tomcat is not complex. Following are the folders involved in an FDS application:

  • bin directory - This directory contains the executable files used to start and stop Tomcat.

  • conf directory - This is the Tomcat configuration directory.

  • logs directory - Contains all the logs.

  • webapps directory - This is the default directory for Web applications. This is the directory where you will copy the Web application archive (WAR) Flex files.

Now that you have installed Tomcat on the deployment machine, you can now move on to the installation of FDS and follow its deployment onto the Web server. As mentioned, FDS is a J2EE Web application and can be installed with the integrated JRun or as J2EE Web applications under a Web server. In the first case, you should install only in the development phase. For the deployment on the production environment, you should install the FDS J2EE as a Web application.

At this point, the following folders will be created in the fds2 directory:

  • Files - The installation root that includes the WAR files (flex.war, samples.war, and flex-admin.war)

  • flex_sdk_2 directory - Contains the Flex Framework, framework source code, and command-line compilers

  • resources directory - Contains installers for Flash Player 9 and the files used for the HTML wrapper, clustering, Hibernate, and so on

  • UninstallerData directory - Contains the uninstaller

To complete the installation on the deployment environment, you must copy the three WAR files taken from the Files folder of the Fds2 directory in the webapps folder of Tomcat (yourDrive:\ProgramFiles\Apache Software Foundation\Tomcat_5_5\webapps). WAR is a ZIP file used to distribute a set of Java classes.

The Flex.war is basically a Web application directory that contains Java classes, filters, and listeners to interpret the Flex applications written in MXML and ActionScript.

By copying the three WAR files into the webapps of Tomcat, the Web server automatically recognizes the file, unpacks it, creates an expanded Web application, and deploys it.

There are now three other folders in the webapps: Flex, Flex-admin, and Samples.

You can now test the correct installation and functioning of the FDS by launching the examples contained in the Samples folder at the following URL (Figure 20-10):

http://127.0.0.1:8080/samples/
Image from book
Figure 20-10: Launching the examples

If your FDS application used the DataService feature, Tomcat needs the Java Open Transaction Manager (JOTM) package installed and correctly configured. JOTM is a JTA-compliant transaction manager that implements the Extended Architecture (XA) protocol. It provides full distributed transactions support for Enterprise Java Bean (EJB) or servlet containers projects. You can download the latest version of JOTM at the following URL:

http://forge.objectweb.org/projects/jotm/

Unzip the file and copy the JAR files from jotm-root/lib to tomcat-root/common/lib. All you must do is configure the definition of the Transaction in the <Context> node of the application configuration file.

<Transaction factory="org.objectweb.jotm.UserTransactionFactory"
 jotm.timeout="60"/>

Restart the Apache Tomcat service, and you have now followed all of the steps necessary for the deployment of FDS under Tomcat on a production machine.

Tip

To delve deeper into the installation procedure of FDS on Tomcat, see the Adobe support documentation at http://www.adobe.com/support/documentation/en/flex/2/install.html#tomcat .

At this point, the production machine phase is ready to host the Flex application. During the deployment phase of a project, it is possible to use two different directory structures that define the location of the application:

  • In the FDS Web application

  • In its own Web application

Let’s begin with the publication of the project in the directory of the FDS Web application.

In the flex folder in webapps (under Tomcat), there is a folder called WEB-INF, which is the root directory for the Flex applications. In this directory, you will copy all the files necessary for the application (SWF, MXML, ActionScript, CSS, JSP, and so on), as shown in Figure 20-11.

Image from book
Figure 20-11: Copying all the necessary files

In the flex folder, you can create as many folders as you have applications using folders for external elements defined in the application’s root directory. In the case in which external assets are shared or sharable by different applications, it is convenient to create a folder to contain them, established on the main root.

It is best practice to copy all of the shared files (images, MXML, ActionScript, and RSLs) into the yourDrive:\Program Files\Apache Software Foundation\Tomcat_5_5\webapps\flex\WEB-INF\flex\user_classes folder, which automatically includes all the applications that you have developed in the source path. In the case in which the C files become copied in different directories, the path must be specified in the <library-path> node in the flexconfig.xml file (or sent as parameters to the compiler):

Tomcat (or J2EE web server)
       | Flex
            |-- myApp_1
            | -- localAsset_1
            |-- myApp_2
            |-- my App_3
            |-- sharedAssets
            | WEB-INF

The second approach to creating a directory structure for the application is to isolate the application from the FDSWeb application. Following this approach, it is more convenient to distribute the application separately:

Tomcat (or J2EE web server)
       | Flex
          | WEB-INF
       |-- myApp_1
          | -- localAsset_1
       |-- myApp_2
       |-- my App_3
          |-- sharedAssets

The following table shows the contents of the Flex directory in webapps (taken from the official Adobe Flex documentation).

Open table as spreadsheet

Directory

Description

/flex

This is the root directory. It contains the WEB-INF directory.

/WEB-INF

The web.xml configuration file is hosted into this folder. If you use other Web applications, this directory could contain other deployment descriptors.

/WEB-INF/flex

Contains the following folders:

  • jars - Contains all the JAR files

  • libs - All the SWC files used by Flex

  • locale - SWC localization resource file

  • themes - Contains the haloclassic.swc file for the look and feel of Flex components

  • user_classes - This is the folder where you put your custom classes, SWC files, and components

Having defined the directory structure of the application and having executed/carried out the transfer from the development environment to the deployment environment, you must configure FDS on the new machine to complete the deployment process.


Configuring for FDS

An application developed using the advanced functions of FDS requires the configuration of different external files: Remoting Service, Proxy Service, Message Service, and Data Management Service. These different configuration files are the same files that were configured on the machine in the development phase.

The configuration of the destinations is the most basic task in the configuration of FDS. Assigning an unambiguous ID to a service (named service) and using it in the MXML page allows Flex to have information on how some named services must be thought of as an authenticated service.

Usually, it is sufficient to simply transfer the files from one environment to the other, overwriting he original files on the deployment environment. The folder in which these files are located is the yourDrive:\Program Files\Apache Software Foundation\Tomcat_5_5\webapps\flex\WEB-INF/flex directory of your FDS Web application (Figure 20-12).

Image from book
Figure 20-12: Location of files

The configuration files involved in the configuration phase obviously depend on the features that have been used in the FDS application. One important aspect in the configuration of the files that can differ greatly between the development phase and the deployment phases is relative to the level of security you want to set on the application.

In the development environment, you usually do not apply a security constraint because you are not interested in restricting access to a group of privileged users by means of authentication. However, this changes in the deployment environment, where access to an application must not be open to everyone, but must be accessible only by the users authorized to do so. Flex does not automatically apply a method of authentication or authorization to users. For this reason, it is necessary to apply security constraints in a destination definition in the FDS configuration in the deployment environment.

Tip

A Remote Procedure Call (RPC) service destination is the object or the service to which you connect through the classes RemoteObject, WebService, or HTTPService.

Through these configurations, it is possible to authenticate the use of a remote service like RemoteObject and to permit only authorized users to make use of the service. To restrict access to a privileged group of users, you apply the rules of security constraint in a destination definition in the FDS configuration file.

There are two methods of configuration: inline and global. The inline method is applied in the destination for which it should be valid, and by configuring the security-constraint property as follows:

<service>
<destination id="myEmployee">
<properties> <source>classes.comtaste.Employee</source>
 <scope>application</scope>
</properties>
<security>
<security-constraint>
<auth-method>Custom</auth-method>
<roles>
<role>DestinationUser</role>
 </roles>
</security-constraint>
 </security>
</destination>
</service>

In this case, the security-constraint is valid only for the destination with id="myDest".

The method of global declaration allows you to share more destinations with the same security settings:

<service>
<destination id="myEmployee">
<properties> <source>classes.comtaste.Employee</source>
 <scope>application</scope>
</properties>
 <security>
<security-constraint ref="securedUser"/>
 </security>
 </destination>

<destination id=" myEmployee_2">
<properties> <source>classes.comtaste.Employee_2</source>
 <scope>application</scope>
</properties>
<security-constraint ref="securedUser "/>
 </destination> ...
 </service> ...
<security>
<security-constraint id="securedUser ">
 <auth-method>Custom</auth-method>
<roles>
<role>DestinationUser </role>
</roles>
</security-constraint>
 </security>

In this example, the two destinations, myEmployee and myEmployee_2, refer to and share the same security-constraint, securedUser, which is defined outside of the two destinations.

The configuration phase of FDS is obviously crucial to the correct functioning of the application and attention must be paid when configuration files are transferred from the development environment to the deployment environment. Routing out and correcting malfunctions caused by incorrect configuration can be time-consuming.


Creating a Wrapper

Flex applications that use only Flex 2 SDK instead of FDS are compiled in an SWF file in the end. The client loads the SWF file of the Flex application in the HTML file on the browser, which imports the SWF and the JavaScript files to support the History Manager and the Flash Player detection. These files are together defined as the wrapper.

Flex offers different wrappers, ready to use in the compilation phase. In Flex SDK 2\resources\html-templates there are six HTML templates that can be implemented and that support different features:

  • Client-side-detection - Includes the index.template.html and AC_OETags.js files. These provide support for the detection of the Flash Player on the client and load alternative contents if the browser does not find the required version.

  • Client-side-detection-with-history - Includes the index.template.html, AC_OETags.js, history.js, history.swf, and history.htm files. In contrast to the preceding template, this adds support to the History Management in the history.js and history.swf files.

  • Express-installation - Includes the index.template.html, AC_OETags.js, and playerProductInstall.swf files. This template is used to support the Express Install, which is discussed in detail later in this chapter.

  • Express-installation-with-history - Includes the index.template.html, AC_OETags.js, history.js, history.swf, history.htm, and playerProductInstall.swf files. Aside from providing the support of Express Install, this also adds History Management.

  • No-player-detection - Includes the index.template.html and AC_OETags.js files. This basic template offers the option of simple importation of an SWF file using an external JavaScript.

  • No-player-detection-with-history - Includes the index.template.html, AC_OETags.js, history.js, history.swf, and history.htm files. The importation of the SWF file adds History Management.

These templates represent the starting point for creating a custom wrapper for Flex applications.

Migrating and Transferring Files

In the deployment phase of a project, all the files imported and used from the wrapper must be migrated and transferred onto the deployment environment, respecting the location of every file. Flex Builder and FDS generate a wrapper by default that includes the support of History Management and of Express Install. The features of the wrapper created by default can, however, be changed and configured to suit individual requirements.

Flex Builder 2 displays these settings in the Flex Compiler dialog box. Following are the options that are possible to set:

  • Generate HTML wrapper file - By disabling this checkbox, the file wrapper will not be generated. Flex Builder will only compile the SWF file of the application.

  • Detect Flash Player version - In these fields, you can specify the exact version that should be checked and verified on the clients. It is also possible to disable this option to choose to not use the support of the detection of Flash Player.

  • Use Express Install - Provides support for Express Install.

  • Enable history management (browser Back button) - Provides support for History Management.

When you run the project and Flex Builder compiles the application, it reads the settings for the HTML wrapper and inserts the wrappers generated in the bin folder of the project. All the file templates necessary for the creation of the wrapper are contained in the html-template that is established at the project level in Flex Builder. If you manually modify these files in the template (for example, inserting the TITLE tag in the HTML page), these changes will be saved in the wrapper generated.

On the other hand, the FDS applications that use the Web-tier compiler compile the MXML file requested by the client on the fly. To see the wrappers generated by FDS, open the HTML file resulting from the call with the view source user of the browser and save it. In this way, it is obviously not possible to save the contents of all the other files involved in the HTML wrapper. To see the contents of these files, you can do the following:

  • Use a browser toolbar such as the Web Developer Extension for Firefox, which permits you to see and save all the contents used in an HTML page.

  • Use a sniffer, a program that traces the request and response flow of HTTP traffic. In the Flex _istall_dir/jrun4/bin folder, there is a TCP Monitor application, which is a Java application that listens to a port and passes this request to the resource on the target port.

Defining Features

By modifying the settings in the flex-webtier-config.xml file, it is possible to define the features supported by the wrapper generated by the FDS compiler. Following are the nodes in the XML file that become involved in the creation phase of the wrapper:

    <!-- enable history management (back button) -->
    <use-history-management>true</use-history-management>

    <flash-player>
        <!-- enable/disable player detection -->
        <use-player-detection>true</use-player-detection>
        <use-express-install>true</use-express-install>

         <!-- required major player version -->
        <required-major-version>9</required-major-version>
        <!-- 'dot' release of the required player -->
        <required-minor-version>0</required-minor-version>
        <!-- minor version revision number of the required player -->
        <required-version-revision>0</required-version-revision>

        <alternate-content-include><![CDATA[This content requires the Adobe Flash
Player 9. <a href=http://www.adobe.com/go/getflashplayer/>Get
Flash</a>]]></alternate-content-include>

    </flash-player>

The deployment phase of a flex-webtier-config.xml file must be transferred to the production server.

When using the Web-tier compiler with FDS, it is also possible to directly access the Flex application pointing directly to the compiled SWF file. In this way, the server does not generate the HTML wrapper files, but only carries out the compilation of the MXML file in SWF.

To force the request of an MXML file without the wrapper, simply add .swf to the request string, as shown below:

http://www.yourdomain.com/myFlexApp.mxml.swf

In this way, however, the possibility of managing History Management, Express Install, and any type of communication between the Flex application and JavaScript will be omitted.

For applications that provide for the use of ExternalInterface API or of Flex/AJAX Bridge, it is not necessary to make the request to the server without the use of the wrapper.

The final compiler to discuss is the mxmlc.

mxmlc Compiler

The mxmlc command-line compiler does not automatically generate a wrapper. It is necessary to manually write it, taking as an example one of the templates found in the Flex SDK 2\resources\html-templates folder. When you launch mxmlc for the compilation, the wrapper will be sent as an advanced option to compile the SWF and the relative HTML wrapper.

Aside from using the Flex wrapper template, it is possible to create its own custom wrapper. The creation of a wrapper provides for the production of an HTML file composed of one <script> block (which imports the JavaScript file and defines the <object> and <embed> tags to include the SWF file) and a <noscript> block (which defines the code for all the browsers that do not support JavaScript).

Begin by defining the code in the HTML file:

<html>
<body>
<script src="embedFlash.js"></script>
<noscript>
<object id=' Flex_2_Deploy ' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
<embed name=' Flex_2_Deploy ' pluginspage='http://
www.macromedia.com/shockwave/download/index.cgi
?P1_Prod_Version=ShockwaveFlash' src='Flex_2_Deploy.swf' height='100%'
width='100%'/>
</object>
</noscript>
</body>
</html>

Immediately after the declaration of the root tag in the first HTML page, a JavaScript file is imported:

<script src="embedFlash.js"></script>

And, immediately after that, the imported SWF file, using both <object> (for Internet Explorer) and <embed> (for Netscape), is inserted in the <noscript> tag:

<noscript>
<object id='Flex_2_Deploy' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
<embed name=' Flex_2_Deploy ' pluginspage='http://
www.macromedia.com/shockwave/download/index.cgi
?P1_Prod_Version=ShockwaveFlash' src='Flex_2_Deploy.swf' height='100%'
width='100%'/>
</object>
</noscript>

The code in the <noscript> tag is required to guarantee the loading of the Flex application even for the browsers that have disabled JavaScript in their preferences. If JavaScript is disabled, all communication between the application and JavaScript using the ExternalInterface API class will not work. For this reason, messages, or the loading of appropriate content to advise the users that the application they are about to load will be limited in some functions, are usually inserted in this tag.

The JavaScript file embedFlash.js simply contains a series of document.write() requests that write the <object> and <embed> tags for the importation of the application. This same <object> and <embed> block defined in the HTML page is used in the JavaScript file:

document.write("<object id='Flex_2_Deploy' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000'
codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=
9,0,0,0' height='100%' width='100%'>");

document.write("<param name='src' value='Flex_2_Deploy.swf'/>");

document.write("<embed name='Flex_2_Deploy' src='Flex_2_Deploy.swf' pluginspage=
'http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=
ShockwaveFlash' height='100%' width='100%'/>");

document.write("</object>");

In this case, you have loaded the Flex_2_Deploy.swf application, created earlier in this chapter, but you can use this wrapper as a starting point for personalization. You could, for example, add a personalized header or footer in the HTML document, adding information relative to your company or copyright.

Be aware that this basic wrapper does not manage History Management, grant the functioning of the Back button of the browser, or Express Install to control the minimum requisites of Flash Player and, in such case, the automatic installation of the plugin.

Adding Features to the Wrapper

The wrapper that was created in the preceding section deals only with the importation of the Flex application into the HTML document.

The features for History Management or for Express Install are not dealt with. It is possible to add features to the wrapper by simply adding properties to the <object> and <embed> tags by importing new JavaScript files or by adding content to the HTML page. It is possible, for example, to insert the Flex application in a structured layout that uses CSS positioning techniques by defining a simple CSS file and the layer structure (using the <DIV> tag) in the HTML document.

Begin by modifying the content of the customWrapper.htm file that you will save with the new name custom Wrapper_2.htm:

<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css"></head>
<body>
<div id="container">
    <div id="header">
        <h1>Flex 2 Profesional - Customizing the Wrapper</h1>
    </div>
    <div id="content">
<script src="embedFlash.js"></script>
<noscript>
<object id='Flex_2_App' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
<embed name='MultipleButtons' pluginspage='http://
www.macromedia.com/shockwave/download/index.cgi
?P1_Prod_Version=ShockwaveFlash' src='Flex_2_Deploy.swf' height='100%'
width='100%'/>
</object>
</noscript>
</div>
<div id="footer">© Developed by Marco Casario<br>
    Blog: <a href="http://casario.blogs.com" target="_blank">
http://casario.blogs.com</a></div>
</div>
</body>
</html>

Following are the only modifications made in this HTML file:

  • The importation of the CSS file in the <style type="text/css"> tag with the method <linkhref="main.css" rel="stylesheet" type="text/css">.

  • This file deals with the pagination of the structure of the content.

  • The insertion of the structure of the layout through the <div> tags, which define the following structure:

     <div id="container">
    <div id="header">
<h1>Flex 2 Profesional - Customizing the Wrapper</h1>
    </div>
    <div id="content">
     <! -- import SWF's file -- >
</div>
<div id="footer">
<! –- copyright info -- >
     </div>
</div>

The main.css file will contain a few lines of code, but will define a monolith layout. With Dreamweaver 8 or with a simple text editor, create a CSS document that you save with the name main.css. The final code of the CSS document is the following:

/* main.css Document */
html,body{margin:0; padding: 0}
body{font-family: arial,sans-serif; font-size: 76%;background-color:#869CA7;}
h1{margin: 0;padding:0}
div#content{padding:0 1.5em}
div#footer{padding:0.5em; color:#000; text-align:center}

Customizing a wrapper is a very simple task, which, in the end, modifies an HTML page and its contents. There are, however, a few rules that must be kept in mind to avoid malfunctioning:

  • To avoid an annoying prompt to the user for the loading of the contents in Flash Player in Internet Explorer, avoid inserting the JavaScript directly in the HTML page. In fact, as part of the XP SP2 Local Machine Zone lockdown, Internet Explorer on Windows XP SP2 blocks active content and scripting that tries to run in the Local Machine zone. For more information on this, consult the Microsoft Web site:

    http://www.microsoft.com/windows/ieak/techinfo/deploy/60/en/appendix.mspx

  • As far as the use of the <object> and <embed> tags is concerned, for the importation of the SWF file, use the same parameters and values so as not to have a difference between the loaded application on different browsers. Furthermore, do not insert periods or special characters in the "id" and "name" properties of the tags, because this could cause problems in the use of an ExternalInterface class.

  • To add support to the History Management and the Express Install in the custom wrapper, you can refer to the files contained in the Flex SDK 2\resources\html-templates folder (in the express-installation-with-history folder).

  • In the deployment phase, remember to transfer all the defined and used files into the wrapper. For example, for the functionality of Express Install and History Management, it is necessary to transfer the following files (aside from the HTML file and the SWF file) to the deployment environment: AC_OETags.js, history.js, history.swf, history.htm, and playerProductInstall.swf.

In the following section, you create a custom wrapper to render the Flex application compliant with the XHTML 1.0 validators.

Creating a Wrapper that Supports Web Standards

The validity and the coherence of the HTML code is an important aspect, especially when the application must respect norms of quality and accessibility. In fact, one of the first rules is that of producing the XHTML code (HTML is by now a deprecated language) valid according to specific World Wide Web Consortium (W3C) reports.

As far as the Flex and Flash applications are concerned, the code necessary to import an SWF file does not produce a document that is valid according the XHTML 1.0 language with Document Type Definition (DTD) of a transitional or strict type. Different techniques exist to produce documents that import SWF standard-compliant files. In this section, you will use the technique known as Flash Satay (http://www.adobe.com/devnet/dreamweaver/articles/flash_satay.html), first created, discussed, and put into action by Drew McLellan.

Carefully look at the HTML code that you created in the preceding sections or through that written in the templates in the Flex SDK 2\resources\html-templates folder. To import an SWF, you use the following code:

<object id='Flex_2_App' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
<embed pluginspage='http://
www.macromedia.com/shockwave/download/index.cgi
?P1_Prod_Version=ShockwaveFlash' src='Flex_2_Deploy.swf' height='100%'
width='100%'/>
</object>

The two <object> and <embed> (nested in the <object>) tags are used with the values necessary for the loading of the SWF file. The first tag is one needed by Internet Explorer, and the second is for all Netscape browsers.

But whereas the <object> tag forms part of the XHTML specifics (http://www.w3.org/TR/xhtml1/), the <embed> tag does not form part of the standard and this is one of the first causes of nonvalidation of code when the validator of the W3C (http://validator.w3.org/) is launched. It is, in fact, said that the <embed> tag is not standard-compliant. Therefore, in the creation of a standard-compliant wrapper, the first task to carry out is that of removing the <embed> tag from the HTML code. The SWF file will be loaded equally well by browsers other than Internet Explorer because the recent versions of browsers all support the <object> tag, being a known standard.

The code you obtain will be the following:

<object id='Flex_2_App' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
</object>

This code, however, will continue to render the file visible only in Internet Explorer and is not valid (that is, XHTML-compliant). The problem is in seeking the classid attribute, which is created exclusively for the use of ActiveX in Internet Explorer and which is, therefore, not interpreted by different browsers.

The role of this attribute is not a light one, and it is required to specify the type of browser to use to load this content. Flash Player, however, also responds to the following MIME type application/x-shockwave-flash, defined in the type attribute:

<object id='Flex_2_App' type="application/x-shockwave-flash"
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
</object>

In the code, you have also removed the codebase attribute that contains the path to copy the Flash plugin to its Adobe servers. This attribute in Internet Explorer specifies the version of the plugin that the server should deliver, whereas in other browsers it blocks the execution of the SWF content.

Finally, you have added the data attribute to specify the location of the object’s data, permitting any browser to load the SWF content:

<object type="application/x-shockwave-flash" data="c.swf?path=Flex_2_Deploy.swf"
width="100%" height="100%">
<param name="movie"
value="c.swf?path=Flex_2_Deploy.swf" />
</object>

It all functions well on all browsers and becomes perfectly validated by the W3C XHTML validator. You can test this by loading the following HTML code in the Validate by Direct Input field at the address of http://validator.w3.org/ (Figure 20-13):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/
TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title></title>
</head>
<body>

<script src="embedFlash.js" type="text/javascript"></script>
<noscript>
<object type="application/x-shockwave-flash" data=" Flex_2_Deploy.swf"
width="100%" height="100%">
<param name="movie"
value="Flex_2_Deploy.swf" />
<!-- img src="noflash.gif"
width="200" height="100" alt="" / -->
</object>
</noscript>

</body>
</html>
Image from book
Figure 20-13: Validating the code

You have, therefore, created a wrapper that perfectly conforms to XHTML standards and is correctly validated by W3C. One last thing is to remedy a problem that appears for SWF film segments of large dimension on Internet Explorer.

The Microsoft browser waits for the SWF file to load before showing any contents. To remedy this inconvenience, simply create an empty Flash movie that on frame 1 will have the following code:

_root.loadMovie(_root.path,0);

The loadMovie() method loads the defined file in the variable path that is sent to it as a parameter of the <object> tag:

<object type="application/x-shockwave-flash"
data="emptyFlash.swf?path=Flex_2_Deploy.swf"
width="100%" height="100%">
<param name="movie"
value="emptyFlash.swf?path=Flex_2_Deploy.swf" />
</object>

The film segment emptyFlash.swf has the usual task of loading the SWF of the application by taking its defined value in the variable path.

emptyFlash.swf?path=Flex_2_Deploy.swf

In this section, you have created an XHTML wrapper that is compliant with the Flex application. You can add support to History Management and Express Install by referring to the template in the Flex SDK 2\resources\html-templates folder.

<object> and <embed>

The <object> and <embed> tags allow for the insertion of a Flex application in the wrapper that will be used to create the final HTML page and to render the SWF contents visible on the users’ browsers.

More generally, these elements allow you to specify the data and parameters for multimedia objects inserted into HTML documents, and the code that can be used to manipulate that data.

The <object> tag is used by Internet Explorer on Windows (that uses an ActiveX control) and the <embed> tag is used by Netscape Navigator (Macintosh and Windows) and Internet Explorer (Macintosh) to tell the browser to load the content using the Adobe Flash Player.

Tip

In terms of compatibility, the <object> tag is for Internet Explorer 3.0 or later on Windows 9x/2000/ NT/ME/XP platforms, or any browser that supports the use of the Flash ActiveX control. The <embed> tag is for Netscape Navigator 2.0 or later, or browsers that support the use of the Netscape-compatible plugin version of Flash Player.

Both tags support the attributes that change according to the contents that must be loaded. As far as the Flex applications and, therefore, the SWF contents are concerned, the properties allow you to change the appearance of the file in the page. You can add and modify these settings in the customizing of the wrapper phase. The following table shows the principle attributes of default for <object> and <embed>.

Open table as spreadsheet
Attribute | Description
data | This attribute can be used to specify the route of the object to be introduced in the page
classid | Gives indications on the route of the object and is useful to identify the type of plugin with which the object will run
codebase | Is needed to indicate the base URL, to which the code indicated in "data" or in "classid" refers
type | Is the type of object to insert (more precisely it is the MIME type of the object)
archive | Indicates a list of URL, separated by a comma, content resources relative to the inserted object
width, height | If necessary, indicates width and height

The following table provides descriptions for parameters.

Open table as spreadsheet
Parameter | Description
allowScriptAccess | Specifies how to perform outbound scripting from within the SWF file. It accepts the following values: always, never, and same domain.
pluginspace | The location of the Flash Player plugin.
border | The width (in pixels) of the SWF file.
declare | Setting the declare property to true tells the SWF to be instantiated by a subsequent object definition referring to this declaration.
devicefont | A Boolean that specifies how the static text objects (for which the deviceFont option is not selected) are drawn using a device font.
standby | Specifies a message displayed by the browser while loading the object’s implementation and data.
style | Defines the style information for the SWF file.
supportembed | A Boolean that specifies if Netscape’s <embed> tag is supported.
tabindex | Specifies the position of the SWF file in the tabbing order for the current document.
id | Identifies the SWF file to be referenced by using JavaScript (or any scripting language) for the <object> tag.
name | Identifies the SWF file to be referenced by using JavaScript (or any scripting language) for the <embed> tag.
menu | A Boolean that specifies if the context menu displays the full menu.
quality | Specifies the quality of the SWF file. Accepts the following values: low, high, autolow, autohigh, and best.
scale | Defines how the browser fills the screen with the SWF file. Used values are: showall, noborder, and exactfit.
align | Specifies the position of the SWF content. Supports the following values: Left, Right, Top, Middle, and Bottom.
allowNetworking | Restricts browser communication. Supports the following values: all, internal, and none.
wmode | Sets the Window Mode property. Accepts the following parameters: Window, Opaque, and Transparent.
bgcolor | The background color of the movie specified in hexadecimal RGB value. In order to make it work with Flex applications, you must clear the application’s backgroundImage style property.
base | Specifies the base directory or URL used to resolve all relative path statements in the Flash Player movie.
flashVars | Sends root-level variables to the Flex application. The format of the string is a set of name=value combinations separated by '&'.
hspace | Specifies the amount of white space inserted to the left and right of the SWF file.
vspace | Specifies the amount of white space inserted at the top and bottom of the SWF file.
lang | The base language of an element’s property values and text content.

Flex does not support the following parameters, which are, on the other hand, supported by ordinary Flash applications:

  • loop

  • play

  • swliveconnect


Using Express Install

It may not be sufficient to carry out a detection of the Flash Player on the client that is loading the Flex application. For example, you may have been able to use one of the features that functions only at the beginning of a “search for a version later” of Flash Player. In this case, it becomes crucial to check the exact version of the plugin installed on the client. If the response that you get from this check does not match your requirements, you can proceed with the relative upgrade of Flash Player and be sure that the client is able to load the Flex application.

With the Flash Player 6r65 version, Adobe has added the support of the Express Install feature for designing the best Flash Player detection experience. Express Install provides the capability for the Flash Player to update itself to a more current version. This has made the upgrade process much simpler for the user.

Flex includes the code of all the files necessary to developers to not only detect when users do not have the latest version of Flash Player, but also to start an update that securely installs the latest version of the Player from the Adobe Web site.

This feature offers many benefits to Flex developers, which can be summarized in the following points:

  • Assuring and guaranteeing Flash Player loads the Flex application correctly.

  • Allowing users not to be redirected from your site to the Adobe.com site in order to upgrade the player.

  • Providing a consistent way for upgrading the system across platforms and operating systems.

  • If the player on the client does not respond to the defined requirements, it is possible to load an alternative content.

In the SDK 2\resources\html-templates folder, there are two default HTML templates that implement and support Express Install:

  • express-installation - Includes the index.template.html, AC_OETags.js, and playerProductInstall.swf files.

  • express-installation-with-history - Includes the index.template.html, AC_OETags.js, history.js, history.swf, history.htm, and playerProductInstall.swf files. Aside from the support of Express Install, it adds History Management.

Therefore, to manage Express Install, it is necessary in the deployment phase to also transfer the AC_OETags.js and playerProductInstall.swf files in order to be able to run the Flex application (aside from the HTML and main application SWF file).

If you also operate History Management, it is necessary to also transfer the history.js, history.swf, and history.htm files.

Sometimes, the Auto Update of Flash Player and the Express Install features become confused. There is a substantial difference between the two options. Auto Upgrade forces the Flash Player to periodically check for new versions, and asks the user to upgrade when a new version is detected. The Express Install is managed and set by the developer who decides on the requirements that must be checked, and the actions that must be interpreted in the case of a mismatch of these.


Editing Your Wrapper

Earlier in this chapter, you learned how the default wrapper used by Flex Builder or by FDS manages Express Install. It is, therefore, possible to customize the wrapper of the compiler to include or exclude the Express Install option.

For applications that use the Web-tier compiler of FDS, it is possible to modify the settings in the flex-webtier-config.xml file by modifying the <use-express-install> node.

Retrieve the custom wrapper that was created in the previous sections and that you saved under the name customWrapper.htm. The HTML code was the following:

<html>
<body>
<script src="embedFlash.js"></script>
<noscript>
<object id='Flex_2_Deploy' classid='clsid:D27CDB6E-AE6D-
11cf-96B8-444553540000' codebase='http://download.macromedia.com
/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0'
height='100%' width='100%'>
<param name='src' value='Flex_2_Deploy.swf'/>
<embed name='MultipleButtons' pluginspage='http://
www.macromedia.com/shockwave/download/index.cgi
?P1_Prod_Version=ShockwaveFlash' src='Flex_2_Deploy.swf' height='100%'
width='100%'/>
</object>
</noscript>
</body>
</html>

To manually add support to Express Install, you must add the JavaScript file to the HTML document inserting it between the head tags:

<html>
<head>
<script src="AC_OETags.js" language="javascript"></script>

This file is located in the folder that contains the Flex SDK 2\resources\html-templates\expressinstallation templates, and will be transferred (in the deployment phase) to another location accessible to the wrapper.

Following this, add the Global section with the declaration of the three variables to define the minimum version of Flash Player that the users must be running. This code will be added immediately under the importation of the script AC_OETags.js:

<script language="JavaScript" type="text/javascript">
<!--
// --------------------------------------------------------------------
// Globals
// Major version of Flash required
var requiredMajorVersion = 9;
// Minor version of Flash required
var requiredMinorVersion = 0;
// Minor version of Flash required
var requiredRevision = 0;
// --------------------------------------------------------------------
// -->
</script>

You can write this code by hand, or simply copy it from the index.template.html file that you will find in the same folder as the AC_OETags.js file.

You now insert the second block of JavaScript code into the page, which sends the information from the SWF file to load to the script AC_OETags.js:

<script language="JavaScript" type="text/javascript">
<!--
// Version check for the Flash Player that has the ability to start Player Product
Install (6.0r65)
var hasProductInstall = DetectFlashVer(6, 0, 65);

// Version check based upon the values defined in globals
var hasRequestedVersion = DetectFlashVer(requiredMajorVersion, requiredMinorVersion,
requiredRevision);

// Check to see if a player with Flash Product Install is available and the version
does not meet the requirements for playback
if ( hasProductInstall && !hasRequestedVersion ) {
     // MMdoctitle is the stored document.title value used by the installation
process to close the window that started the process
     // This is necessary in order to close browser windows that are still
utilizing the older version of the player after installation has completed
     // DO NOT MODIFY THE FOLLOWING FOUR LINES
     // Location visited after installation is complete if installation is required
     var MMPlayerType = (isIE == true) ? "ActiveX" : "PlugIn";
     var MMredirectURL = window.location;
    document.title = document.title.slice(0, 47) + " - Flash Player Installation";
    var MMdoctitle = document.title;

     AC_FL_RunContent(
          "src", "playerProductInstall",
          "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+
'&MMdoctitle=
'+MMdoctitle+"",
          "width", "100%",
          "height", "100%",
          "align", "middle",
          "id", "Flex_App_id",
          "quality", "high",
          "bgcolor", "#869ca7",
          "name", "Flex_App_Name",
          "allowScriptAccess","sameDomain",
          "type", "application/x-shockwave-flash",
          "pluginspage", "http://www.adobe.com/go/getflashplayer"
     );
} else if (hasRequestedVersion) {
     // if we've detected an acceptable version
     // embed the Flash Content SWF when all tests are passed
     AC_FL_RunContent(
               "src", "Flex_App_Name",
               "width", "100%",
               "height", "100%",
               "align", "middle",
               "id", "Flex_App_ID",
               "quality", "high",
               "bgcolor", "#869ca7",
               "name", " Flex_App_Name",
               "flashvars",'historyUrl=history.htm%3F&lconid=' + lc_id + '',
               "allowScriptAccess","sameDomain",
               "type", "application/x-shockwave-flash",
               "pluginspage", "http://www.adobe.com/go/getflashplayer"
     );
  } else {  // flash is too old or we can't detect the plugin
    var alternateContent = 'Alternate HTML content should be placed here. '
       + 'This content requires the Adobe Flash Player. '
        + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
    document.write(alternateContent);  // insert non-flash content
  }
// -->
</script>

In this block of code, you define the properties “ïd”, “name”, and “src”, which correspond to those assigned in the <object> and <embed> tags:

AC_FL_RunContent(
          "src", "playerProductInstall",
          "FlashVars",
"MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle=
'+MMdoctitle+"",
          "width", "100%",
          "height", "100%",
          "align", "middle",
          "id", "Flex_2_Deploy",
          "quality", "high",
          "bgcolor", "#869ca7",
          "name", "Flex_2_Deploy",
          "allowScriptAccess","sameDomain",
          "type", "application/x-shockwave-flash",
          "pluginspage", "http://www.adobe.com/go/getflashplayer"
     );

These are also defined a little lower down inside the same function:

else if (hasRequestedVersion) {
     // if we've detected an acceptable version
     // embed the Flash Content SWF when all tests are passed
     AC_FL_RunContent(
               "src", "Flex_2_Deploy",
               "width", "100%",
               "height", "100%",
               "align", "middle",
               "id", "Flex_2_Deploy",
               "quality", "high",
               "bgcolor", "#869ca7",
               "name", "Flex_2_Deploy",
               "flashvars",'historyUrl=history.htm%3F&lconid=' + lc_id + '',
               "allowScriptAccess","sameDomain",
               "type", "application/x-shockwave-flash",
               "pluginspage", "http://www.adobe.com/go/getflashplayer"
     );

If you want to manage an alternate content to load in the case that the version of Flash Player installed on the client does not correspond to that defined in the minimum requirements, you can do so in the else cycle shown here, defining the contents in the variable alternateContent:

else {  // flash is too old or we can't detect the plugin
    var alternateContent = 'Alternate HTML content should be placed here. '
       + 'This content requires the Adobe Flash Player. '
        + '<a href=http://www.adobe.com/go/getflash/>Get Flash</a>';
    document.write(alternateContent);  // insert non-flash content
}

The final HTML file can be seen in the customWrapper.htm example file. In the deployment environment, do not forget to transfer the files necessary to detect the Express Install (AC_OETags.js and playerProductInstall.swf).

In the case in which History Management was also to be managed, it would be necessary to define the flashvars variable as follows:

"name", "Flex_2_Deploy",
"flashvars",'historyUrl=history.htm%3F&lconid=' + lc_id + '',
"allowScriptAccess","sameDomain",

It is also necessary to transfer the history.js, history.htm, and history.swf files in the deployment phase.


Configuring Express Install on Flex Data Services

When an application is developed with FDS, it is possible to use the Web-tier compiler that compiles the Flex application and its assets in SWF at run-time once the .mxml file is requested by the client:

http://www.yourdomain.com/myFlexApp.mxml

The compiler, at this point, returns the wrapper that embeds the resulting SWF file to the client.

You configure the Web-tier compiler by editing the flex-config.xml files (which contain the same defined nodes for the compiler command line) and the flex-webtier-config.xml file (which allows for the production mode to be enabled and to configure player version detection and caching). Both of these files are located in the flex_webapp_root/WEB-INF/flex directory.

To modify the options for Express Install, you can edit the settings in the flex-webtier-config.xml file, in which it is possible to define features supported by the wrapper generated by the FDS compiler.

Following are the nodes in the XML file that are involved in the creation phase of the wrapper:

  • <use-express-install>true</use-express-install> - Allows you to enable or disable the use of Express Install.

  • <required-major-version>9</required-major-version> - Required major player version.

  • <required-minor-version>0</required-minor-version> - “Dot” release of the required player.

  • <required-version-revision>0</required-version-revision> - Minor version revision number of the required player.

These settings are located in the <flash-player> node:

        <flash-player>
        <!-- enable/disable player detection -->
        <use-player-detection>true</use-player-detection>
        <use-express-install>true</use-express-install>

         <!-- required major player version -->
        <required-major-version>9</required-major-version>
        <!-- 'dot' release of the required player -->
        <required-minor-version>0</required-minor-version>
        <!-- minor version revision number of the required player -->
        <required-version-revision>0</required-version-revision>

        <alternate-content-include><![CDATA[This content requires the Adobe Flash
Player 9. <a href=http://www.adobe.com/go/getflashplayer/>Get
Flash</a>]]></alternate-content-include>

    </flash-player>

The last <alternate-content-include> node manages the loading of the alternative content for the case in which the version of Flash Player installed on the client does not meet the minimum requirements.


Upgrading Without Express Install

Though Express Install is user-friendly, it is not the only possibility that a developer of Flex applications has available for managing the updating of Flash Player.

Through the properties of the <object> and <embed> tags, it is possible to define a path to upgrade and install Flash Player. The <object> tag displays the codebase property that controls the version of the plugin in Internet Explorer.

In the <object> tag, two attributes become defined: the classid (which identifies the ActiveX control used by the browser to read the film segment) and the codebase. The classid specifies the base path used to resolve relative URIs specified by the classid, data, and archive attributes:

<object
classid="clsid:"
codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/
swflash.cab#version=9,0,0"
width=400 height=300 id="mymovie">
<param name=movie value="flexApp.swf">
</object>

In this case, the following line of code, aside from indicating the download URL of Flash Player, also establishes the minimum requirements defining the version:

codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/
swflash.cab#version=9,0,0"

Therefore, the browser loads the Flash-defined film segment from this <object> tag. If, on the client, it does not find version 9 of the Flash Player, it will request that the user perform an upgrade of the plugin.

Similarly, for the Firefox, Netscape 8, and all other Mozilla-based browsers, the pluginspace property of the <embed> tag functions in the same way:

<embed src="myFlexApp.swf" quality="high"
    width="350" height="200"
    name="flexApp" type="application/x-shockwave-flash"
    pluginspace="http://www.macromedia.com/go/getflashplayer">

The only difference with respect to the tag object is that it is not possible to specify a version of the plugin, and, therefore, it can only verify the presence of Flash Player on the client.

Using these two methods does not always obtain the desired results. Depending on the type of browser and the version, the user may not be able to load the exact version of Flash Player requested for the Flex application to function.

In addition to the Flash Player–detection techniques described here, you can always provide alternative content that displays the version information and contains a link to the Flash Player download page. This content should be put in the <noscript> block.

To examine more detail about the Flash Player detection, Adobe has created the Flash Player Detection Kit (located at http://www.adobe.com/products/flashplayer/download/detection_kit/), which includes the following:

  • The documentation describing the requirements, methods, and procedures for detecting and updating the end user’s Flash Player version

  • Client-side detection sample files

  • ActionScript-based detection sample files


Summary

This chapter provided a comprehensive guide on the different methods of application deployment, as well as the consequences of each. It demonstrated the use of the wrapper file and all of the ways this file can be edited for Web-standard compliance, as well as to suit the individual needs of the application being deployed. The History Manager and Express Install were also discussed, and examples demonstrated how to deploy an application using either or both of these.

Chapter 21 is dedicated to the Cairngorm micro-architecture developed by the Adobe Consulting team. Examples on the implementation of Cairngorm and all of the pieces that make up the Cairngorm framework are demonstrated.


Part VI: Advanced Flex 2.0

Chapter List

Chapter 21: Using the Cairngorm Framework
Chapter 22: Using the Flex-Ajax Bridge
Chapter 23: Using the ActionScript 3.0 Libraries
Chapter 24: Using ColdFusion/Flex Connectivity


Chapter 21: Using the Cairngorm Framework

Cairngorm is a framework used to develop Rich Internet Applications (RIAs) in Adobe Flex. It was originally developed by iteration::two, which was acquired by Macromedia (now Adobe) in 2005.

The framework was released for Flex 1.5 and later updated to version 2 to work in conjunction with the newly released Flex 2.0. The latest version of the Cairngorm Framework, version 2.1, was released at Adobe MAX 2006 in Las Vegas by the Adobe Consulting Team. The example used in this chapter uses Cairngorm 2.1, which is currently as of this writing the latest version of the framework.

The Cairngorm Framework

The framework is an adaptation of Sun’s core J2EE patterns and was first applied to Flash development and then to Flex. Iteration::two also played a significant role in helping shape the Flex Framework.

Over the years, iteration::two developed the Cairngorm Framework through considerable research and development using best-practice techniques from the field of design patterns. The framework was then applied to the emerging technology of RIAs using Flex.

At the MAX 2004 conference in New Orleans, iteration::two announced the release of the Cairngorm Framework as an Open Source project for the Flex development community.

For more information on the Cairngorm Framework, Steven Webster has a great series of articles on “Developing Flex RIAs with Cairngorm Micro-Architecture.” The series is comprised of the following six parts:

  • Part 1: Introducing Cairngorm

  • Part 2: Keeping state on the client

  • Part 3: Architecting the view

  • Part 4: Feature-driven development

  • Part 5: Server-side integration

  • Part 6: Rapid and consistent development with Cairngorm and Flex

You can find the series of articles at http://www.adobe.com/devnet/flex/architecture.html.

It is a must-read if you want to learn more about the Cairngorm Framework and how it works with Adobe Flex. To get to grips with Cairngorm, this chapter takes you through the framework while building a Flex weather application. This seems to be the most efficient way in learning something new.


Understanding Frameworks

It is important to understand what a framework is before you start using one for the first time.

The word “framework” is often misunderstood in the software development field. There are two different types of frameworks, one being application frameworks and the other being architectural frameworks.

For a more in-depth explanation of frameworks, refer to part 1 of Steven Webster’s series of articles at http://www.adobe.com/devnet/flex/articles/cairngorm_pt1_02.html.

Application Frameworks

Application frameworks usually refer to a set of libraries and classes used to implement the standard structure of an application. Flex 2.0 is a great example of an application framework. The Flex 2.0 Framework provides a set of rich class libraries that provide functionality for developers to create custom applications. For example, Flex 2.0 provides a competent framework that allows you to develop custom components to be reused in your Flex applications.

Application frameworks have become more popular with the rise of graphical user interfaces (GUIs), which seem to promote a standard structure for applications. Object-oriented programming (OOP) techniques usually are used to implement frameworks such as the unique part of an application that can inherit from preexisting classes in the framework.

Architectural Frameworks

Architectural frameworks refer to a set of tools that can be used to provide a structure where the business layer of the application can be defined. In other words, an architectural framework is the internal structure on which an application is built.


Building an Application Using the Cairngorm Framework

In the remainder of this chapter, you build an application from the ground up, utilizing the Cairngorm micro-architecture. The Flex Weather application showcases the basics of a Flex application framework, and demonstrates data binding, navigator containers, and controls and effects. The Weather application is a great way for you to become familiar with the Cairngorm Framework.

Figure 21-1 shows the completed Flex Weather application using the Cairngorm Framework.

Image from book
Figure 21-1: Example Weather application using the Cairngorm Framework

Value Object and Model Locator Pattern

Developers who come from a Web application background must change the way they think about RIAs. The reason is because Flex applications are stateful, rather than the stateless HTTP request-and-response model of an HTML Web application.

To overcome this, developers require ways to maintain state on the client. This is done by using either cookies or sessions on the server to achieve a stateful client.

RIAs work in the same way that desktop applications work in that their state is maintained on the client. So the principles of building Web applications must be changed when designing and developing RIAs.

Value Object

When developing applications in Flex (or any enterprise application, for that matter), you should create classes or objects that represent an entity. For example, in the Weather application, the one thing that you must represent is the weather for that location. Each location has a number of weather attributes, such as temperature, date, conditions, longitude, latitude, wind, and so on.

Useful structures can be exchanged or transferred between tiers in your application. On the server side, you could run a query in SQL that returns a result set and then converts it into a collection of custom value objects (VOs) to return to the client. Flex can then deserialize each VO in the collection into the corresponding VO on the client.

VOs are used to create a layer of business objects that can be transferred between tiers, instead of using records, results sets, and datasets.

Using VOs also allows stricter typing on the client. This is great when compiling your Flex applications because any references to properties that do not exist, or types that do not correspond, will throw a compiler error.

Listing 21-1 shows a representation of a location’s weather forecast in a VO.

Listing 21-1: WeatherVO.as
Image from book

package com.wiley.proflex2.chapter23.vo
{
     import com.adobe.cairngorm.vo.IValueObject;

     [Bindable]
     public class WeatherVO implements IValueObject
     {
          public var location:String;
          public var humidity:Number;
          public var visibility:Number;
          public var conditions:String;
          public var code:String;
          public var temp:String;
          public var date:String;
          public var link:String;
          public var sunrise:String;
          public var sunset:String;
          public var windspeed:String;
          public var units:UnitsVO;
          public var highTemp:Number;
          public var lowTemp:Number;

          public function WeatherVO()
          {
               units = new UnitsVO();
          }
     }
}
Image from book

Contained inside the WeatherVO is another value object called the UnitsVO, shown in Listing 21-2. This contains all the units for distance, pressure, speed, and temperature. You may find it easier to manage your code by moving some of the properties in one VO into another one, such as in this scenario.

Listing 21-2: UnitsVO.as
Image from book

package com.wiley.proflex2.chapter23.vo
{
     import com.adobe.cairngorm.vo.IValueObject;

     [Bindable]
     public class UnitsVO implements IValueObject
     {
          public var distance:String;
          public var pressure:String;
          public var speed:String;
          public var temperature:String;
     }
}
Image from book

WeatherVO is simply a set of properties that describes the weather for a specific location. Once the weather data has been downloaded, you set it to an instance of a WeatherVO and store it in the model or state of your application. This means you can access the WeatherVO instance anywhere in your Flex application.

The Model Locator

The Model Locator pattern is a singleton and was created purely to be used with Flex application development. In this case, a singleton is a design pattern that allows for only one instance of the Model Locator to be present within your application’s memory. Any data that you think is required to live in the application’s state should be stored inside the Model Locator. The Model Locator creates a central area where all the states can be held in your Flex application. This allows the view components to bind to the model or state of the application and keep everything up to date.

Listing 21-3 shows the Model Locator of the Flex Weather application.

Listing 21-3: ModelLocator.as
Image from book

package com.wiley.proflex2.chapter23.model
{
     import com.adobe.cairngorm.model.ModelLocator;
     import com.wiley.proflex2.chapter23.vo.WeatherVO;
     import mx.events.IndexChangedEvent;

     [Bindable]
     public class ModelLocator implements com.adobe.cairngorm.model.ModelLocator
     {
          private static var modelLocator:com.wiley.proflex2.chapter23.model
.ModelLocator;

          public static function getInstance():com.wiley.proflex2.chapter23.model
.ModelLocator
          {
               if (modelLocator == null)
                    modelLocator = new com.wiley.proflex2.chapter23.model
.ModelLocator();

               return modelLocator;
          }

          public function ModelLocator()
          {
               if ( com.wiley.proflex2.chapter23.model.ModelLocator.modelLocator !=
 null )
                    throw new Error( "Only one ModelLocator instance should be
instantiated" );
          }

          // Store the location id
          public var location:String;

          // The current weather for that location id
          public var weather:WeatherVO;

          public var showWeatherDetail:Boolean = false;
          public var backgroundColor:uint = DAYTIME_COLOR;

          public const DAYTIME_COLOR:uint = 0x93BCF6;
          public const NIGHTTIME_COLOR:uint = 0xB6B3C1;
     }
}
Image from book

While reviewing the code for the Model Locator, you will notice two properties: the locationid property and the weather property (which is an instance of the WeatherVO class). These are stored in the state of the client so that the relevant views can bind to those properties.

Later on in this chapter, you will see that the WeatherView component requires the current location’s weather forecast so that it can display the details. The weather property in the Model Locator can be passed in to the WeatherView component, as shown here:

<view:WeatherView weather="{model.weather}" />

The view is updated accordingly because a reference is passed from the weather instance in the Model Locator to the weather instance in the WeatherView component.

The View

The view of your application represents the elements that the user sees and interacts with. You will learn how to create and build the view using the Cairngorm Framework.

As mentioned earlier, the Model Locator pattern was designed specifically for Flex development. The main reason for its existence is so that you can use the powerful data-binding capabilities of the Flex Framework to update the view of your application.

To use binding, you need a source and a destination. The source is the point where the data comes from and the destination is where the data is sent to. The source property has one or many destinations. Any time the source is updated, one or more destinations that are bound to the source are updated by copying the contents of the source to one or many destinations. This is a very powerful capability that most Flex developers cannot live without.

The entry point for the Flex Weather application is the Main.mxml file (shown in Listing 21-4), which contains one other component view, WeatherView.mxml (shown in Listing 21-5). The WeatherView.mxml file contains all the components that make up the view of the application.

Listing 21-4: Main.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:business="com.wiley.proflex2.chapter23.business.*"
     xmlns:view="com.wiley.proflex2.chapter23.view.*"
     xmlns:control="com.wiley.proflex2.chapter23.control.*">

     <mx:Style>

          Application
          {
               backgroundColor: #000000;
          }

          Label
          {
               fontFamily: Arial;
               fontSize: 11;
          }

          Button, ComboBox
          {
               highlightAlphas: 0.37, 0.73;
               fillAlphas: 0.6, 0.53, 0.88, 0.63;
               borderColor: #EEEEEE;
               themeColor: #0099cc;
               cornerRadius: 3;
          }

          LinkButton
          {
               color: #FFFFFF;
               borderStyle: solid;
               borderColor: #FFFFFF;
          }

          @font-face
          {
              src: url(assets/fonts/arial_fonts.swf);
              fontFamily: Arial;
          }

          @font-face
          {
              src: url(assets/fonts/arial_fonts.swf);
              fontFamily: Arial;
              fontWeight: bold;
          }

     </mx:Style>

     <!-- ========================================================================== -->

     <!-- the ServiceLocator where we specify the remote services -->
     <business:Services id="loginServices" />

     <!-- the FrontController, containing Commands specific to this appliation -->
     <control:ApplicationController id="controller" />

     <!-- ========================================================================== -->

     <view:MainView />

</mx:Application>
Image from book
Listing 21-5: WeatherView.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:filters="flash.filters.*">

     <mx:Script>
          <![CDATA[

               import com.wiley.proflex2.chapter23.model.ModelLocator;
               import com.wiley.proflex2.chapter23.events
.GetWeatherByLocationEvent;
               import com.adobe.cairngorm.control.CairngormEventDispatcher;
               import com.wiley.proflex2.chapter23.vo.WeatherVO;

               [Bindable]
               public var weather:WeatherVO;

               [Bindable]
               public var model:ModelLocator = ModelLocator.getInstance();

          ]]>
     </mx:Script>

     <mx:Form>
          <mx:FormItem label="City, State or Zip Code" direction="horizontal">
               <mx:TextInput id="locationId" text="SFXX0010" />
               <mx:ComboBox id="units">
                    <mx:dataProvider>
                         <mx:Array>
                              <mx:Object label="C" data="c" />
                              <mx:Object label="F" data="f" />
                         </mx:Array>
                    </mx:dataProvider>
               </mx:ComboBox>
          </mx:FormItem>
          <mx:FormItem>
               <mx:Button label="Get Weather" click="CairngormEventDispatcher
.getInstance().dispatchEvent(new GetWeatherByLocationEvent(locationId.text,
units.selectedItem.data))" />
          </mx:FormItem>
     </mx:Form>

     <mx:VBox backgroundColor="{model.backgroundColor}" borderColor="#8E8E8E"
borderStyle="solid" cornerRadius="4" showEffect="{fade}"
          paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"
visible="{model.showWeatherDetail}">
          <mx:HBox>
               <mx:VBox>
                    <mx:Label text="{weather.location}" fontWeight="bold"
fontSize="11" />
                    <mx:Label text="Current conditions as of {weather.date}" />
                    <mx:Label text="{weather.conditions}" fontWeight="bold"
fontSize="12" />
                    <mx:Form>
                         <mx:FormItem label="Feels Like:">
                              <mx:Label text="{weather.temp} {weather.units
.temperature}" />
                         </mx:FormItem>
                         <mx:FormItem label="Humidity:">
                              <mx:Label text="{weather.humidity}%" />
                         </mx:FormItem>
                         <mx:FormItem label="Visibility:">
                              <mx:Label text="{weather.visibility}
{weather.units.distance}" />
                         </mx:FormItem>
                         <mx:FormItem label="Wind:">
                              <mx:Label text="{weather.windspeed}
{weather.units.speed}" />
                         </mx:FormItem>
                         <mx:FormItem label="Sunrise">
                              <mx:Label text="{weather.sunrise}" />
                         </mx:FormItem>
                         <mx:FormItem label="Sunset">
                              <mx:Label text="{weather.sunset}" />
                         </mx:FormItem>
                    </mx:Form>
               </mx:VBox>
               <mx:Canvas>
                    <mx:Image source="http://us.i1.yimg.com/us.yimg.com/i/us/nws/
weather/gr/{weather.code}d.png" />
                    <mx:Label text="{weather.temp} {weather.units.temperature}"
fontSize="40" color="#FFFFFF" right="10" top="20">
                         <mx:filters>
                              <filters:GlowFilter strength="1" color="#555555" />
                         </mx:filters>
                    </mx:Label>
                    <mx:HBox bottom="60" right="20">
                         <mx:Label text="High: {weather.highTemp} Low: {weather
.lowTemp}" color="#FFFFFF" />
                     </mx:HBox>
               </mx:Canvas>
          </mx:HBox>
          <mx:filters>
               <filters:GlowFilter strength="1" color="#555555" />
          </mx:filters>
     </mx:VBox>

     <mx:Fade id="fade" duration="200" alphaFrom="0" alphaTo="1" />

</mx:VBox>
Image from book

In the WeatherView.mxml file, you can view the implementation of the component. As you can see, a lot of Flex visual components are bound to the properties of the weather instance.

Any changes to the weather instances held in the Model Locator cause the binding to execute in the <view:WeatherView/> instance, updating the weather property of the WeatherView component. Cairngorm ensures that dynamic data displayed in MXML comes from the Model Locator and nowhere else.

The Main.mxml file contains the <mx:Application> tag, which is the entry point for all Flex applications. The styles for the application are defined inline within the <mx:Style> tag. Also contained here are the Service Locator and Front Controller, which are discussed in the next few sections. They are defined here so that the compiler includes them in the application. Otherwise, the Cairngorm Framework would not be able to access them.

The Front Controller, Cairngorm Event Broadcaster, and Command Patterns

In this section, you learn about the design patterns Cairngorm uses to listen to user actions and convert those into something meaningful to the user of the application.

You will also come across the most important and innovative patterns in the Cairngorm Framework. The Front Controller, Cairngorm Event Broadcaster, and Command patterns work together to help you develop consistent RIAs using Flex.

The Command Class

In the Flex Weather application, you have one feature: retrieving the weather by location. This feature gets executed once the user has filled in the location and clicks the button to retrieve the weather by location.

For every feature or use case in your application, a corresponding custom command and event must be created. Each command contains an execute() method that is run by the framework when the user action has been executed. These classes are occasionally referred to as worker classes because they carry out the work for an application.

Consider the only feature in the Flex Weather application: being able to retrieve weather for a specific location. To implement this feature, you create a Command class called GetWeatherByLocationCommand.

Listing 21-6 shows the GetWeatherByLocationCommand.as file.

Listing 21-6: GetWeatherByLocationCommand.as
Image from book

package com.wiley.proflex2.chapter23.commands
{
     import com.adobe.cairngorm.commands.ICommand;
     import mx.rpc.IResponder;
     import com.adobe.cairngorm.control.CairngormEvent;
     import com.wiley.proflex2.chapter23.business.WeatherDelegate;
     import com.wiley.proflex2.chapter23.events.GetWeatherByLocationEvent;
     import mx.utils.ObjectUtil;
     import mx.controls.Alert;
     import com.wiley.proflex2.chapter23.model.ModelLocator;
     import com.wiley.proflex2.chapter23.vo.WeatherVO;

     public class GetWeatherByLocationCommand implements ICommand, IResponder
     {
          public function execute( event : CairngormEvent ) : void
          {
               var delegate : WeatherDelegate = new WeatherDelegate( this );
               var initialEvent : GetWeatherByLocationEvent =
GetWeatherByLocationEvent( event );

               delegate.getWeatherByLocation(initialEvent.locationId,
initialEvent.unit);
          }

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

          public function result( event : Object ) : void
          {
               trace(ObjectUtil.toString(event.result.rss.channel));

               var item:Object = event.result.rss.channel;
               var weather:WeatherVO = new WeatherVO();

               weather.location = item.title;
               weather.sunrise = item.astronomy.sunrise;
               weather.sunset = item.astronomy.sunset;
               weather.link = item.link;
               weather.conditions = item.item.condition.text;
               weather.date = item.item.condition.date;
               weather.code = item.item.condition.code;
               weather.temp = item.item.condition.temp;
               weather.humidity = item.atmosphere.humidity;
               weather.visibility = item.atmosphere.visibility;
               weather.windspeed = item.wind.speed;
               weather.units.distance = item.units.distance;
               weather.units.pressure = item.units.pressure;
               weather.units.speed = item.units.speed;
               weather.units.temperature = item.units.temperature;
               weather.highTemp = item.item.forecast[0].high;
               weather.lowTemp = item.item.forecast[0].low;

               model.weather = weather;
               model.showWeatherDetail = true;

          }

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

          public function fault( event : Object ) : void
          {
               Alert.show(event.fault);
          }

          [Bindable]
          public var model:ModelLocator = ModelLocator.getInstance();
     }
}
Image from book

As you can see, the GetWeatherByLocationCommand class implements the ICommand and IResponder interfaces. The ICommand interface means that any class that implements this interface must contain an execute() method to act as an entry point, which allows Cairngorm to execute each and every command.

In the execute() method, an instance of the WeatherDelegate class is created and the initialEvent instance is cast from a CairngormEvent to type GetWeatherByLocationEvent. The WeatherDelegate class is a business delegate that creates a mapping between the client and server side. In other words, it is an API that maps to the server-side methods of your application.

The GetWeatherByLocationEvent class extends the CairngormEvent class. The CairngormEvent is a base event class that developers are encouraged to extend to create application-specific events. Each execute() in a command takes a CairngormEvent as a parameter, which you can then cast to your custom-implemented event. Every time you create a command, a corresponding event must be created. The events broadcast using the Cairngorm Event Dispatcher.

Listing 21-7 shows the implementation of the GetWeatherByLocationEvent.as.

Listing 21-7: GetWeatherByLocationEvent.as
Image from book

package com.wiley.proflex2.chapter23.events
{
     import com.adobe.cairngorm.control.CairngormEvent;
     import com.wiley.proflex2.chapter23.control.ApplicationController;

     public class GetWeatherByLocationEvent extends CairngormEvent
     {
          public function GetWeatherByLocationEvent(locationId:String, unit:String)
          {
               super( ApplicationController.EVENT_GET_WEATHER );
               this.locationId = locationId;
               this.unit = unit;
          }

          public var locationId : String;
          public var unit : String;
     }
}
Image from book

The GetWeatherByLocationEvent class contains two properties: locationid and unit. When the event is broadcast, there are two values that must be passed into the constructor of the GetWeatherByLocationEvent. These values are critical in returning the correct weather data to your Flex application. The following example shows this:

<mx:Button label="Get Weather" click="CairngormEventDispatcher.getInstance()
.dispatchEvent(new GetWeatherByLocationEvent(locationId.text, units.selectedItem
.data))" />

Now, let’s go back to the rest of the implementation of the execute() method. The getWeatherByLocation() method of the WeatherDelegate is called and requires two parameters, locationid and unit. These are passed in via the initialEvent instance, which is of type GetWeatherByLocationEvent.

The result() and fault() methods are part of the IResponder interface. These methods wait for the asynchronous call to return results from the server. The result() method handles the results if the call was successful, and the fault() method handles the results if they were not successful.

The Front Controller

The Front Controller is a central place where all the commands are mapped to the relevant events. Once an event is dispatched, the Front Controller finds the corresponding command to execute.

Listing 21-8 shows the Front Controller pattern in the Flex Weather application.

Listing 21-8: ApplicationController.as
Image from book

package com.wiley.proflex2.chapter23.control
{
     import com.adobe.cairngorm.control.FrontController;
     import com.wiley.proflex2.chapter23.commands.*;

     public class ApplicationController extends FrontController
     {
          public function ApplicationController()
          {
               addCommand( ApplicationController.EVENT_GET_WEATHER_BY_LOCATION,
GetWeatherByLocationCommand );
          }

          public static const EVENT_GET_WEATHER_BY_LOCATION : String =
"getWeatherByLocation";
     }
}
Image from book

First, all the events are named as constants on the ApplicationController instance. This means the compiler can catch any mistyped events at compile time rather than at run-time.

In the constructor, the command class is added to the list of commands. In a larger application, there will be many more of these commands. It is important to ensure that they are all added when the Front Controller is first created by adding them in the constructor.

The addcommand() method takes the event name as type string and the name of the command of type string:

addCommand( ApplicationController.EVENT_GET_WEATHER_BY_LOCATION,
GetWeatherByLocationCommand );

You may have noticed that the ApplicationController extends FrontController. This is so that you can create a FrontController specifically for your application’s needs. By extending the Front Controller, you have access to the addCommand() method of its superclass. This allows you register events with their corresponding command classes.

You create your controller in the base file of your application. In this example, it is the main.mxml file between the <mx:Application> tag, as follows:

<!-- the FrontController, containing Commands specific to this application -->
<control:ApplicationController id="controller" />

This means that your application has a Front Controller that responds to events and invokes all the commands that you registered with the addCommand() method.

Cairngorm Event Dispatcher

Cairngorm provides a singleton Cairngorm Event Dispatcher that works with the Front Controller class. Whenever you want to dispatch Cairngorm events, you use the Cairngorm Event Dispatcher.

The following code shows how to broadcast a Cairngorm event using the Cairngorm Event Dispatcher:

CairngormEventDispatcher.getInstance().dispatchEvent(new GetWeatherByLocationEvent
(locationId.text, units.selectedItem.data))

The dispatchEvent() method of the Cairngorm Event Dispatcher singleton takes a parameter of type flash.events.Event. This event is dispatched and the corresponding command is executed.

This is how the Front Controller, Cairngorm Event Dispatcher, Command patterns, and Cairngorm Events work together with the Cairngorm Event, the Model Locator, and VO patterns to create an immersive experience for the user of an RIA.

Business Delegate and Service Locator

This is the last part of the Cairngorm Framework that allows the functionality to connect between the client and the server side.

Flex RPC Services

In Chapter 11, you learned about RPC services and the three RPC components that come with Flex - the HTTP service, the Web service, and Remote object components.

You will find that as your applications get bigger, the calls to these services will increase. With the Cairngorm Framework, you can call a mixture of all these services. To accomplish this, Cairngorm offers the Service Locator, where you can accommodate all the three services.

Service Locator

The Service Locator contains all the services that are required by your RIA in one central place. This is great because you can reuse them throughout your application.

By using the Service Locator, you don’t need to know which service you are using to retrieve the results from a remote server. In essence, the Service Locator hides all the implementation of the services from the developer, so they can all be treated the same.

The Service Locator is a singleton for service access, and you typically extend the base class in MXML, as the following example shows:

<?xml version="1.0" encoding="utf-8"?>

<cairngorm:ServiceLocator xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:cairngorm="com.adobe.cairngorm.business.*">

     <mx:HTTPService id="weatherService"
          url="http://xml.weather.yahoo.com/forecastrss"
          showBusyCursor="true" />

</cairngorm:ServiceLocator>

As you can see, there is a weather service that fetches the weather for a specific location. It is an instance of an HTTP service, which contains a URL to Yahoo’s servers. If you were using Flex Data Services, you could define the destination in the services-config.xml file and hide the implementation in the Flex application from a hacker. You would need to replace the url property with the destination property.

Business Delegate

The Business Delegate delegates all the responsibility for the business logic that must locate a service, and then invokes a method on the service.

In the Flex Weather application, there is one Business Delegate called WeatherDelegate. You can have as many delegates as you think appropriate, probably one for each service. Listing 21-9 shows the WeatherDelegate.as.

Listing 21-9: WeatherDelegate.as
Image from book

package com.wiley.proflex2.chapter23.business
{
     import com.adobe.cairngorm.business.ServiceLocator;
     import mx.utils.ObjectUtil;
     import mx.rpc.IResponder;

     public class WeatherDelegate
     {
          public function WeatherDelegate( responder : IResponder )
          {
               this.service = ServiceLocator.getInstance().getHTTPService
( "weatherService" );
               this.responder = responder;
          }

          public function getWeatherByLocation(locationId:String, unit:String): void
          {
               var call : Object = service.send({p: locationId, u: unit});
               call.addResponder(responder);
          }

          private var responder:IResponder;
          private var service:Object;
     }
}
Image from book

If you remember, the GetWeatherByLocation class calls the getWeather() method in its execute() method:

public function execute( event : CairngormEvent ) : void
{
               var delegate : WeatherDelegate = new WeatherDelegate( this );
               var initialEvent : GetWeatherByLocationEvent =
GetWeatherByLocationEvent( event );

               delegate.getWeather(initialEvent.locationId, initialEvent.unit);
}

These two classes work together in the following way. The Command class creates an instance of the Weather Delegate passing itself (this) to the constructor of the delegate.

The Command class then takes responsibility as the responder and, as such, implements the IResponder interface in the Flex Framework. This ensures that the developer adds the result() method and fault() method.

Take a look at the result() method of the GetWeatherByLocation. It extracts the values from the XML object and sets them into a WeatherVO value object. That instance of the WeatherVO is set to the Model Locator’s weather instance.


Summary

This chapter has discussed all the design patterns that contribute to the Cairngorm Framework. Cairngorm is lightweight and makes it easier for developers to create large-scale applications and scale them accordingly.

Adobe Consulting is always refining the Cairngorm Framework and will be supporting it as long as Adobe Flex is still around.

If you need any support regarding Cairngorm, visit the FlexCoders mailing list (http://tech.groups.yahoo.com/group/flexcoders/). The Cairngorm Committee is a regular contributor, and many Flex developers are now familiar with the framework. So you should find answers to your questions regarding the Cairngorm Framework.

Chapter 22 discusses the Flex-Ajax Bridge and describes how to integrate HTML applications with Flex applications. In essence, it shows how to communicate back and forth using JavaScript.


Chapter 22: Using the Flex-Ajax Bridge

The release of Flash Player 9 included a new External API using a class file called the ExternalInterface that allows for the communication between JavaScript and Flash applications. To create the communication link and pass data between JavaScript and Flex, the developer must create custom code to handle each call. You can see examples of this covered in the “Communicating with the Wrapper” section of Chapter 8.

The Flex-Ajax Bridge has simplified the usage of this API. By simply including the necessary classes, the bridge exposes all of the classes within the Flex application to JavaScript. It will also allow you to create almost anything in your Flex application using JavaScript instead of ActionScript.

Why Use Flex with JavaScript?

Following is a short list of the many reasons why Flex and JavaScript are a good fit with each other:

  • Combining the built-in (as well as custom) classes of Flex, and also the large collection of JavaScript libraries, creates a very complete collection of source code.

  • The Flex-Ajax Bridge allows existing JavaScript developers the ability to create Flex content using the syntax they are accustomed to.

  • Creating a hybrid application is now easier than ever. Because all of the Flex classes are now accessible through JavaScript, you can script the creation Flex components in real time.

  • Flex has an excellent set of rich components that can now easily be included within your HTML application.


Requirements for the FA Bridge

You can download the Flex-Ajax Bridge from the Adobe Labs site located at http://labs.adobe.com/wiki/index.php/Flex_Framework:FABridge. The download includes all of the necessary files, as well as a sample application.

When using the Flex-Ajax Bridge, there are a few requirements. After unpacking the download, you will find a folder named bridge that should be included within the root of your application. Within this folder, there is a single ActionScript file named FABridge.as, which must be instantiated in your Flex application.

If you have defined the namespace (xmlns:bridge="bridge.*") within the mx:Application tag, you can choose to instantiate the FABridge using the following standard syntax:

<bridge:FABridge id="bridgeInst"/>

Or you can do it all in one line, using the following syntax:

<bridge:FABridge xmlns:bridge="bridge.*" id="bridgeInst" />

That is all that is needed on the Flex side. On the JavaScript side, there are additional requirements. You will first need to include a JavaScript file named FABridge.as that is included within the bridge folder. Simply add a JavaScript include to the HTML page that will be including your SWF. Here is the syntax for the JavaScript include:

<script src=”bridge/FABridge.js” ></script>

Next, you will need to include a few additional parameters to the script and noscript code blocks used to include the SWF in your HTML page. The flashvars property named bridgeName must be included in two places, as in Listing 22-1. You can name the bridge whatever you want because it will be used as an ID when making calls to the SWF file. In Listing 22-1, the bridgeName is set to myBridge.

Listing 22-1: Including the SWF in the HTML Page
Image from book

<script language="JavaScript" type="text/javascript">
<!--
    AC_FL_RunContent(
          "src", "validate",
          "width", "0",
          "height", "0",
          "align", "middle",
          "id", "validate",
          "quality", "high",
          "bgcolor", "#869ca7",
          "name", "validate",
          "flashvars","bridgeName=myBridge",
          "allowScriptAccess","sameDomain",
          "type", "application/x-shockwave-flash",
          "pluginspage", "http://www.adobe.com/go/getflashplayer"
  );
// -->
</script>
<noscript>
  <object classid="clsid:"
      id="validate" width="1" height="1"
      codebase="http://fpdownload.macromedia.com/get/flashplayer/current/
swflash.cab">
      <param name="movie" value="validate.swf" />
      <param name="quality" value="high" />
      <param name="bgcolor" value="#869ca7" />
      <param name="allowScriptAccess" value="sameDomain" />
      <param name="flashvars" value="bridgeName=myBridge"/>
      <embed src="validate.swf" quality="high" bgcolor="#869ca7"
        width="0" height="0" name="validate" align="middle"
        play="true"
        loop="false"
        quality="high"
        allowScriptAccess="sameDomain"
        type="application/x-shockwave-flash"
        pluginspage="http://www.adobe.com/go/getflashplayer">
      </embed>
  </object>
</noscript>
Image from book

Using the flashvar named myBridge as shown in Listing 22-1 will allow you to access the content of the SWF using FABridge.myBridge.root(). For additional information on using the bridgeName, please see the examples at the end of this chapter.


Memory-Consumption Issues

As of this writing, there are some memory-consumption issues that may evolve because of the limitations in the integration between the JavaScript and ActionScript garbage collectors. Once an ActionScript object has been accessed from JavaScript, it will remain in memory. To release the objects from memory, you can call FABridge.<bridgeName>.releaseASObjects(). This will cause all references to be invalid and will free up the memory. Adobe has stated that it hopes to make the bridge more efficient and will only cache the objects throughout the life of each call.


Flex-Ajax Bridge Samples

The following examples show two different uses of the Flex-Ajax Bridge. The first uses the Flex Validator classes to validate an HTML form. The second example is a simple one showing how to create Flex components using JavaScript.

Using Flex Validators from JavaScript

Flex has a great set of data validators that are very simple to use and have custom error messages predefined. Listing 22-2 shows how you can take advantage of these validators within your HTML form validation. The source code in Listing 22-3 shows both the HTML wrapper file and the Flex root application file that is loaded into the wrapper.

Listing 22-2: ValidateSample.html - the HTML Wrapper File
Image from book

<html>
<head>
<title>Flex Bridge Validate Example</title>
<script src="AC_OETags.js" language="javascript"></script>
<style>
body { margin: 0px; overflow: hidden }
</style>
</head>
<body scroll='no'>
  <br />
  <div align="center">
  <table>
  <form onSubmit="return checkForm(this)">
    <tr>
      <td>e-mail Address:</td>
      <td><input type="text" name="email" /></td>
    </tr>
    <tr>
      <td>Telephone Number:</td>
      <td><input type="text" name="phone" /></td>
    </tr>
    <tr>
      <td colspan="2" align="right"><input type="Submit" value="Validate with Flex"
/></td>
    </tr>
  </form>
  </table>
  </div>

<script language="JavaScript" type="text/javascript">
<!--
    AC_FL_RunContent(
          "src", "Validate",
          "width", "0",
          "height", "0",
          "align", "middle",
          "id", "Validate",
          "quality", "high",
          "bgcolor", "#869ca7",
          "name", "Validate",
          "flashvars","bridgeName=flexValidate",
          "allowScriptAccess","sameDomain",
          "type", "application/x-shockwave-flash",
          "pluginspage", "http://www.adobe.com/go/getflashplayer"
  );
// -->
</script>
<noscript>
  <object classid="clsid:"
      id="Validate" width="1" height="1"
      codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
      <param name="movie" value="Validate.swf" />
      <param name="quality" value="high" />
      <param name="bgcolor" value="#869ca7" />
      <param name="allowScriptAccess" value="sameDomain" />
      <param name="flashvars" value="bridgeName=flexValidate"/>
      <embed src="Validate.swf" quality="high" bgcolor="#869ca7"
        width="0" height="0" name="Validate" align="middle"
        play="true"
        loop="false"
        quality="high"
        allowScriptAccess="sameDomain"
        type="application/x-shockwave-flash"
        pluginspage="http://www.adobe.com/go/getflashplayer">
      </embed>
  </object>
</noscript>

<script src="bridge/FABridge.js" ></script>
<script language="JavaScript" type="text/javascript">
<!--
function checkForm(form) {
  var errors="";
  var email = form.email.value;
  var emailValidate = 'with (FABridge.flexValidate.root()) getMessage
( validateEmail(email) )';
  errors = errors += eval(emailValidate);
  var phone = form.phone.value;
  var phoneValidate = 'with (FABridge.flexValidate.root()) getMessage
( validatePhone(phone) )';
  errors = errors += eval(phoneValidate);
  if(errors.length){
    alert(errors);
    return false;
  }
  alert('Form is valid');
  return true;
}
function getMessage(s){
  if(s.length)return '\n' + s;
  return '';
}
-->
</script>
</body>
</html>
Image from book
Listing 22-3: Validate.mxml - the Source for the Validation SWF Library
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns="*" width="1" height="1">
  <mx:Script>
    <![CDATA[
      import mx.events.ValidationResultEvent;
      import mx.validators.*;

      private var emailValidator:EmailValidator = new EmailValidator();
      private var emailIsValid:ValidationResultEvent;

      public function validateEmail(email:String):String{
        emailValidator.requiredFieldError='e-mail address is required.';
        emailIsValid = emailValidator.validate(email);
        if (emailIsValid.type==ValidationResultEvent.INVALID){
          return emailIsValid.message;;
        }
        return '';
      }

      private var phoneNumberValidator:PhoneNumberValidator =
new PhoneNumberValidator();
      private var phoneIsValid:ValidationResultEvent;

      public function validatePhone(phone:String):String{
        phoneNumberValidator.requiredFieldError='Telephone number is required.';
        phoneIsValid = phoneNumberValidator.validate(phone);
        if (phoneIsValid.type==ValidationResultEvent.INVALID){
          return phoneIsValid.message;;
        }
        return '';
      }
    ]]>
  </mx:Script>
  <bridge:FABridge xmlns:bridge="bridge.*" id="bridgeInst" />
</mx:Application>
Image from book

The Validate.mxml file in Listing 22-3 includes two functions to validate both a phone number and an e-mail address, and it also instantiates the Flex-Ajax Bridge. The HTML wrapper file includes the necessary JavaScript files, as well as the validation SWF. The bridgeName is defined as flexValidate within a Flash variable. The HTML form validates the form fields on submission of the form by calling the checkForm JavaScript function. This function then make calls to the validateEmail and validatePhone functions that are part of the embedded Validate SWF. These two calls are made by creating a local JavaScript variable to hold the ActionScript that will be run using the JavaScript eval function. An example of the syntax to make the call looks like this:

'with (FABridge.flexValidate.root()) getMessage( validateEmail(email) )'

The call is made using the with keyword to set the scope, and then setting a JavaScript handler function to interpret the results. The scope is set to the root of the SWF using FABridge.<bridgeName>.root(). The getMessage function interprets the results of the Flex validators and then builds the errors string, which is returned to the checkForm function. The results are shown in Figure 22-1.

Image from book
Figure 22-1: A JavaScript alert showing the Flex validation messages

There are many additional Flex validators (as well as formatters) that could be added to the Validate SWF, creating a full library of functions that can be used within your HTML forms.

Create Flex Components Using JavaScript

The Flex-Ajax Bridge also provides the ability to create Flex components at run-time from JavaScript. You can create any base component by simply setting up an empty SWF as a Flex-Ajax Bridge, or any other component, as long as you have imported the necessary classes. Listing 22-4 and Listing 22-5 show basically an empty SWF with only a panel to hold the created content and the setup of the FA Bridge.

Listing 22-4: Component.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    width="500" height="300"
 backgroundColor="#FFFFFF">
  <mx:Panel id="panel" title="Create Component Example" width="100%" height="100%"
    paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" />
  <bridge:FABridge xmlns:bridge="bridge.*" id="bridgeInst" />
</mx:Application>
Image from book
Listing 22-5: CreateComponent.html
Image from book

<html>
<head>
<title>Flex Bridge Create Component Example</title>
<script src="AC_OETags.js" language="javascript"></script>
<style>
body { margin: 0px; overflow:hidden }
</style>
</head>
<body scroll='no'>
  <br />
  <div align="center">
  <table>
  <form onSubmit="return createButton(this)">
    <tr>
      <td>Button Label:</td>
      <td><input type="text" name="buttonLabel" value="My Button" /></td>
    </tr>
    <tr>
      <td>Button Width:</td>
      <td><input type="text" name="buttonWidth" value="150" /></td>
    </tr>
    <tr>
      <td>Button Height:</td>
      <td><input type="text" name="buttonHeight" value="25" /></td>
    </tr>
    <tr>
      <td colspan="2" align="right"><input type="Submit" value="Create New Button"
 /></td>
    </tr>
    <tr>
      <td colspan="2">Code sent to Flex</td>
    </tr>
    <tr>
      <td colspan="2"><textarea name="myTA" cols="50" rows="10" readonly=
"true"></textarea></td>
    </tr>
  </form>
  </table>

<script language="JavaScript" type="text/javascript">
<!--
    AC_FL_RunContent(
          "src", "Component",
          "width", "500",
          "height", "300",
          "align", "middle",
          "id", "Component",
          "quality", "high",
          "bgcolor", "#869ca7",
          "name", "Component",
          "flashvars","bridgeName=myBridge",
          "allowScriptAccess","sameDomain",
          "type", "application/x-shockwave-flash",
          "pluginspage", "http://www.adobe.com/go/getflashplayer"
  );
// -->
</script>
<noscript>
  <object classid="clsid:"
      id="Validate" width="500" height="300"
      codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
      <param name="movie" value="Component.swf" />
      <param name="quality" value="high" />
      <param name="bgcolor" value="#869ca7" />
      <param name="allowScriptAccess" value="sameDomain" />
      <param name="flashvars" value="bridgeName=myBridge"/>
      <embed src="Component.swf" quality="high" bgcolor="#869ca7"
        width="500" height="300" name="Component" align="middle"
        play="true"
        loop="false"
        quality="high"
        allowScriptAccess="sameDomain"
        type="application/x-shockwave-flash"
        pluginspage="http://www.adobe.com/go/getflashplayer">
      </embed>
  </object>
</noscript>
</div>
<script src="bridge/FABridge.js" ></script>
<script language="JavaScript" type="text/javascript">
<!--
function createButton(form) {
    var newButton =
      'var btn = FABridge.myBridge.create("mx.controls.Button");\n' +
      'btn.setLabel("'+form.buttonLabel.value+'");\n' +
      'btn.setWidth("'+form.buttonWidth.value+'");\n' +
      'btn.setHeight("'+form.buttonHeight.value+'");\n' +
      'panel().addChild(btn);';
  var temp = "with (FABridge.myBridge.root()) {\n" + newButton + "\n}";
  eval(temp);
  //var newCode = "with (FABridge.myBridge.root()) {\n setCodeTrace
("+newButton+")\n}";
  //eval(newCode);
  form.myTA.value=newButton;
  return false;
}
-->
</script>
</body>
</html>
Image from book

The JavaScript function createButton is executed when the form button is clicked. This function accepts a form object and builds the ActionScript needed to create a Flex Button. It also sets the Button label, width, and height properties by filling in the form values.

Notice that the last line of the newButton string says panel().addChild(btn). The panel() is not actually a Flex function. It is the syntax that is used to access a component within the embedded SWF. The ID of the Panel that the button is being added to is actually named panel, but when accessing it from JavaScript, the parentheses are required. Once the ActionScript String has been created, the JavaScript eval function is run, which creates the button within the embedded SWF.

Figure 22-2 shows the page when it loads, and Figure 22-3 shows the page after the createButton method has been run. Figure 22-3 also shows the JavaScript that was created and passed to Flex.

Image from book
Figure 22-2: Page when it loads
Image from book
Figure 22-3: Page after the createButton method has been run


Summary

The Flex-Ajax Bridge will find its way into the development of Web 2.0 applications because it ties the two leading RIA solutions together into a new hybrid application with hundreds of JavaScript and Flex code libraries.

This chapter provided an overview of why you would use the Flex-Ajax Bridge, requirements, and installation, as well as demonstrations of how the FA Bridge can be used in different ways. Information on possible memory issues was provided as well.

Chapter 23 discusses the ActionScript libraries that are freely available from Adobe Labs. Descriptions are included for all of the available libraries, as well as a fully functioning example showing the YouTube library.


Chapter 23: Using the ActionScript 3.0 Libraries

Overview

The ActionScript 3.0 libraries are a free set of libraries that Adobe’s Developer Relations Team has released to the public. These libraries help developers get started when building Flex 2.0 applications. The libraries are split up into seven separate projects with their own distinctive functionalities.

The libraries are available on Adobe Labs, which is a Web site that provides you with the opportunity to experience and evaluate new and emerging technologies and products from Adobe.

At Adobe Labs, you have access to resources such as the following:

  • Prerelease software and technologies

  • Code samples

  • Early versions of products and documentation

  • Forums and wiki-based content to help you interact with like-minded developers


Types of Libraries

The following is list of libraries that have been updated to work with the final release of Flex Builder 2.0 and MXMLC. Note that these libraries are of beta quality and that Adobe does not officially support them.

  • Corelib - The Corelib library consists of several basic utilities for MD5 hashing, JavaScript Object Notation (JSON) serialization, advanced string and date parsing, and more. Authors of this project are Christian Cantrell, Mike Chambers, Daniel Dura, and Darren Schall.

  • FlexUnit - The FlexUnit library is a unit testing framework for Flex and ActionScript 3.0 applications. It copies the functionality of JUnit (a Java unit-testing framework), and includes a graphical test runner application built in Flex 2.0. Authors of the project are Matt Chotin, Daniel Dura, Alistair Mc Lead, Tom Ruggles, Steven Webster, and Jason Williams. All projects use the FlexUnit framework to test the libraries and ensure that they are working correctly.

  • Flickr - The Flickr library is an ActionScript 3.0 API for use with the popular online photo-sharing Web application, Flickr. This library provides access to the entire Flickr API. The author of this project is Darren Schall.

  • Mappr - The Mappr library is an ActionScript 3.0 API that provides access to Mappr’s geo-tagged image data. Mappr is a service that combines images from Flickr with geographically located information. The author of this project is Mike Chambers.

  • RSS and Atom - The RSS and Atom libraries are used to parse Atom and all versions of RSS easily. You can parse any type of feed without knowing what kind of feed it is. The author of this project is Christian Cantrell.

  • Odeo - The Odeo library is an ActionScript 3.0 API for searching and retrieving podcasts from Odeo. Odeo is a service that provides functionality to listen to, upload, and record your own podcasts. The author of this project is Mike Chambers.

  • YouTube - The YouTube API provides an ActionScript 3.0 API to search for videos from YouTube. The author of this project is Daniel Dura.


How to Include the SWC in Your Application

To include the SWC in your application, you must first download a library, such as the Corelib library that is used here for reference. Open the ZIP file and you will find three folders inside the corelib folder: bin, docs, and src. The bin folder contains the binary SWC file for use within your application.

Be sure you know from where you extracted the files, and make a note as to where the binary SWC is. Open up Flex Builder 2 and select File Image from book Flex Project to see the screen shown in Figure 23-1.

Image from book
Figure 23-1: New Flex Project opening screen

Follow the wizard and create a Flex project with a name and path, as shown in Figure 23-2. Then, click Next.

Image from book
Figure 23-2: Assigning a name and path

As shown in Figure 23-3, you can either change the Main application file to whatever you like, or leave it as is.

Image from book
Figure 23-3: Set build paths

Select the Library Path tab and click the Add SWC button (Figure 23-4). Locate the binary SWC file in the bin directory of the unzipped Corelib library on your hard disk.

Image from book
Figure 23-4: Add SWC button

You should see that it has been added to the build path libraries tree. Click the Finish button and you should be ready to use the Corelib library in your Flex application.


Building a Simple Application Using One of the Libraries

In Chapter 21 you learned how to build an application in the Cairngorm Framework. This example uses the Cairngorm Framework and the YouTube ActionScript 3 library.

Figure 23-5 shows the completed application running in Flex.

Image from book
Figure 23-5: Completed application

Listings 23-1 through 23-8 show the files that make up the application structured using the Cairngorm Framework. The only difference is that there is no Server Locator or any Business Delegates.

Listing 23-1: Main.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:business="com.wiley.proflex2.chapter25.business.*"
     xmlns:view="com.wiley.proflex2.chapter25.view.*"
     xmlns:control="com.wiley.proflex2.chapter25.control.*">

     <mx:Script>
          <![CDATA[

               import com.wiley.proflex2.chapter25.model.DataModel;

               [Bindable]
               public var model:DataModel = DataModel.getInstance();

          ]]>
     </mx:Script>

     <mx:Style>

          Application
          {
               backgroundColor: #888888;
          }

          Label
          {
               fontFamily: Arial;
               fontSize: 11;
          }

          Button, ComboBox
          {
               highlightAlphas: 0.37, 0.73;
               fillAlphas: 0.6, 0.53, 0.88, 0.63;
               borderColor: #EEEEEE;
               themeColor: #0099cc;
               cornerRadius: 3;
          }

          @font-face
          {
              src: url(assets/fonts/arial_fonts.swf);
              fontFamily: Arial;
          }

          @font-face
          {
              src: url(assets/fonts/arial_fonts.swf);
              fontFamily: Arial;
              fontWeight: bold;
          }

     </mx:Style>

     <!-- ========================================================================== -->

     <!-- the ServiceLocator where we specify the remote services -->
     <!--<business:Services id="loginServices" /> -->

     <!-- the FrontController, containing Commands specific to this application -->
     <control:ApplicationController id="controller" />

     <!-- ========================================================================== -->

     <view:SearchForm />
     <mx:HBox>
          <view:VideoPlayer />
          <view:VideoListView videos="{model.videos}" />
     </mx:HBox>

</mx:Application>
Image from book
Listing 23-2: GetVideosByTagCommand.as
Image from book

package com.wiley.proflex2.chapter25.commands
{
     import mx.rpc.IResponder;
     import mx.utils.ObjectUtil;
     import mx.controls.Alert;

     import com.adobe.cairngorm.control.CairngormEvent;
     import com.adobe.cairngorm.commands.ICommand;

     import com.adobe.webapis.youtube.YouTubeService;
     import com.adobe.webapis.youtube.methodgroups.Videos;
     import com.adobe.webapis.youtube.events.YouTubeServiceEvent;

     import com.wiley.proflex2.chapter25.events.GetVideosByTagEvent;
     import com.wiley.proflex2.chapter25.model.DataModel;

     public class GetVideosByTagCommand implements ICommand
     {
          public function execute( event : CairngormEvent ) : void
          {
               var youTubeService:YouTubeService = new YouTubeService();
               youTubeService.apiKey = model.API_KEY;
               youTubeService.addEventListener(YouTubeServiceEvent
.VIDEOS_LIST_BY_TAG, result);
               var videos:Videos = new Videos(youTubeService);
               videos.listByTag(GetVideosByTagEvent(event).tag);
          }

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

          public function result( event : YouTubeServiceEvent ) : void
          {
               model.videos.source = event.data.videoList;
          }

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

          public function fault( event : Object ) : void
          {
               Alert.show(event.fault);
          }

          [Bindable]
          public var model:DataModel = DataModel.getInstance();
     }
}
Image from book
Listing 23-3: ApplicationController.mxml
Image from book

package com.wiley.proflex2.chapter25.control
{
     import com.adobe.cairngorm.control.FrontController;
     import com.wiley.proflex2.chapter25.commands.*;

     public class ApplicationController extends FrontController
     {
          public function ApplicationController()
          {
               addCommand( ApplicationController.EVENT_GET_VIDEOS_BY_TAG,
GetVideosByTagCommand );
          }

          public static const EVENT_GET_VIDEOS_BY_TAG : String = "getVideosByTag";
     }
}
Image from book
Listing 23-4: GetVideosByTagEvent.as
Image from book

package com.wiley.proflex2.chapter25.events
{
     import com.adobe.cairngorm.control.CairngormEvent;
     import com.wiley.proflex2.chapter25.control.ApplicationController;

     public class GetVideosByTagEvent extends CairngormEvent
     {
          public function GetVideosByTagEvent(tag:String)
          {
               super( ApplicationController.EVENT_GET_VIDEOS_BY_TAG );
               this.tag = tag;
          }

          public var tag : String;
     }
}
Image from book
Listing 23-5: DataModel.as
Image from book

package com.wiley.proflex2.chapter25.model
{
     import com.adobe.cairngorm.model.DataModel;
     import mx.collections.ArrayCollection;
     import com.adobe.webapis.youtube.Video;

     [Bindable]
     public class DataModel implements com.adobe.cairngorm.model.DataModel
     {
          private static var dataModel:com.wiley.proflex2.chapter25.model.DataModel;

          public static function getInstance():com.wiley.proflex2.chapter25
.model.DataModel
          {
               if (dataModel == null)
                    dataModel = new com.wiley.proflex2.chapter25.model.DataModel();
               return dataModel;
          }

          public function DataModel()
          {
               if ( com.wiley.proflex2.chapter25.model.DataModel.dataModel != null )
                    throw new Error( "Only one DataModel instance should be
instantiated" );

               initCollections();
          }

          private function initCollections():void
          {
               videos = new ArrayCollection();
          }

          // The list of videos
          public var videos:ArrayCollection;

          public var videoId:String;

          public const API_KEY:String = "YOUR-YOUTUBE-API-KEY";
     }
}
Image from book
Listing 23-6: SearchForm.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[
               import com.wiley.proflex2.chapter25.events.GetVideosByTagEvent;
               import com.adobe.cairngorm.control.CairngormEventDispatcher;
          ]]>
     </mx:Script>

     <mx:Form>
          <mx:FormItem label="Search by Tag">
               <mx:TextInput id="tag" />
          </mx:FormItem>
          <mx:FormItem>
               <mx:Button label="Search" click="CairngormEventDispatcher
.getInstance().dispatchEvent(new GetVideosByTagEvent(tag.text))" />
          </mx:FormItem>
     </mx:Form>

</mx:VBox>
Image from book
Listing 23-7: VideoListView.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns:filters="flash.filters.*">

     <mx:Script>
          <![CDATA[

               import mx.collections.ArrayCollection;
               import com.wiley.proflex2.chapter25.model.DataModel;
               import com.adobe.cairngorm.control.CairngormEventDispatcher;

               [Bindable]
               public var videos:ArrayCollection;

               [Bindable]
               public var model:DataModel = DataModel.getInstance();

          ]]>
     </mx:Script>

     <mx:DataGrid width="500" height="400" dataProvider="{videos}" change=
"model.videoId = event.currentTarget.selectedItem.id">
          <mx:columns>
               <mx:DataGridColumn dataField="title" headerText="Title" />
               <mx:DataGridColumn dataField="lengthSeconds" headerText=
"Length (seconds)" />
               <mx:DataGridColumn dataField="author" headerText="Author" />
          </mx:columns>
     </mx:DataGrid>

</mx:VBox>
Image from book
Listing 23-8: VideoPlayer.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import com.wiley.proflex2.chapter25.model.DataModel;

               [Bindable]
               public var model:DataModel = DataModel.getInstance();

          ]]>
     </mx:Script>

     <mx:VideoDisplay id="vidDisplay" width="425" height="350"
          source="http://youtube.com/get_video?video_id=CwUPAFFRMns&amp;t=
OEgsToPDskIPR4of8rRS9GKf8lAIGjET" />

     <mx:Label text="{model.videoId}" />

     <mx:HBox width="320">
          <mx:Button label="Play" click="vidDisplay.play()" />
          <mx:Button label="Pause" click="vidDisplay.pause()" />
     </mx:HBox>

</mx:VBox>
Image from book


Summary

The YouTube application built in this chapter shows how you can easily integrate Cairngorm and other Open Source libraries. The YouTube library added functionality to the application so that you can search for the latest videos on YouTube by tag. Integration with rich media was also very easy because the Flex Framework provides all the components and libraries required to do this.

Chapter 24 examines how newer versions of ColdFusion and Flash Remoting can be used to share structured data.


Chapter 24: Using ColdFusion/Flex Connectivity

The combination of Flex 2 and ActionScript means new standards. The Flash Player’s ability to connect and share structured data with ColdFusion predates Flex, with the introduction of Flash Remoting in 2002. ColdFusion 7 introduced event gateways that allowed ColdFusion to communicate in ways that went beyond what the browser has to offer: talking Short Message Service (SMS), instant messaging, and interacting with Java Messaging Services (JMS).

ColdFusion 7.0.2 was released at the same time as Flex 2. It introduced a new version of Flash Remoting that featured a new standard, Action Messaging Format version 3 (AMF3), which offers compatibility with ActionScript 3 and support for new data types. ColdFusion 7.0.2 also included the Flex Messaging Event Gateway, which allows ColdFusion applications to send and receive messages with Flex Data Services (FDS).

Flex Builder 2 is new from the ground up, built on top of Eclipse. It doesn’t support ColdFusion directly, but has included with it a number of wizards and plugins bundled together as the ColdFusion Extensions for Flex Builder. These offer secure connectivity to the ColdFusion server for data maintenance, file management, and query building.

Using the Flash Remoting Update

Flash Remoting has been available to developers since 2002 with the release of ColdFusion 6 and JRun 4. It allows the Flash Player and the ColdFusion server to communicate with each other, sending data in both directions using Action Messaging Format (AMF), a protocol developed by Macro media (now Adobe).

One of the great advantages of Flash Remoting is the ease of communication between Flex and ColdFusion. The original structure of data is preserved during that communication, converted by a Flash Remoting API on the client side and automatically handled by ColdFusion on the server side. AMF translates between ColdFusion and ActionScript native data types in both directions automatically. The data’s structure is represented using an XML schema inspired by the Simple Object Access Protocol (SOAP). It is transported via HTTP as a binary file to improve the packet size for transmission (offering packets up to 75 percent smaller than SOAP packets with equivalent data).

The ColdFusion 7.0.2 Flash Remoting Updater is available as an update installer for ColdFusion, or you can download the latest release of ColdFusion (version 7.0.2). Updating to 7.0.2 means that you have a version of Flash Remoting that can talk to applications via AMF3, the latest version of AMF (required for Flex 2 applications). AMF3 makes use of ActionScript 3.0, sending data more efficiently over a network connection than its predecessor, and supporting new data types introduced with ActionScript 3.0 (ByteArray and XML, for example).

Following are third-party plugins for other application servers that also offer Flash Remoting:

  • AMFPHP (http://www.amfphp.org/) - This is a free community project that currently only supports the original AMF0 protocol, meaning that you are unable to take advantage of ActionScript 3 features.

  • FLUORINE (http://fluorine.thesilentgroup.com/) - This is an Open Source .NET Remoting gateway that supports AMF3.

  • WebOrb (http://www.themidnightcoders.com/weborb/) - This is also a gateway for .NET, the commercial version of which supports AMF3.

The ColdFusion server is configured for Flash Remoting via an XML file, services-config.xml. This is located in {ColdFusion webroot}\WEB-INF\flex\. Flex Builder uses project properties to dynamically fill a number of variables in the configuration file (such as the location of the ColdFusion server). A new feature of ColdFusion 7.0.2 is a separate panel in the ColdFusion Administrator for managing Flex integration. Looking under the Data & Services category of tools, you will find that it offers control for both Flash Remoting and FDS support. These two options are switched on by default.

It’s important to select the right kind of Flex project in Flex Builder 2 for your ColdFusion Flash Remoting application. There are additional settings for Flash Remoting, including additional compiler arguments that point to services-config.xml on the ColdFusion server.

Follow these steps to create a new Flex Builder project that will be deployed on ColdFusion:

  1. Choose File Image from book New Image from book Flex Project.

  2. Choose ColdFusion Flash Remoting Service (Figure 24-1).

    Image from book
    Figure 24-1: ColdFusion Flash Remoting Service option

  3. Enter the root folder and root URL of the ColdFusion server.

  4. Enter a project name and the root folder of the ColdFusion server.

  5. Select the output folder that will be used by the ColdFusion server.

If you check the properties of a ColdFusion-based project after it’s been created, you can see that an argument locating the services-config.xml file has been added to the compiler settings, as shown in Figure 24-2.

Image from book
Figure 24-2: The additional compiler arguments for ColdFusion Flash Remoting

You should be familiar with the RemoteObject component, discussed in Chapter 11. The RemoteObject component is used to access ColdFusion via Flash Remoting. Set the RemoteObject component’s destination attribute to ColdFusion, and the source attribute to the location of the ColdFusion Component (CFC) that you’re accessing for data.

The location of the CFC is called in the same way that you would invoke the CFC within your ColdFusion Markup Language (CFML). You locate it by its position under the server Web root. Use dot notation instead of slashes to indicate the directory structure, and omit the extension at the end.

The following example code is calling a CFC called FlexData.cfc located in the directory {Web root}/components/data. This directory can be either physically under the Web root, or a Web server virtual directory. The important thing to note is that to the server, the directory resides under the Web root.

<mx:RemoteObject
  id="myService"
  destination="ColdFusion"
  source="components.data.FlexData"
  result="myResultHandler(event)"
  fault="myFaultHandler(fault)"
  showBusyCursor="true"/>

The server’s XML configuration file can be edited to include the location of a CFC as a mapping, or named resource. The named resource entry has the location of the CFC and the name for the mapping. Following is an example of an entry for the CFC called in the preceding example of the RemoteObject component:

<destination id="myComponentID">
     <channels>
       <channel ref="my-cfamf"/>
  </channels>
     <properties>
          <source> components.data.FlexData </source>
          <lowercase-keys>true</lowercase-keys>
     </properties>
</destination>

This mapping is then used as the value for the destination argument of the RemoteObject component. You would also omit the source argument of the component call because its value is defined in the named resource.

<mx:RemoteObject
     id="myService"
     destination=" myComponentID "
     result="myResultHandler(event)"
     fault="myFaultHandler(fault)"
     showBusyCursor="true"/>

The RemoteObject components must be called by an event (either system- or user-generated). In this case, use the creationComplete event of the Application tag to fetch data from a CFC for the application once it’s ready to run:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="myService.simpleString()">

The results handler is a function that you will build to handle the results returned by the CFC. How you construct that will depend on your business requirements. It should receive one argument data typed as ResultEvent. You will need to import the ResultEvent class to handle the result.

<mx:Script>
     <![CDATA[

          import mx.rpc.events.ResultEvent;

          private function myResultHandler(event:ResultEvent):void {
          myLabel.text = new String(event.result as String);
     }

     ]]>
</mx:Script>

The handler in the preceding example code will accept the response from the RemoteObject component call and access the result property of the object that’s called. This example receives a string value. Notice that the value has been data typed as String to ensure that it’s compatible with the Label component’s attribute that it’s being assigned to. Following is the complete code for the MXML file:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="myService.simpleString()">

     <mx:Script>
     <![CDATA[

          import mx.rpc.events.ResultEvent;

          private function myResultHandler(event:ResultEvent):void {
               myLabel.text = new String(event.result as String);
          }

     ]]>
     </mx:Script>

<mx:RemoteObject id="myService" destination="ColdFusion"      source=
"components.data.FlexData" result="myResultHandler(event)"      fault=
"myFaultHandler(fault)" showBusyCursor="true"/>

     <mx:Label id="myLabel"/>

</mx:Application>

The CFC being used for this example is quite simple. The following example has a single function that returns a string variable. What’s needed to make this work for Flash Remoting is to set the access property of the CFFunction tag to "remote", as shown here:

<cfcomponent name="FlexData" hint="Returns data for Flash Remoting">
     <cffunction name="simpleString" access="remote" returntype="string">
          <cfset var greeting = "Hello world"/>
          <cfreturn greeting/>
     </cffunction>
</cfcomponent>

ColdFusion will send data to Flex preserved in its original structure, with the exception of queries. There’s no equivalent native data type to query in Flash. The previous version of Flash Remoting basically had a hack to process a query into an array of untyped objects, which Flash could then understand. This meant that data conversion had to occur on the client side as it was received, resulting in performance problems with large record sets of data.

The solution to this problem is the introduction of the ArrayCollection, a new data type analogous to an array of objects. ColdFusion 7.0.2 will handle the conversion of queries to ArrayCollections and reverse as it transmits data backward and forward via Flash Remoting. The following example code calls a method on a CFC that returns a query, converted by Flash Remoting into an ArrayCollection:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="myService.simpleQuery()">

     <mx:Script>
     <![CDATA[

          import mx.rpc.events.ResultEvent;
          import mx.collections.ArrayCollection;

          [Bindable]
          private var simpleData:ArrayCollection;

          private function myResultHandler(event:ResultEvent):void {
               simpleData = event.result as ArrayCollection;
          }

     ]]>
     </mx:Script>

     <mx:RemoteObject id="myService" destination="ColdFusion"
      source="components.data.FlexData" result="myResultHandler(event)"
      fault="myFaultHandler(fault)" showBusyCursor="true"/>

     <mx:DataGrid id="myData" dataProvider="{simpleData}" width="500"/>

</mx:Application>

Notice that the ArrayCollection class has been imported and a bindable variable has been created to store the result, data typing it as an ArrayCollection. In the result handler method, the variable has been set to the result, again casting it to ArrayCollection to ensure that it’s the proper data type. For now, the data is being bound as the dataProvider property of a DataGrid component so as to dump it temporarily while performing the development work.

Following is an example of the CFC for this data:

<cfcomponent name="FlexData" hint="Returns data for Flash Remoting">
     <cffunction name="simpleQuery" access="remote" returntype="query">
          <cfquery name="qGetEmployees" datasource="employees">
          SELECT * from employees
          </cfquery>
          <cfreturn qGetEmployees>
     </cffunction>
</cfcomponent>

The RemoteObject tag can be modified so that you can call multiple methods on the CFC. This is done by nesting method tags containing the details of each method on the CFC that you will connect to.

<mx:RemoteObject id="myService" destination="ColdFusion"
source="components.data.FlexData" showBusyCursor="true">
     <mx:method name="fetchDepartments" result="departmentResultHandler(event)"/>
     <mx:method name="insertEmployee" result="insertEmpResultHandler(event)"/>
</mx:RemoteObject>

Notice that there are two methods in this example, each with a different result handler. You will call them on an event in exactly the same way as previously described.

Data can be passed to the CFC as part of the call so that you can do things such as handling form submission or doing parameterized searching. Multiple values can be passed as a comma-separated list:

myService.insertEmployee(fname,lname,email);

The argument could instead be passed as a complex object. The following sample code takes the values from a form, makes them properties of a value object (VO), and passes that object as an argument in the last line of the function:

<mx:Script>
     <![CDATA[
          import EmployeeVO;

          private function submitForm():void {
          var empData:EmployeeVO = new EmployeeVO();
          empData.fname = fname.text;
          empData.lname = lname.text;
          empData.email = email.text;
          empData.mobilePhone = mobilePhone.text;
          empData.department = selectedItem.departmentID;
          myService.insertEmployee(empData);
     }

     ]]>
</mx:Script>

Following is the class for the VO used in the preceding example code. The VO allows you to data-type the properties of the structured data that you are passing back to the CFC via Flash Remoting.

package
     {
     [Bindable]
     public class EmployeeVO
     {
          public var fname:String = "";
          public var lname:String = "";
          public var email:String = "";
          public var mobilePhone:String = "";
          public var department:int = 0;

          public function EmployeeVO()
          {
          }
     }
}

Each of the properties of this object match arguments within the CFC’s method that you are calling. Following is the code for the method:

<cffunction name="insertEmployee" access="remote" returntype="boolean">
     <cfargument name="fname" required="true" type="string" default="wally">
     <cfargument name="lname" required="true" type="string">
     <cfargument name="email" required="true" type="string">
     <cfargument name="mobilePhone" required="true" type="string">
     <cfargument name="department" required="true" type="numeric">
     <cfset var success = true>
     <cftry>
          <cfquery name="qInsertEmp" datasource="employees">
          INSERT INTO employees (fname,lname,email,mobilePhone,department)
          VALUES ("#fname#","#lname#","#email#","#mobilePhone#",#department#)
          </cfquery>
          <cfcatch type="database">
               <cfset success = false>
          </cfcatch>
     </cftry>
     <cfreturn success>
</cffunction>

You are taking the object that’s passed to the CFC’s method and inserting the values into the database as a new record, returning a Boolean based on whether or not the database activity is a success, using a simple CFTRY/CFCATCH technique for the database activity trapping. Back in the MXML file, you will handle the result of the database with an Alert component to notify you if the action was a success.

Following is the complete MXML file. Notice that there are two methods on the CFC that you are calling. The first is called by the creationComplete event of the Application tag, pulling data back from the CFC to populate a ComboBox component in the form. The second result handler is for the Boolean that the insert method on CFC will return. It uses an Alert component to inform you if the insert action was a success.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="myService.fetchDepartments()">

     <mx:Script>
     <![CDATA[
          import mx.rpc.events.ResultEvent;
          import mx.collections.ArrayCollection;
          import mx.controls.Alert;
          import EmployeeVO;

          [Bindable]
          private var departments:ArrayCollection;

          [Bindable]
          private var selectedItem:Object;

          private function departmentResultHandler(event:ResultEvent):void {
               departments = event.result as ArrayCollection;
               departmentCombo.enabled = true;
          }

          private function insertEmpResultHandler(event:ResultEvent):void {
               if (Boolean(event.result) == true) {
                    Alert.show("New employee successfully added", "Employee added");
          } else {
               Alert.show("There was an error adding the new employee", "Error");
          }
     }

     private function submitForm():void {
          var empData:EmployeeVO = new EmployeeVO();
          empData.fname = fname.text;
          empData.lname = lname.text;
          empData.email = email.text;
          empData.mobilePhone = mobilePhone.text;
          empData.department = selectedItem.departmentID;
          myService.insertEmployee(empData);
     }

     ]]>
     </mx:Script>

<mx:RemoteObject id="myService" destination="ColdFusion" source="
components.data.FlexData" showBusyCursor="true">
     <mx:method name="fetchDepartments" result="departmentResultHandler(event)"/>
     <mx:method name="insertEmployee" result="insertEmpResultHandler(event)"/>
</mx:RemoteObject>

<mx:Form>
     <mx:FormItem label="First Name">
          <mx:TextInput id="fname"/>
     </mx:FormItem>
     <mx:FormItem label="Last Name">
          <mx:TextInput id="lname"/>
     </mx:FormItem>
     <mx:FormItem label="Email">
          <mx:TextInput id="email"/>
     </mx:FormItem>
     <mx:FormItem label="Mobile Phone">
          <mx:TextInput id="mobilePhone"/>
     </mx:FormItem>
     <mx:FormItem label="Department">
          <mx:ComboBox id="departmentCombo" dataProvider="{departments}"
          labelField="departmentName" prompt="Please select" enabled="false"
          close="selectedItem=ComboBox(event.target).selectedItem" />
     </mx:FormItem>
     <mx:FormItem>
          <mx:Button id="submit" label="submit" click="submitForm()"/>
     </mx:FormItem>
</mx:Form>

</mx:Application>

Following is the CFC that is being called via Flash Remoting. It has two methods: one that will be used to populate the form’s ComboBox component, and the other to insert a new record in the database using the data from the form.

<cfcomponent name="FlexData" hint="Returns data for Flash Remoting">

     <cffunction name="fetchDepartments" access="remote" returntype="query">
          <cfquery name="qGetDepartments" datasource="employees">
          SELECT * from departments
          </cfquery>
          <cfreturn qGetDepartments>
     </cffunction>

     <cffunction name="insertEmployee" access="remote" returntype="boolean">
          <cfargument name="fname" required="true" type="string" default="wally">
          <cfargument name="lname" required="true" type="string">
          <cfargument name="email" required="true" type="string">
          <cfargument name="mobilePhone" required="true" type="string">
          <cfargument name="department" required="true" type="numeric">
          <cfset var success = true>
          <cftry>
               <cfquery name="qInsertEmp" datasource="employees">
               INSERT INTO employees (fname,lname,email,mobilePhone,department)
               VALUES ("#fname#","#lname#","#email#","#mobilePhone#",#department#)
               </cfquery>
               <cfcatch type="database">
                    <cfset success = false>
               </cfcatch>
          </cftry>
          <cfreturn success>
     </cffunction>

</cfcomponent>

Although the cftry/cfcatch method of error trapping is simple and effective, you should not implement it until the method is fully tested, because it will suppress database error messages. This makes it a little difficult to debug.

Tools available to developers allow for the monitoring and testing of Flash Remoting applications. ServiceCapture (http://kevinlangdon.com/serviceCapture/) is for Windows only, and Charles (http://www.xk72.com/charles/) is a Java-based application that will run on Windows, Mac OS X, and Linux. Both were developed for the monitoring and analysis of Flash Remoting, and do this by capturing and interpreting HTTP traffic on your computer.


Using the Flex Messaging Event Gateway

The release of ColdFusion 7 introduced a number of event gateways for going beyond browser protocols. Included with its initial release were gateways for communicating with Short Message Service (SMS), instant messaging, Java Messaging Service (JMS), sockets, and server directory monitoring. ColdFusion 7.0.2 includes a Flex Messaging Event Gateway that allows ColdFusion applications to send and receive messages with FDS. Event gateways are only supported in the ColdFusion Enterprise edition.

Flex can use ColdFusion CFCs to send messages as part of a Flex publish-subscribe messaging application. Flex publish-subscribe messaging applications have the following named elements:

  • Producer - The term given for the file that originates either the message or message request. It’s likely to be the MXML file being viewed. The message would be created here and sent to a destination.

  • Destination - The destination is the file that is listening for messages on the server.

  • Consumer - The consumer is the logic (either contained within a page or incorporated into a CFC) that processes any messages sent to it via the producer. It would then respond to the producer via the gateway.

The producer and consumer do their thing by exchanging messages between each other via the destination.

Both ColdFusion and Flex are capable of commencing the messaging process, because ColdFusion can broadcast to Flex, or Flex could send a message to ColdFusion.

Flex Messaging Event gateways are created on the ColdFusion Administrator. They can be configured to control IP access, specify a separate server machine for FDS, or control access to code while processing a gateway request. This configuration is done either in the calling message, or with the use of a configuration file.

The configuration file is in the form of a Java properties file. It will have the following properties:

  • destination - Allows you to specify a destination. Overrides any destination information within the message.

  • host - The host name or IP address of the FDS server.

  • allowedIPs - A comma-delimited list of IP addresses that the gateway is allowed to accept messages from.

Here’s an example of what a configuration file would look like:

#
# Flex event gateway configuration
#
# Destination
destination=Flex2CF702emailPopApp
# Hostname or IP address of the Flex Enterprise Server.
host=127.0.0.1:8700
# IP addresses from which the application will accept messages.
allowedIPs=198.162.0.2,198.162.0.7

Configuration files are saved to the ColdFusion server in the {CF directory}/gateway/config/ directory with a .cfg extension. There are a number of template configuration files there by default that would be worth having a look at before making your first configuration.

FDS must be configured to communicate via the Flex Messaging Event Gateway with ColdFusion. It uses the XML file messaging-config.xml to configure it for all messaging. There is an <adapter> section in the file to which you add the following to enable communication with ColdFusion:

<adapter-definition id="cfgateway" class="coldfusion.flex.CFEventGatewayAdapter"/>

You can find an example of a messaging-config.xml that includes the ColdFusion definition in FDS at C:\fds2\resources\config\flex. You will need to locate the messaging-config.xml for the Web application that you wish to add the configuration to. Using the samples directory from the standard FDS install as an example Web application, the messaging-config.xml would be found in the directory located at C:\fds2\jrun4\servers\default\samples\WEB-INF\flex.

The next step in preparing to work with the Flex Messaging Event Gateway is to add to the messaging config.xml file a destination definition for the ColdFusion gateway. The example version of messaging-config.xml mentioned previously has a detailed sample of a ColdFusion Flex Messaging <destination> tag to copy from, if required. The definition looks like this:

<destination id="ColdFusionGateway">
  <adapter ref="cfgateway" />
  <properties>
                    <gatewayid>*</gatewayid>
  </properties>
  <channels>
                    <channel ref="my-rtmp"/>
                   <channel ref="my-polling-amf"/>
     </channels>
</destination>

Each Web application should have its own unique destination ID. The example being used here creates a destination ID for the Samples Web application. You should assign a different destination ID for the Flex Web application to ensure that ColdFusion doesn’t have two choices.

It is possible to create VOs on ColdFusion and transfer objects to Flex via the gateway with the data typing of the various properties of the VO intact. You must include the necessary configuration details in the services-config.xml file of your Web application. Following is an example of these. You can also find an example in the sample services-config.xml in the C:\fds2\resources\config folder.

<!-- ColdFusion specific HTTP channel -->
<channel-definition id="cf-polling-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint
uri="http://{server.name}:{server.port}/{context.root}/messagebroker/
cfamfpolling"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<serialization>
<!-- This must be turned off for any CF channel -->
<instantiate-types>false</instantiate-types>
</serialization>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>8</polling-interval-seconds>
</properties>
</channel-definition>

The Structure of Messages

The process of using a Flex Messaging gateway passes data between ColdFusion and FDS in a predetermined structure. You must be familiar with the structure and its elements so that you can ensure that data is read and transmitted in the right format.

The following elements are required when constructing a structure to send in a message from ColdFusion to FDS via the Flash Gateway:

  • body - The body of the message (required).

  • CorrelationID - The Correlation identifier of the message.

  • Destination - The Flex destination of the message (required if not in the configuration file).

  • Headers - A CFML structure that contains the header keys and values. Used if the message contains any containers.

  • LowercaseKeys - Forces the structure key names to be lowercase when the ActionScript types are created. ActionScript 3 is case-sensitive. This would allow for a constant lowercase to be used.

  • TimeToLive - The number of milliseconds that the current message is valid.

The messaging gateway will also add on the following additional elements:

  • MessageID - A Universally Unique Identifier (UUID).

  • Timestamp - The time that the message was sent.

  • ClientID - The ID of the Flex Messaging gateway instance (equal to the ColdFusion session ID).

Messages can be sent from CFML to Flex via the Flex Messaging Gateway using one of two methods. The typical way would be to use the cfreturn tag within a CFC function. There is also a SendGatewayMessage function specifically for sending messages via the gateway.

The following example creates a ColdFusion structure with two of the keys listed previously (body and Destination) and uses the SendGatewayMessage function to send the values back to FDS:

<cfset success = StructNew()>
<cfset success.body = "SMS was sent at " & Now()>
<cfset success.Destination = "flexgateway">
<cfset ret = SendGatewayMessage("Flex2CF702", success)>

The data that ColdFusion will receive via the gateway will be structured in a specific structure as well. Its key/value pairs are similar to the outgoing packet and are as follows:

  • body - The body of the message.

  • ClientID - The ID of the client that sent the message (equal to the ColdFusion session ID).

  • CollectionID - The Collection identifier of the message.

  • Destination - The Flex destination of the message (required if not in the configuration file).

  • Headers - A CFML structure that contains the header keys and values. Used if the message contains any containers.

  • Timestamp - The time that the message was sent.

The gateway will also add on the following:

  • messageID - A UUID.

  • timeToLive - The number of milliseconds that the current message is valid.

Armed with the knowledge of how the data will be structured, you can now construct the CFML to process the data that comes through the gateway. Your CFC should have a function called onIncomingMesage. This is the default that will be called by the Flex Messaging Gateway when a message is transmitted to the CFC.

The actual structure of the message will be embedded within the data property of an object called event. Your code would be calling the value at event.data.body.username if you needed to access a username property that was passed from the transmitting Flex file.

In the following example CFC, you will notice the single argument event in the onIncomingMessage function. The code creates a variable formDetails set equal to event.data.body.

<cfcomponent name="PopGateway" hint="Demo application that illustrates how to use
the Flex Gateway">
     <cffunction name="onIncomingMessage" access="remote" returntype="query">
          <cfargument name="event" type="struct" required="true">
          <cfset formDetails = event.data.body>
          <cfpop action="getheaderonly" name="GetHeaders"      startrow="1"
maxrows="10" timeout="15" server="#formDetails.popserver#"
username="#formDetails.username#" password="#formDetails.pwd#">
          <cfreturn GetHeaders>
     </cffunction>
</cfcomponent>

Web applications built with FDS, ColdFusion, and the Flex Messaging Event Gateway can be secured by either restricting IP addresses, or by making use of remote credentials.

With a configuration file, you can restrict which IP addresses the ColdFusion server will accept messages from. The configuration file (mentioned previously) allows the administrator to nominate the host and destination addresses, as well as the IP addresses, that messages can be accepted from.

Flex has a built-in function to handle user authentication with ColdFusion. Using the setRemoteCredentials method before sending a message through the gateway allows you to transmit values for username and password, allowing ColdFusion to then utilize its cflogin tag within Application.cfm or Application.cfc. Following is an example of the setRemoteCredentials method:

var msg:Message = new AsyncMessage();
msg.body = {fname:fname.text,lname:lname.text,email:email.text};
msg.headers.gatewayID = "Flex2CF702";
msg.setRemoteCredentials(myUserName, myPassword);


Using the ColdFusion Event Gateway Adapter

FDS has a number of Message Service adapters that provide you with the means to create a publish-subscribe messaging system. FDS has adapters for ActionScript Messaging, JMS Messaging, and Cold Fusion. With the ActionScript Messaging adapter, you could have two Flex-based applications communicate with each other (for example, have an order UI communicating directly with the fulfillment UI, both running in different locations on separate clients). The JMS Messaging adapter could be used to build a live stock feed, utilizing Java to fetch the required data, and displaying it in a Flex application either via charting, tabular format, or a combination of both.

ColdFusion 7.0.2 includes a Flex Messaging Gateway that you can call from FDS, thus allowing you to build Flex applications that can communicate directly with ColdFusion to produce publish-subscribe messaging applications. ColdFusion 7.0.2 has a number of other gateways, including a directory watcher to monitor changes to a specific directory and its contents on the file system. Another ColdFusion Gateway is an SMS gateway that allows an application to send a text message to a mobile phone.

The idea behind this kind of architecture is that a producer (in this chapter’s examples, an MXML file) creates a message and sends it to a destination (the gateway). The destination has a consumer configured that is listening for messages being sent to it, which can respond to the producer via the destination. The producer and consumer exchange messages through the destination.

Applications that are built with the two gateways described here are accessed via the MXML file that is deployed on FDS, which, in turn, calls the CFC on the ColdFusion server as required. While ColdFusion’s various gateways can then provide access to a variety of services not available on FDS, the developer should also realize that there is functionality offered by ColdFusion that is not available in FDS itself. Two examples are ColdFusion (being a Java application) accessing Java objects and the numerous tags that ColdFusion has to offer (CFMAIL, for example, can send e-mail via an SMTP server).

FDS has a ColdFusion Event Gateway adapter that communicates with ColdFusion’s Flex Messaging Event gateway. An instance of the ColdFusion Event Gateway must be enabled on FDS before you can start communication with any gateway on the ColdFusion server. The messaging-config.xml file holds all the details of the ColdFusion server. It is stored in the WEB-INF\flex directory of your FDS server. If you choose to create a ColdFusion Event Gateway–based application using the samples server provided with FDS, you’d find the file located at C:\fds2\jrun4\servers\default\samples\WEB-INF\flex.

Take a look at building an application that exchanges data between FDS and ColdFusion via the two gateways. This application will retrieve and display a list of e-mails from a Post Office Protocol (POP) server. Following are the tasks at hand:

  • Create an instance of the ColdFusion Event Gateway adapter on FDS

  • Create an instance of the Flex Messaging Gateway on ColdFusion

  • Create the necessary ActionScript, MXML, and CFML for the application

The application itself is relatively simple. On the MXML side, you must have a form that takes the URL, username, and password of a POP mail server. When the user submits the form, FDS will talk to ColdFusion, requesting that it use the form data to retrieve messages from a POP server. ColdFusion will fetch the results as a query and then send that to FDS and the MXML page as an ArrayCollection. The results will be displayed within the MXML using a DataGrid as a simple form of data dump.

There is a sample messaging-config.xml with ColdFusion Event Gateway settings that you can use to copy the settings from. It’s preinstalled into the C:\fds2\resources\config directory. Take a look at using the applicable tag from it to build a sample application.

In that file, you’ll find a <destination> tag with the attribute id="ColdFusionGateway". Copy that tag into the existing messaging-config.xml found at C:\fds2\jrun4\servers\default\samples\WEB-INF\flex and save the file to update it. Following is an example:

<destination id="ColdFusionGateway">
     <adapter ref="cfgateway" />
     <properties>
          <gatewayid>*</gatewayid>
     </properties>
     <channels>
          <channel ref="my-rtmp"/>
          <channel ref="my-polling-amf"/>
     </channels>
     </destination>

You must have a CFC ready to go before you can create an instance of a Flex Messaging Event Gateway on your ColdFusion server. The form that you’re about to use requires you to nominate a CFC as one of the required details when the instance is created. If you’re keen to get started, you can create an empty file. You can work on its contents later. Save that CFC into the ColdFusion directory that the application will call it from. For the sake of this exercise, create a CFC called PopGateway.cfc, and save it to a new directory at C:\CFusionMX7\wwwroot\flexgatewaypop.

Now, you must configure the Flex Gateway setting in the ColdFusion Administrator. From Event Gateways, choose Gateway Instances. Enter Flex2CF702 as the value for Gateway ID and select Flex Messaging – Flex as the Gateway Type. Specify the full path to the CFC you’ve just created as the CFC Path. Select Automatic as the Startup Mode and choose Add Gateway Instance.

The next thing you must do is create the MXML page. The form that you’ll use to collect user login details is quite straightforward. It will need to collect the username and password. You also use the form to collect the URL of the POP server so that the application is generic enough to allow users to log in to any server and retrieve a list of mail messages. The last thing to do with the UI will be to set the DataGrid component to display the results once received.

In this code, you also have an instance of the Consumer component. This will be used by FDS in a fashion similar to how the RemoteObject tag is used for Flash Remoting. Notice that you use a function to nominate the handler in order to process the result as part of the argument for the message attribute of the Consumer component.

<mx:Consumer id="consumer" destination="ColdFusionGateway" message=
"messageHandler(event)" />

<mx:Form>
     <mx:FormItem label="POP Server Address:">
          <mx:TextInput id="popUrl"/>
     </mx:FormItem>
     <mx:FormItem label="User Name">
          <mx:TextInput id="userName"/>
     </mx:FormItem>
     <mx:FormItem label="Password">
          <mx:TextInput id="password" displayAsPassword="true"/>
     </mx:FormItem>
     <mx:FormItem>
          <mx:Button id="submit" label="fetch pop mail" click="fetchPopMail();"/>
     </mx:FormItem>
</mx:Form>

<mx:DataGrid dataProvider="{popData}" width="400"/>

Next, start adding ActionScript to the MXML. Add a pair of Script tags and add to that the import statements. Then define the variables to be used within the application.

<mx:Script>
     <![CDATA[

          import mx.messaging.events.*;
          import mx.messaging.Producer;
          import mx.messaging.messages.AsyncMessage;
          import mx.collections.ArrayCollection;

          public var pro:mx.messaging.Producer;
          public var con:mx.messaging.Consumer;

          [Bindable]
          private var popData:ArrayCollection;
     ]]>
</mx:Script>

In this code, you’ll notice that you’re importing a number of messaging classes. Notice that the first two variables are typed to classes within the messaging packages. The last variable is going to be used in the DataGrid as the dataprovider. The variable is data typed to ensure that it will be compatible with its associated command. It’s bindable so that the DataGrid will be able to use it as the application commences. It’s also bindable because it will store the value returned by the adapter to gateway progress, and so that the DataGrid can update itself once the information has been received from the server.

The next thing is to add the functions to the Script, as shown here:

public function initApp():void {
          pro = new mx.messaging.Producer();
          pro.destination = "ColdFusionGateway";
          consumer.subscribe();
}

public function fetchPopMail():void {
          var msg:AsyncMessage = new AsyncMessage();
          msg.headers.gatewayid = "Flex2CF702";
          msg.body = new Object();
          msg.body.popurl = popUrl.text;
          msg.body.userName = userName.text;
          msg.body.password = password.text;
          pro.send(msg);
}

private function messageHandler(event:MessageEvent):void {
          popData = event.message.body as ArrayCollection;
}

The functions have now been added. The first, initApp(), will be called by a CreationComplete event on the Application tag. It establishes the location of the destination. The next function, fetchPopMail(), retrieves the location of the ColdFusion Flex Gateway, fetches the contents of the form elements, and sends them to the server as a single object. This will be called when the Submit button in the form is clicked. The last function, messageHandler(), handles the result from the server when it is returned. The result is then assigned to the ArrayCollection, which, because of the binding, will force the DataGrid to refresh and redisplay.

The last thing to build is the CFC that will handle the call via the gateways. In this case, it will contain a relatively simple function that will use cfpop to retrieve 10 messages from the POP server. Take a look at the code:

<cfcomponent name="PopGateway" hint="Demo application that illustrates how to use
the Flex Gateway">
     <cffunction name="onIncomingMessage" access="remote" returntype="query">
          <cfargument name="event" type="struct" required="true">
          <cfset formDetails = event.data.body>
          <cfpop action="getheaderonly" name="GetHeaders"      startrow="1"
maxrows="10" timeout="15" server="#formDetails.popserver#"
username="#formDetails.username#" password="#formDetails.pwd#">
          <cfreturn GetHeaders>
     </cffunction>
</cfcomponent>

Notice the name of the function in the CFC: onIncomingMessage. Though Adobe’s documentation doesn’t point this out, this is a reserved function name that the gateway is expecting to call. Also notice the names and structure of the argument used in this function. Again, these are reserved names. In the case of the Flex gateway, you should expect a structure called event with the data you’ve passed to the function nested in structure called body, which, in turn, is nested in a structure called data.


Using the Flex Data Service Assembler

The logic behind an application built on top of Flex Data Management Services is a combination of both client side and server side. It’s used to manage data distribution within a Flex application. On the client side in Flex, you use the DataService component to manage data locally, and to communicate about said data with the Flex Data Management Service, which runs on the server side as part of FDS. Data Management Service manages data on the server side, maintaining a distribution of it between both multiple clients and server-side data resources.

The Data Management Service is quite different in its approach to handling data when compared to the Remote Procedure Call (RPC) feature of Flex. The Data Management Service can manage both automatic and manual synchronization of application data, broadcasting changes to both server-side managed data and multiple connected clients. It can be also used to manage changes to data for persistence in occasionally connected clients.

The DataService component is also different from the RemoteObject component because it does not call methods on the server side, nor does it return a result. Instead, it uses Data Management Service on the server side to replicate the data that it’s managing to multiple clients. Both the Web application and the server-side database would be clients, in this example. Changes made to the data in any of the clients are then broadcast to all the clients currently listening to it using messaging.

Changing a value in a DataGrid on the client side would be immediately reflected within the database on the server side. Changes to a value in a table within the database on the server side would push to the dataprovider for a ComboBox component on the client side.

There is a need for conflict resolution with changes to data. You can have multiple instances of a Web application being served to multiple user machines. The Data Management Server has its own conflict resolution API to handle this. You can write logic for the client side to handle conflict exceptions.


Configuring ColdFusion

As mentioned, you use the DataService component on the client side. This can be scripted as either MXML or ActionScript. It would be used as the source of data for a collection like the ArrayCollection, which, in turn, would be used to populate a control like the DataGrid component. The DataService component would then synchronize itself with the Data Management Service, keeping the data up to date with both the server and other clients.

The DataService must have a destination for the Data Management Service configured. This would be done in the services-config.xml configuration file. Following is an example of the DataService component:

<mx:DataService id="employeesDS" destination="employeesDest"/>

Here’s the same DataService created using ActionScript, instead:

<mx:Script>
     <![CDATA[
          import mx.data.DataService;
          public var employeesDS:DataService;

          public function initApp():void {
               employeesDS = new DataService("employeesDest");
          }
     ]]>
</mx:Script>

Notice in this code that you have imported the mx.data.DataService class and declared a variable of type DataService.

The DataService component has a number of methods that you call as necessary to synchronize data with the other clients. The fill() method is used to populate a ListCollectionView object with the data that the DataService component is synchronized with (typically an ArrayCollection). The DataService will then manage the specified ArrayCollection.

You can use the DataService component’s releaseCollection() method to release an Array Collection from being managed by the DataService component. Calling the fill() method again would refresh the ArrayCollection.

Following is an example of creating an ArrayCollection from the DataService that you’ve already created. In the example, you’ll see that the initApp() method is used to call the DataService’s fill() method to populate the ArrayCollection. The initApp() method is being called by the Application component’s creationComplete event listener.

<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="initApp();">
     <mx:Script>
          <![CDATA[
               import mx.data.DataService;
               import mx.collections.ArrayCollection;
               public var employeesDS:DataService;

                [Bindable]
                public var employeesAC:ArrayCollection;

               public function initApp():void {
                    contacts = new ArrayCollection();
                    employeesDS = new DataService("employeesDest");
                    employeesDS.fill(employeesAC);
               }
          ]]>
     </mx:Script>

Changes to the data that the DataService component is managing will be automatically synchronized with the server-side destination. The DataService has a commit() method that will be called as the data changes in the ArrayCollection object. This is controlled by the autoCommit property of the DataService, which is set to true by default. Depending on your business requirements, you may choose to disable autoCommit by setting its value to false, and, thus, choosing to manually call the commit() method to apply changes according to your business rules.

The DataService component is not automatically connected to the server-side destination until the first time that the data it manages is called. It then attempts to connect to the server-side destination. A result event is sent to the DataService component if there is a success; a fault event is sent otherwise. A disconnect from the destination can be forced using the DataService component’s disconnect() method. The DataService component can keep track of changes to the data that it’s managing, and it will attempt to resynchronize when the application is reconnected to the server.

Changes to the managed data are tracked by the Data Management Service server-side in an object called DataStore. Calling the DataService component’s commit() method will commit all changes in the DataStore to the managed data. A commit will also be made if the DataService component’s autoCommit property is set to true.

The DataStore can be shared by more than one DataService component. Associations between DataService components will cause them to share a DataStore. You can also set the DataService component’s dataStore property to refer to the DataStore of another DataService component. The DataService component is capable of broadcasting a fault event for any errors that may occur, including server connection errors and errors generated as the result of a commit.

The DataService is capable of handling errors during the commit process. It is capable of keeping track of uncommitted changes. You can programmatically revert changes by calling the revertChanges() method of the DataService component, referring to a specific item as an argument to the revertChanges() method, or passing no argument to revert all changes.

The Flex Data Management Service is designed to monitor and detect changes to data, broadcasting the changes to various clients that hold subscriptions via Flex. It is possible to shift the responsibility of listening for change from the DataService component to the Web application. The DataService component’s autoMerge property can be set to false, disabling the Data Management Service’s ability to detect change.

The DataService component can keep track of changes via the mergeRequired property of the DataStore object. Pending changes can be merged by calling the DataService.dataStore.merge() method. You should merge changes from the Data Management Service before modifying local data to avoid conflicts in your data.

Value Object CFC

The following example builds a VO CFC to format data into a VO to use within the Data Management Service. Though VOs are not part of standard ColdFusion development, they are used frequently in Flex frameworks. The VO being used for this application has all the properties of a single row from the database table. It allows ColdFusion to map the data to properties defined in Employee.as. Each property is added to the VO CFC using cfproperty tags.

The properties will then need to be initialized and assigned default values.

Equal to a constructor, you call a method to initialize the object, and then you create getters and setters for each of the object’s properties.

<cfcomponent output="false" alias="samples.employee.Employee">

     <cfproperty name="employeeId" type="numeric" default="0">
     <cfproperty name="fName" type="string" default="">
     <cfproperty name="lName" type="string" default="">
     <cfproperty name="email" type="string" default="">
     <cfproperty name="mobilePhone" type="string" default="">

     <cfscript>
     variables.employeeId = 0;
     variables.fName = "";
     variables.lName = "";
     variables.email = "";
     variables.mobilePhone = "";
     </cfscript>

     <cffunction name="init" output="false" returntype="Contact">
     <cfreturn this>
     </cffunction>

     <cffunction name="getEmployeeId" output="false" access="public"
returntype="any">
     <cfreturn variables.employeeId>
     </cffunction>

     <cffunction name="setEmployeeId" output="false" access="public"
returntype="void">
     <cfargument name="val" required="true">
     <cfset variables.employeeId = arguments.val>
     </cffunction>

     <cffunction name="getFName" output="false" access="public" returntype="any">
     <cfreturn variables.fName>
     </cffunction>

     <cffunction name="setFName" output="false" access="public" returntype="void">
     <cfargument name="val" required="true">
     <cfset variables.fName = arguments.val>
     </cffunction>
.............

EmployeeAssembler.cfc

This is the interface between Flex Data Services and ColdFusion. It’s invoked by Flex as part of the Data Management process. Flex Data Management Service calls a number of methods on the assembler as it manages data. The assembler, in turn, calls the Data Access Object (DAO) to interface with the database. The assembler has the following methods:

  • fill - This method has been coded to retrieve all the employee records from the database by default, returned to Flex as an array. The method can optionally filter by a record ID.

  • get - Retrieves a specific record. It accepts a record ID as its argument.

  • sync - Uses a change list to manage data synchronization issues. It is an array of change objects. It calls private methods to create, delete, and update records in the database via an instance of the DAO.cfc.

  • count - Returns the number of records in a result set.

Following is a simple example of the fill() method:

<cffunction name="fill" output="no" returntype="samples.employees.Employee[]"
access="remote">
     <cfargument name="param" type="string" required="no">
     <cfset var ret = ArrayNew(1)>
     <cfif structKeyExists(arguments, "param")>
          <cfreturn variables.dao.read(param=arguments.param)>
     <cfelse>
          <cfreturn variables.dao.read()>
     </cfif>
</cffunction>

     <cffunction name="get" output="no" returnType="samples.employees.Employee"
access="remote">
     <cfargument name="uid" type="struct" required="yes">
     <cftry>
          <cfset key = uid.employeeId>
          <cfset ret="">
          <cfset ret=variables.dao.read(id=key)>
          <cfif ArrayLen(ret) EQ 1>
               <cfreturn ret[1]>
          <cfelseif ArrayLen(ret) GT 1>
               <cfset msg="get returned more than one record when employeeId had a
value of #key#.">
               <cfthrow message="#msg#">
          <cfelse>
               <cfset msg="get did not return anything when employeeId had a value
of #key#.">
               <cfthrow message="#msg#">
          </cfif>
          <cfcatch type="any">
               <cfset msg = "Error during get: " & cfcatch.message >
               <cfthrow message="#msg#">
          </cfcatch>
     </cftry>
</cffunction>

<cffunction name="sync" output="no" returnType="array" access="remote">
     <cfargument name="changes" type="array" required="yes">
     <cfset var newchanges=ArrayNew(1)>
     <cfloop from="1" to="#ArrayLen(changes)#" index="i" >
          <cfset co = changes[i]>
          <cfif co.isCreate()>
               <cfset x = doCreate(co)>
          <cfelseif co.isUpdate()>
               <cfset x = doUpdate(co)>
          <cfelseif co.isDelete()>
               <cfset x = doDelete(co)>
          </cfif>
          <cfset ArrayAppend(newchanges, x)>
     </cfloop>
     <cfreturn newchanges>
</cffunction>

<cffunction name="count" output="no" returntype="Numeric" access="remote">
<cfargument name="param" type="string" required="no">
     <cftry>
          <cfif structKeyExists(arguments, "param")>
               <cfreturn variables.dao.count(param=arguments.param)>
          <cfelse>
               <cfreturn variables.dao.count()>
          </cfif>
          <cfcatch type="database">
               <cfif isDefined("cfcatch.queryError") AND isDefined("cfcatch.sql")>
                    <cfset msg = "Error during count: " & cfcatch.queryError & ".
SQL was :" & cfcatch.sql>
               <cfelse>
                    <cfset msg = "Error during count: " & cfcatch.message >
               </cfif>
               <cfthrow message="#msg#">
          </cfcatch>
          <cfcatch type="any">
               <cfset msg = "Error during count: " & cfcatch.message >
               <cfthrow message="#msg#">
          </cfcatch>
     </cftry>
</cffunction>

The assembler will, in turn, use a DAO component to perform data management.

The DAO.cfc

The DAO.cfc is the DAO that makes all the calls to the database. In the context of the discussion in this chapter, it is a ColdFusion component with a number of predefined methods. It could also be authored in Java. Following are the methods that the assembler will be calling on the DAO:

  • read - Retrieves the dataset. The request can be parameterized to filter data.

  • create - Inserts a new record into the database.

  • update - Updates an existing record in the database.

  • delete - Removes a record from the record set.

  • count - Retrieves the number of records in the dataset.

Any conflicts with the data, duplicate insert records (create), unsuccessful updates, or unsuccessful deletes are passed on to the assembler to handle. The Flex change object can be set to have a conflict. The developer should be aware of this so that the application has the appropriate checks and balances in the methods of both the DAO and the assembler, and so that the correct response is transmitted to Flex Data Management Service.


ColdFusion Extensions for Flex Builder 2

The ColdFusion Extensions for Flex Builder are a number of wizards that help the developer work with Flex and ColdFusion. They give Flex Builder 2 the capability to create ActionScript classes and generate ColdFusion components by interacting with data on both the ColdFusion server and the development environment.

The following sections describe what is contained in the ColdFusion Extensions package.

Eclipse RDS Support Plugin

This gives Eclipse and Flex Builder 2 the capability to connect to the ColdFusion server over a secure connection via Remote Development Services (RDS), allowing you access to both files and the data sources that have been configured in ColdFusion Administrator. RDS must have been chosen as part of the ColdFusion installation. You must have a valid password for RDS access from within Flex Builder 2.

The RDS support plugin will be configured to connect to the ColdFusion Developer edition by default. This is found at local host IP address 127.0.0.1, port 8500. You may need to configure the plugin to suit your development environment. The settings for the RDS plugin are found at Window Image from book Preferences Image from book RDS Configuration. As you can see in Figure 24-3, you either create a new set of connection parameters for another ColdFusion server, or make changes to your existing settings.

Image from book
Figure 24-3: RDS Configuration

Settings for the server’s IP address, port number, and context are entered into a form to add or modify an RDS connection. Testing the connection parameters is also done from this form. If you are running ColdFusion on a J2EE server with different ports and context roots to the default values, you may have to modify your server settings. You should leave the Context Root value blank if your ColdFusion server has not been deployed on a J2EE server. All the RDS connections accessed by the RDS plugin will require you to sign in with your password for the first time per session.

You will need to switch to Window Image from book Other Views and expand the ColdFusion option, as shown in Figure 24-4. Here you will see three options: RDS Dataview, RDS Fileview, and Services Browser.

Image from book
Figure 24-4: RDS view options

If you are familiar with ColdFusion Studio, you will be familiar with the concept of RDS and the kinds of tools that the RDS plugin offers to the developer. The RDS Dataview (Figure 24-5) provides the ability to explore the ColdFusion server’s datasources via a tree view. Datasources can be expanded so that the tables and their columns (as well as data properties) can be viewed.

Image from book
Figure 24-5: RDS Dataview

From the RDS Dataview, you can launch the RDS Query Viewer (Figure 24-6) by using the second button in the toolbar at the top-right of the Dataview. It will launch within Flex Builder 2 immediately above the RDS Dataview. The RDS Query Viewer allows you to construct SQL statements. Double-click the table names within the RDS Dataview to insert them into the SQL. The RDS Query Viewer’s interface is reasonably simple. It assumes that the SQL server and datasource from what tables are selected in the RDS Dataview. You can change these, if required. You can test the SQL before copying it into the ColdFusion query that it’s intended for.

Image from book
Figure 24-6: RDS Query Viewer

The Visual Query Builder (Figure 24-7) allows you to build SQL queries visually by first dragging the tables into the builder, then double-clicking the required columns in their respective tables. Dragging and dropping the relationships easily indicates table joins. Additional SQL-like sort order and aliases are easily added via the interface. The SQL is written for you as you use the Visual Query Builder, and can be tested before deploying in your ColdFusion templates.

Image from book
Figure 24-7: Visual Query Builder

With the RDS Fileview (Figure 24-8), you can browse the files on the ColdFusion server that you’re currently connected to via RDS. This is a tool that allows you to view, create, and delete files and folders on the server. Folders are displayed in the upper half, with their contents in the lower half of the screen.

Image from book
Figure 24-8: RDS Fileview

Installation

Software updates are not part of the standard Flex Builder install process. Instead, they appear as an option toward the end of the setup as a popup that offers to put an installer into the local system.

The wizards are installed as a package via a standard Eclipse process accessed from the Help menu (Figure 24-9). Choose Help Image from book Software Updates Image from book Find and Install to commence, then select Search For New Features To Install.

Image from book
Figure 24-9: The first step in the install process

From the options on the right of the dialog box (Figure 24-10), choose New Archived Site. Eclipse (which Flex Builder 2 is built on top of) has the capability to install new plugins from either a location online or a compressed file.

Image from book
Figure 24-10: Confirmation that CF_FB_Extensions.zip is to be installed

The location that the Flex Builder 2 installer places the required file into is a temp directory buried in the user settings of the computer. A little bit of configuration is required to properly locate the ZIP file that contains the extensions.

Browse to C:\Documents and Settings\Your Profile\Local Settings\Temp\ColdFusion Extensions for Flex Builder. You must enable Tools Image from book Folder Options Image from book View Image from book Show Hidden Files and Folders within Windows before choosing to install the ColdFusion Extensions so that you can see this directory. Select the file that you see there, CF_FB_Extensions.zip, and choose Open.

You will be asked to confirm the file you’ve selected. Choose OK, ensure that the file is also selected in the next dialog box, and select Finish. Ensure that CF_FB_Extensions.zip is checked on the next dialog box (Figure 24-10) and choose Next.

Agree to the license agreement and click Next. Choose Finish on the next dialog box. The necessary files for the ColdFusion Extensions will now be installed, and a verification screen (Figure 24-11) will appear during this process. Choose Install All on this screen.

Image from book
Figure 24-11: Install All option

The process will take a few minutes because documentation for the extensions and ColdFusion is also added to the help files as well. You must restart Flex Builder 2 before the extensions can be used. A dialog box will appear asking you if you want to do that.

Documentation for both the ColdFusion Extensions and the ColdFusion language are installed into the Flex Builder 2 help system. You might like to take some time looking at what’s been added to familiarize yourself with what the extensions have to offer.

Create CFC Wizard

The Create CFC Wizard (Figure 24-12) will create the necessary CFCs and ActionScript files for access to data in tables on the database. You use this wizard by right-clicking the database table required to display from within the RDS Dataview. The wizard will ultimately produce a VO, but in doing so, it will produce the code to access the VO as well. It offers the rapid creation of code with three styles of CFC data access:

  • Active Record CFC

  • Bean CFC and DAO CFC

  • Flex Data Service Assembler CFCs

Image from book
Figure 24-12: CFC Value Object Wizard

Choosing the type of CFC will then affect the output of the wizard and how many files that it produces. A lot of checks and balances are put in place in the code dynamically for error trapping. Following is an example of the fill() method from a dataAssembler.cfc produced by the wizard:

<cffunction name="fill" output="no" returntype="Employee.departments[]"
access="remote">
     <cfargument name="param" type="string" required="no">
     <cftry>
     <cfif structKeyExists(arguments, "param")>
          <cfreturn variables.dao.read(param=arguments.param)>
     <cfelse>
          <cfreturn variables.dao.read()>
     </cfif>
<!--- If the SQL failed, report the error, include SQL if debugging turned on --->
     <cfcatch type="database">
          <cfif isDebugMode() AND  isDefined("cfcatch.queryError") AND
isDefined("cfcatch.sql")>
               <cfset msg = "Error during fill: " & cfcatch.queryError & ". SQL was
:" & cfcatch.sql>
          <cfelse>
               <cfset msg = "Error during fill: " & cfcatch.message >
          </cfif>
          <cfthrow message="#msg#">
     </cfcatch>
<!--- If anything else happened, report the error --->
     <cfcatch type="any">
          <cfset msg = "Error during fill: " & cfcatch.message >
          <cfthrow message="#msg#">
     </cfcatch>
     </cftry>
</cffunction>

ActionScript to CFC Wizard

The ActionScript to CFC Wizard builds a CFC based on an ActionScript class. The main purpose of this is to create a DTO or VO for use in applications. This CFC would then be used to cast a complex object of a specific data type with its own properties, as well as getters and setters.

Right-click an ActionScript from the list of available files in the Project Navigator to use the wizard. Choose ColdFusion Wizards Image from book Create CFC. Enter the location of where the file is to be saved in the first option of the dialog box that appears. You can either type the location or browse to it. Next, enter the name of the CFC that you’re creating. You may need to verify the overwriting of an existing file. If you are using this wizard to generate a DTO, you must choose the Generate Get/Set Methods option. Set the appropriate property scope (private/public). Click Finish and the generated CFC will display shortly.

CFC to ActionScript Wizard

The CFC to ActionScript Wizard builds an ActionScript class based on a CFC VO. Select a ColdFusion CFC VO from the Project Navigator by right-clicking and choose ColdFusion Wizards Image from book Create AS Class.

Nominate the project folder to save the file into by either typing the path or using the Browse button to locate it. Give the new class an appropriate packed name with the next option, then give the new class a name. Choose to overwrite any existing versions of the CFC. This will be selected for you by default. The last thing is to nominate the path to the CFC. This value will be used as part of the ActionScript class. This will create an alias for the location of the CFC that will be used as a binding in the ActionScript class, like the following example shows:

[Bindable]
[RemoteClass(alias="sandboxes.flexApp.Employee")]

Click Finish and the wizard will build the ActionScript class.

Services Browser

The Services Browser allows the developer to view CFCs and Web services hosted on the ColdFusion server. It displays a full listing of CFCs organized by path, showing the individual CFCs in a chosen location. Expanding a CFC in the view will reveal its methods with the data return type indicated. Methods can be expanded further to show their arguments. Setting a method of a function to remote, public, or private will affect its listing in the Services Browser.

WSDL URLs can be added to the Services Browser so that it can be used to manage a list of Web services. The Services Browser can then be used to generate the necessary CFML to invoke a Web service in a ColdFusion page. You can also use it to generate CFML to create a Web service object, instead. The Services Browser can be used to generate the necessary ActionScript to consume a Web service.


Summary

Flex 2 and ColdFusion 7.0.2 are ready partners. Through Flash Remoting, they can seamlessly exchange complex data between each other. ColdFusion can also be used to communicate with Flex applications via Flex Data Services (FDS). Flex can also exchange data with ColdFusion by calling ColdFusion Components (CFCs) via the Flex Messaging Event Gateway.

Publish-subscribe messaging applications can be built with a combination of FDS and ColdFusion. The Flex Web application can subscribe to data on the ColdFusion server via FDS and be aware of changes to information via the publish-subscribe managed by the Data Management Service provided by FDS.

The ColdFusion Extensions for Flex Builder 2 offer a number of wizards that allow for the creation of ColdFusion Components and ActionScript classes used as part of the process of data connectivity and management. Other tools included in the ColdFusion Extensions give the developer access to information within the database.

Chapter 25 discusses how to incorporate video and audio into your Flex application to create a richer experience for your user. The Flash run-time has become the most installed multimedia player with the highest penetration across all major operating systems, and Flex makes it easy to develop multimedia applications for that run-time.


Part VII: Integration Techniques

Chapter List

Chapter 25: Rich Media Integration
Chapter 26: Integration with External Applications


Chapter 25: Rich Media Integration

Overview

Video and audio are fast becoming an important part of business and consumer applications. If you take a look around the Web today, you will notice the influx of Web sites that contain video and audio. You probably find the wrong version of the media player is installed or there are limited options to interact with the video. All of this disrupts the user experience, and this is where Flex and Flash are far more superior.

The Adobe Flash Player contains video and audio playback and streaming capabilities. As of this writing, Flash Player 8 is installed on 90 percent of users’ computers. This is the reason companies such as Brightcove, Google, and YouTube have adopted the Flash Player to play back video.

With Flex, video is more than just a streaming experience. It can be a more tightly integrated part of the application. During playback of video, events can be triggered and behaviors of other components are driven by the events, all of which creates a much richer experience. The capabilities enable an extensive range of new, innovative, and highly interactive applications.

Rich media comes from the term “multimedia,” and is actually audio, video, text, and graphics combined with animation and interactivity. All these kinds of media have been around for years on the desktop, but now the focus is using rich media on the Web. As always with new technology, it does pose a problem with accessibility. If done correctly, however, it can be an even better experience for the user.

This chapter introduces you to the integration of rich media into your Flex applications, and shows how easy it is to implement and work with.


Integration

Before looking at an example application, you must understand how rich media is integrated into a Flex application. This section provides you with the basics of how easy it is to do this in Flex.

To integrate rich media such as audio and video into your Flex application, you can use the flash.media.Sound class and flash.media.Video class, respectively. Working with those two lower-level classes might be a bit tedious for a beginner, so the Flex Framework provides easier ways to use audio and video in your application.

Audio

To integrate sound (such as an .mp3 file), you can embed the sound file as you would an image, as the following example shows:

[Embed(source="sample.mp3")]
[Bindable]
public var soundAsset:Class;

public var s:Sound = new soundAsset() as Sound;

This example embeds the .mp3 file into your Flex application and casts the soundAsset instance to a Sound class instance. This allows you to access the sound file’s data and manipulate it as necessary. Doing it this way would increase the file size. For sound effects, it would probably be fine to embed the sound files, as long as they are not too big. For bigger sound files, it would not be recommended to do it this way. Instead, you could download the sound files progressively by using the flash.media.Sound class.

The SoundEffect class lets you control the volume and panning of an .mp3 file. You can either specify the .mp3 file from a URL, or embed it and set the source property to the embedded class. This class can pan the .mp3 file from a range of –1.0 to 1.0, where –1.0 uses the left channel, and 1.0 uses the right channel.

The following example embeds the .mp3 file and sets the panFrom and panTo properties of the SoundEffect instance:

<mx:SoundEffect id="mySound" source="@Embed(source='assets/sound/rock.mp3')"
panFrom="-0.5" panTo="0.5" />

Video

To use video inside Flex, you must use a Flash Video (FLV) file, which is a proprietary file format developed by Macromedia (now Adobe) for use in Adobe Flash Player versions 6, 7, 8, and 9. Flash Player 6 and 7 used a variant of H.263 video standard by Sorenson Spark, and versions 8 and 9 use On2 TrueMotion VP6 codec, which is of a much higher quality.

Flex provides a VideoDisplay component that lets you play an FLV file in your application. It contains no controls for the play, pause, or stop actions. So it is up to you to create the user interface for your video player. The VideoDisplay component supports progressive download over HTTP, streaming from Flash Media Server, and streaming from a Web cam using the Camera object.

It is relatively simple to use VideoDisplay. Just set the source property to a relative or absolute path to the FLV file, as shown here:

<mx:VideoDisplay id="videoDisplay" width="320" height="240" source="myvideo.flv" />

As mentioned earlier, all you should see is a video playing and nothing else. The layout and interactivity of the VideoDisplay component is up to the developer. The following example defines a VideoDisplay component and two LinkButton components. The first LinkButton instance is used for two actions: play and pause the video. The second LinkButton instance is used to stop the video. The playPause() method checks to see if the label is set to "Play". If so, it sets the label property of the LinkButton to "Pause" and plays the video. The same happens if the label property is set to "Pause".

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
     <mx:Script>
          <![CDATA[

              import mx.events.*;
              import mx.controls.*;

              private function playPause(event:MouseEvent):void
               {
                    var buttonInstance:LinkButton = event.currentTarget as
LinkButton;

                    if (buttonInstance.label == "Play")
                    {
                         buttonInstance.label = "Pause";
                         videoDisplay.play();
                    }
                    else if (buttonInstance.label == "Pause")
                    {
                         buttonInstance.label = "Play";
                         videoDisplay.pause();
                    }
               }
          ]]>
     </mx:Script>

     <mx:VideoDisplay id="videoDisplay" width="320" height="240"
source="myvideo.flv" />
     <mx:HBox>
          <mx:LinkButton id="playPauseBtn" label="Play" click="playPause(event)" />
          <mx:LinkButton label="Stop" click="videoDisplay.stop()" />
     </mx:HBox>
</mx:Application>

Using the Camera

The Camera class gives access to a Web camera on a client’s workstation. You mainly use the Camera class with Flash Media Server, but you can use it without the server. For example, you could capture a single frame from the camera stream, encode the data, and send it to the server to be stored. The camera can also be used to create cool effects, such as the ones in Apple’s PhotoBooth application. You could apply a blur filter, a sepia effect, or morphing to the streaming video. Some developers have even been able to create effects that interact with the user.

The Microphone class again gives you access to a microphone on the client’s workstation. This can be used without the Flash Media Server, but again with limited functionality.

The Camera class is used in conjunction with the VideoDisplay control. The following example shows this in action:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     creationComplete="initApp()">

     <mx:Script>
          <![CDATA[

               public var camera:Camera;

               public function initApp():void
               {
                    camera = Camera.getCamera();

                    myVideoDisplay.attachCamera(camera);
               }

          ]]>
     </mx:Script>

     <mx:VideoDisplay id="myVideoDisplay" width="320" height="240" />

</mx:Application>

The next example uses the VideoDisplay, Image, and Button controls to capture an image from the camera stream and display it in the Image control instance. All the magic lies in this simple, but very powerful, getBitmapData(target:UIComponent) method. The implementation of this method allows you to capture BitmapData of any visual component at run-time.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

     <mx:Script>
          <![CDATA[

               import mx.core.UIComponent;
               import flash.media.Camera;

               public var camera:Camera;

               public function initCamera():void
               {
                    camera = Camera.getCamera();

                    myVideoDisplay.attachCamera(camera);
               }

               private function getBitmapData(target:UIComponent):BitmapData
               {
                    var bd:BitmapData = new BitmapData(target.width, target.height);
                    bd.draw(target);
                    return bd;
               }

               private function captureCamera():void
               {
                    var bd:BitmapData = getBitmapData(myVideoDisplay);
                    myImage.source = new Bitmap(bd);
               }

          ]]>
     </mx:Script>

     <mx:VideoDisplay id="myVideoDisplay" width="320" height="240"
creationComplete="initCamera()" />
     <mx:Image id="myImage" width="320" height="240" />
     <mx:Button label="Capture Camera" click="captureCamera()" />

</mx:Application>

By clicking the button, you capture the VideoDisplay control with an image from the camera stream. You could extend this application and encode the BitmapData using a compression algorithm such as JPEG or PNG, and send the data to the server to be stored for later retrieval.


Building an Application with Rich Media Integration

So far, you have seen how easy it is to integrate rich media into your Flex applications. In this section, you build a simple application that integrates video and audio with some transitions and effects.

Figure 25-1 shows the Flex application with video playing on the left-hand side. A reflection effect has been added to make it look more professional. This application did not take long to build, and all the code is housed in the root Main.mxml application file.

Image from book
Figure 25-1: Rich media application

Listing 25-1 shows the code for the entire application. Take a look through the code before moving on.

Listing 25-1: Main.mxml
Image from book

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
     xmlns="*">

     <mx:Style>

          Application
          {
               backgroundGradientColors: #000000, #000000;
               paddingBottom: 2;
               paddingLeft: 2;
               paddingRight: 2;
               paddingTop: 2;
          }

          List
          {
               fontSize: 40;
               color: #FFFFFF;
               backgroundAlpha: 0;
               borderStyle: none;
               fontFamily: myFontFamily;
               rollOverColor: #990000;
               selectionColor: #0099CC;
          }

          @font-face
          {
              src:local("Arial Black");
              fontFamily: myFontFamily;
              flashType: true;
          }

     </mx:Style>

     <mx:Script>
          <![CDATA[

               import mx.controls.List;

               [Bindable]
               private var trailerFileName:String;

          ]]>
     </mx:Script>

     <mx:states>
          <mx:State name="showTrailer">
               <mx:RemoveChild target="{mainView}" />
               <mx:AddChild>
                    <mx:VBox id="fullScreenVideo" width="100%" height="100%">
                         <mx:VideoDisplay id="fullScreenVideoDisplay" width="100%"
height="100%"
                              source="trailers/{trailerFileName}"
doubleClickEnabled="true"
                              doubleClick="this.currentState = '';" />
                    </mx:VBox>
               </mx:AddChild>
               <mx:SetProperty target="{videoDisplay}" name="source" value="null" />
          </mx:State>
     </mx:states>

     <mx:transitions>
          <mx:Transition fromState="*" toState="showTrailer">
               <mx:Sequence targets="{[mainView, fullScreenVideo]}">
                    <mx:Fade target="{mainView}" alphaFrom="1" alphaTo="0"
duration="1000" />
                    <mx:RemoveChildAction />
                    <mx:AddChildAction />
                    <mx:Fade target="{fullScreenVideo}" alphaFrom="0" alphaTo="1"
duration="500" />
               </mx:Sequence>
          </mx:Transition>

          <mx:Transition fromState="showTrailer" toState="*">
               <mx:Sequence targets="{[mainView, fullScreenVideo]}">
                    <mx:Fade target="{fullScreenVideo}" alphaFrom="1" alphaTo="0"
duration="500" />
                    <mx:RemoveChildAction />
                    <mx:AddChildAction />
                    <mx:Fade target="{mainView}" alphaFrom="0" alphaTo="1"
duration="1000" />
               </mx:Sequence>
          </mx:Transition>
     </mx:transitions>

     <mx:VBox id="mainView" width="100%" height="100%" paddingBottom="0"
paddingLeft="0" paddingRight="0" paddingTop="0"
          horizontalAlign="center">
          <mx:HBox width="100%" horizontalAlign="center" verticalAlign="middle">
               <mx:Image source="images/Movie.png" />
               <mx:Label text="Trailers" fontFamily="myFontFamily" fontSize="50"
color="#FFFFFF" />
          </mx:HBox>
          <mx:HRule strokeColor="#FFFFFF" strokeWidth="1" width="100%" />
          <mx:Spacer height="10" />

          <mx:HBox width="100%" height="100%" paddingLeft="10" paddingRight="10"
horizontalGap="10">

               <mx:VBox width="40%" height="100%" verticalAlign="middle"
verticalGap="0">
                    <mx:VideoDisplay id="videoDisplay" width="509" height="211" />
                    <Reflection id="reflection" target="{videoDisplay}"
width="100%" height="211" />
               </mx:VBox>

               <mx:List width="60%" height="100%" horizontalScrollPolicy="off"
verticalScrollPolicy="off" rowHeight="80"
                    change="videoDisplay.source = 'trailers/' +
List(event.currentTarget).selectedItem.data"
                    doubleClickEnabled="true" doubleClick="trailerFileName =
List(event.currentTarget).selectedItem.data; this.currentState = 'showTrailer'">
                    <mx:itemRenderer>
                         <mx:Component>
                              <mx:VBox verticalAlign="middle"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
                                   <mx:Label text="{data.label}" />
                              </mx:VBox>
                         </mx:Component>
                    </mx:itemRenderer>
                    <mx:dataProvider>
                         <mx:Array>
                              <mx:Object label="Blood Diamond" data="Blood
Diamond.flv" />
                              <mx:Object label="Deja Vu" data="Deja Vu.flv" />
                              <mx:Object label="Fantastic 4 - Rise of the Silver
Surfer" data="Fantastic 4 - Rise of The Silver Surfer.flv" />
                              <mx:Object label="Ratatouille"
data="ratatouille-tsr1_h480p.flv" />
                              <mx:Object label="Teenage Mutant Ninja Turtles"
data="Teenage Mutant Ninja Turtles 2.flv" />
                              <mx:Object label="Spiderman 3" data="Spider-Man
3.flv" />
                         </mx:Array>
                    </mx:dataProvider>
               </mx:List>
          </mx:HBox>
     </mx:VBox>

</mx:Application>
Image from book

The Inner Workings of the Application

Now that you have looked over the code, take a look at the most important parts of the application. Without the VideoDisplay control, this application would be an application lacking rich media and, thus, this is the most important component. However, the application still needs logic to get the right video to display inside the VideDisplay control.

To the right of the VideoDisplay control is a List control. This provides the list of trailers by using an inline data provider, for the sake of simplicity. The data provider is a list of objects with a label property and a data property. The label property is displayed in each row of the List control instance, and the data property contains the FLV filename.

<mx:List width="60%" height="100%" horizontalScrollPolicy="off"
verticalScrollPolicy="off" rowHeight="80"
                    change="videoDisplay.source = 'trailers/' +
List(event.currentTarget).selectedItem.data"
                    doubleClickEnabled="true" doubleClick="trailerFileName =
List(event.currentTarget).selectedItem.data; this.currentState = 'showTrailer'">
                    <mx:itemRenderer>
                         <mx:Component>
                              <mx:VBox verticalAlign="middle"
verticalScrollPolicy="off" horizontalScrollPolicy="off">
                                   <mx:Label text="{data.label}" />
                              </mx:VBox>
                         </mx:Component>
                    </mx:itemRenderer>
                    <mx:dataProvider>
                         <mx:Array>
                              <mx:Object label="Blood Diamond" data="Blood
Diamond.flv" />
                              <mx:Object label="Deja Vu" data="Deja Vu.flv" />
                              <mx:Object label="Fantastic 4 - Rise of the Silver
Surfer" data="Fantastic 4 - Rise of The Silver Surfer.flv" />
                              <mx:Object label="Ratatouille"
data="ratatouille-tsr1_h480p.flv" />
                              <mx:Object label="Teenage Mutant Ninja Turtles"
data="Teenage Mutant Ninja Turtles 2.flv" />
                              <mx:Object label="Spiderman 3" data="Spider-Man
3.flv" />
                         </mx:Array>
                    </mx:dataProvider>
</mx:List>

The List instance contains an inline item renderer so that the Label instance can be aligned vertically inside the VBox container. If you do not do this, you will find that the label aligns on the top.

The List control instance contains a change event implementation that sets the videoDisplay.source property to the FLV file. So any time a row is selected, a new video starts playing in the VideoDisplay instance to the left.

The doubleClick event of the List instance sets the videoPath property to the relative path of the relevant FLV file through the List instance selectedItem.data property. This means that any time a row is clicked in the List instance, the correct video is displayed in the VideoDisplay instance.

The second piece of code that is executed in the doubleClick event handler sets the state of the Flex application to a new state. Following is the MXML code for the new state:

<mx:states>
          <mx:State name="showTrailer">
               <mx:RemoveChild target="{mainView}" />
               <mx:AddChild>
                    <mx:VBox id="fullScreenVideo" width="100%" height="100%">
                         <mx:VideoDisplay id="fullScreenVideoDisplay" width="100%"
height="100%"
                              source="{videoPath}" doubleClickEnabled="true"
                              doubleClick="this.currentState = '';" />
                    </mx:VBox>
               </mx:AddChild>
               <mx:SetProperty target="{videoDisplay}" name="source" value="null" />
          </mx:State>
</mx:states>

The new state removes the mainView instance, which is essentially the base state of the application, and adds a VBox container with the VideoDisplay control as its child. The <mx:SetProperty> tag ensures that when the application moves into the new state, the VideoDisplay instance source property in the base state is set to null. This ensures that only the right VideoDisplay instance is playing the FLV file.

Figure 25-2 shows the new state of the application with the VideoDisplay control using the full width and height of the browser window. When the VideoDisplay control is double-clicked, the application will return to the base state using transitions and effects.

Image from book
Figure 25-2: New state of the application

The following example shows the two transitions used in the application, one from the base state to the new state, and the other from the new state to the base state. Refer to Chapter 8 for more information on transitions.

<mx:transitions>
          <mx:Transition fromState="*" toState="showTrailer">
               <mx:Sequence targets="{[mainView, fullScreenVideo]}">
                    <mx:Fade target="{mainView}" alphaFrom="1" alphaTo="0"
duration="1000" />
                    <mx:RemoveChildAction />
                    <mx:AddChildAction />
                    <mx:Fade target="{fullScreenVideo}" alphaFrom="0" alphaTo="1"
duration="500" />
               </mx:Sequence>
          </mx:Transition>

          <mx:Transition fromState="showTrailer" toState="*">
               <mx:Sequence targets="{[mainView, fullScreenVideo]}">
                    <mx:Fade target="{fullScreenVideo}" alphaFrom="1" alphaTo="0"
duration="500" />
                    <mx:RemoveChildAction />
                    <mx:AddChildAction />
                    <mx:Fade target="{mainView}" alphaFrom="0" alphaTo="1"
duration="1000" />
               </mx:Sequence>
          </mx:Transition>
</mx:transitions>

Using transitions in the application means that moving from one state to another looks more elegant and professional. The transition from the base state to the new state fades out the mainView instance, then removes it, adds the new state, and fades it in. The other transition does the exact opposite, and returns the user back to the base state.

This application took but a few hours to build and shows just how easy it is to get rich media integration into your Flex application.


Summary

Over the next year or two, you will see more and more Web applications integrating rich media such as video and audio. Flex makes it easy to integrate all of this type of rich media into your application. This is the best time to get on the bandwagon and start developing killer Rich Internet Applications that use rich media.

Chapter 26 discusses integrating external applications in Flex, such as using JavaScript to communicate between Flex and HTML applications, integrating with Microsoft Excel, and using the flash.net.LocalConnection class to communicate with a Microsoft Windows application.


Chapter 26: Integration with External Applications

ActionScript 3.0 supports the External API that defines a method for Adobe Flash Player SWFs to communicate with their container applications. The most common container applications that the Flash Player resides in are the browser or desktop applications with the Flash Player embedded. Along with learning about the newer External API, this chapter explores using LocalConnection as another method of communicating with outside applications.

This chapter requires other non-Flex resources and development tools. For the ExternalInterface example, you will need Flash 8 Professional and the ability to create SWFs in the IDE. The LocalConnection example uses C# .NET technology, and was created using the freely available Microsoft Visual C# 2005 Express Edition of the Visual Studio product line.

Tip

As of this writing, the link to Microsoft Visual C# 2005 Express Edition is located at http://msdn.microsoft.com/vstudio/express/visualcsharp/.

Using the External API

The root of the External API stems around the ExternalInterface class. This class defines a standard method of communicating with container applications using the Flash Player. Just as the Remote Procedure Call service classes (HTTPService, WebService, and RemoteObject) provide methods to communicate with external back-end services, the ExternalInterface implements methods to communicate with Flash Player container applications.

Tip

The External API is a replacement for the older fscommand() functionality.

The ExternalInterface is, therefore, the framework and preferred method for talking with JavaScript. The Flex-Ajax Bridge (covered in Chapter 22) is an extension to ExternalInterface that helps to solve some of the limitations of the ExternalInterface class. One way to look at it is that the Flex-Ajax Bridge helps you focus on writing JavaScript and not ActionScript, whereas ExternalInterface forces you to build all the communication structure on both sides.

AVM1 and AVM2 SWF Communication

A good example to demonstrate how to use the ExternalInterface is to tackle the problem that became apparent with the rollout of a new ActionScript virtual machine (AVM) in Flash Player 9. An SWF created with Flex 2 and ActionScript 3 is AVM2 compatible, and any SWF created for the previous ActionScript virtual machine is called AVM1 compatible. The newer ActionScript virtual machine is quite different, which means AVM1 SWFs loaded into AVM2 cannot talk directly to each other. This is where ExternalInterface comes into to play.

Follow these steps to create the AVM1 SWF used in this section:

  1. Open Flash 8 Professional.

  2. Create a new Flash document called AVM1.fla.

  3. In the timeline, create two layers and call them ActionScript and Controls.

  4. Open up the Components window by pressing Ctrl+F7 or clicking Windows Image from book Components.

  5. Select the Controls layer and drag the following components onto the Flash Stage, as shown in Figure 26-1:

    1. Button

    2. TextInput

    3. TextArea

    Image from book
    Figure 26-1: Button, TextInput, and TextArea on the Flash Stage

  6. Click the Button component and give it an instance name of btnSend.

  7. Click the TextInput component and give it an instance name of txtMessage.

  8. Click the TextArea component and give it an instance name of txtOutput.

  9. Select the ActionScript layer and copy the following ActionScript into the first frame:

import flash.external.ExternalInterface;
import mx.utils.Delegate;

// Register callback method for retrieving messages
ExternalInterface.addCallback( "retrieveMessage", this, retrieveMessage );

// Button Click Event
btnSend.addEventListener("click", Delegate.create( this, sendMessage) );

function sendMessage():Void
{
     ExternalInterface.call( "sendMessage", "AVM1: " + txtMessage.text );
}

function retrieveMessage( msg ):Void
{
     txtOutput.text += msg + "\n";
}

  10. Publish the AVM1.swf and make note of where it is located. You will need to copy the SWF into the Flex Builder project that you create in a moment.

That’s all for the AVM1 SWF part. The ActionScript code is very straightforward. The btnSend’s click event listener calls the sendMessage function. The sendMessage function executes an ExternalInterface call to the JavaScript sendMessage method, passing text from the txtMessage.text property as its parameter.

The next steps revolve around Flex 2:

  1. Open Adobe Flex Builder 2.

  2. Create a new Flex Basic Project.

  3. Open up the index.template.html page located in the html-template folder.

  4. Copy the following HTML code in between the </script> and </head> tags of the default template:

...
</script>

<script language="JavaScript">

    function thisMovie(movieName) {
        if (navigator.appName.indexOf("Microsoft") != -1) {
            return window[movieName];
        } else {
            return document[movieName];
        }
    }
    function sendMessage(value) {
         thisMovie("${application}").retrieveMessage(value);
         thisMovie("${application}").retrieveMessage2(value);
    }
</script>

</head>
...

  5. Open up the project’s properties popup and set the Output folder and Output folder URL (located in the Flex Build Path section) to valid Web server values. This is required because of the security constraints of the Flash Player, which are enforced when using the ExternalInterface from local file system resources.

  6. Copy the AVM1.swf into the root folder of the Flex Builder 2 project.

  7. Rename the main.mxml to AVM2.mxml and copy the code from Listing 26-1 into the file.

    Listing 26-1: AVM2.mxml

    Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
  initialize="init()"
  layout="vertical">
  <mx:Script>
    <![CDATA[
      private function init():void
      {
        ExternalInterface.addCallback( "retrieveMessage2", retrieveMessage2 );
      }
      private function retrieveMessage2( str:String ):void
      {
        txtOutput.text += str + "\n";
      }
    ]]>
  </mx:Script>
  <mx:HBox>
    <mx:Button
      id="btnSend2"
      label="Send AVM2"
      click="ExternalInterface.call( 'sendMessage', 'AVM2: ' + txtMessage2.text )"/>
    <mx:TextInput
      id="txtMessage2" />
  </mx:HBox>
  <mx:TextArea
    id="txtOutput"
    width="300" height="120" />
  <mx:SWFLoader
    id="ldrAVM1"
    source="AVM1.swf" />
</mx:Application
    Image from book

  8. Run the file and see the results.

The added HTML code defines the JavaScript method sendMessage. The sendMessage method calls the retrieveMessage and retrieveMessage2 methods on the Flash embedded object. Because the Flex application loaded the AVM1 SWF through the SWFLoader, they both are listening to method calls made on the Flash embedded object made in JavaScript. The sendMessage and sendMessage2 are needed for the Flex SWF and AVM1 SWF’s ExternalInterface.addCallback() to recognize distinct callback calls from JavaScript. This wraps up the example of two different SWFs made for different AVMs communicating through the ExternalInterface class.

Figure 26-2 shows the application running with sample messages.

Image from book
Figure 26-2: Application running with sample messages


ExternalInterface and LocalConnection

Flex requires external services or servers to complete the functional requirements of most applications. The broadest options use widely defined standards and protocols (for example SOAP, Remoting, or Sockets). ExternalInterface and LocalConnection are unique in the sense that they are specific to the Flash Player and the immediate surroundings. ExternalInterface uses the Flash Player’s container application to communicate with, whereas the LocalConnection uses the Flash Player’s memory mapping. This allows different SWFs on the same client machine to communicate with each other. Put this all together and you have the ExternalInterface constrained to the Flash Player’s container applications, the LocalConnection limited to the Flash Player on the client machine, and the other communication mechanisms supported by the Flash Player open to services running on remote servers or the client machine.

The LocalConnection class acts a lot like the NetConnection class. You connect with a connection string and make calls with the send() method. The client property defines which object will handle the method calls.

Because the LocalConnection uses an area in the Flash Player process’s memory allocation space, there are limitations on the amount of data that can be passed back and forth. The size limitation is restricted to no more than 40KB of data. Using LocalConnection over ExternalInterface depends on if the applications will reside in the same container application, and if there are size constraints in data passed back and forth. The following examples show a case where LocalConnection is used to provide a non-Flash application the ability to read messages from a Flash application.


Building Custom Tracing Utility

ExternalInterface is becoming the preferred method to communicate between different SWFs, especially with the upcoming release of Adobe’s Engagement Platform technology, code-named Apollo. The LocalConnection has one unique area that has been used by developers. This section extends the custom logging and trace panel Flex classes created in Chapter 19 to communicate with a custom Windows tracing utility using the LocalConnection class.

This example requires knowledge of the C# .NET language, as well as a basic understanding of Microsoft Visual Studio development tools. The .NET Framework does not directly support the LocalConnection functionality of the Flash Player, and requires the application to directly access the Flash Player memory. Therefore, the following example covers some low-level concepts specific to the Windows operating system, which cannot all be covered in depth.

Flash Player Process Structure

When you create an SWF that uses LocalConnection, the Flash Player will create two kernel objects. These objects provide the Flash Player the most common and reliable way to exchange data between different processes or applications. The two objects are called MacromediaFMOmega and MacromediaMutexOmega. The following table shows their handle types.

Open table as spreadsheet
Type | Name
Section | \BaseNamedObject\MacromediaFMOmega
Mutant | \BaseNamedObject\MacromediaMutexOmega

A mutex is a process object that allows multiple process threads to share the same resources but not simultaneously access the shared resource. In this case, the MacromediaMutexOmega defines which process can have access to the memory area defined by MacromediaFMOmega. It is in the memory space of MacromediaFMOmega that the LocalConnection reads and writes all the communication messages. The LocalConnection’s messages are structured in the AMF message format. The memory area also holds the list listeners that are listening to the specific LocalConnection.

For the ease of explaining and providing a working example, the C# and the readily available Microsoft Visual C# IDE were chosen to be used in following example. The C# language provides a higher level abstraction and framework of classes to work with because it is compliant with the Common Language Infrastructure (CLI).

It is also important to point out the difference between managed code and unmanaged code. Managed code uses an Intermediate Language (IL) that is compiled into machine code at run-time. Because the code is executed through a managed virtual machine, all garbage collection, exception handling, and type checking can be guaranteed. Earlier languages such as C and C++ are considered unmanaged code, because all memory allocation, assignment of memory, and releasing of memory is handled by the code itself. C++ is not left out, as the newer compilers will allow both managed and unmanaged code to be compiled. As for C#, this is done through the Component Object Model (COM) interoperability.

To accomplish creating a C# .NET application capable of reading the LocalConnection messages, the MacromediaMutexOmega and MacromediaFMOmega will need to be used. The C# .NET environment, by default, is a managed code base. To access memory directly using C#, the application must execute unmanaged code and make calls to specific Win 32 DLLs. Once you have access to the memory through the mutex object, the memory must be read byte-for-byte and deserialized into something meaningful.

Using LocalConnection and C# .NET Windows Application

This example uses the Flex custom logger classes that were used in Chapter 19. First, a new Target class is needed to use LocalConnection as the communication mechanism, as shown in Listing 26-2.

Listing 26-2: LocalConnectionTraceTarget.as
Image from book

package
{

import flash.events.StatusEvent;
import flash.net.LocalConnection;

import mx.controls.TextArea;
import mx.core.mx_internal;
import mx.logging.ILogger;
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;

use namespace mx_internal;

public class LocalConnectionTraceTarget extends LineFormattedTarget {

  public function LocalConnectionTraceTarget() {
    super();

    lc = new LocalConnection();
    lc.addEventListener(StatusEvent.STATUS, statusEventHandler);
  }

  private var lc:LocalConnection;

  private function statusEventHandler(event:StatusEvent):void {
    // Handles Event Status Calls
  }

  override public function logEvent(event:LogEvent):void
  {
    var level:int = event.level;

    var date:String = "";
    if (includeDate || includeTime)
    {
      var d:Date = new Date();
      if (includeDate)
      {
        date = Number(d.getUTCMonth() + 1).toString() + "/" +
        d.getUTCDate().toString() + "/" +
        d.getUTCFullYear() + fieldSeparator;
      }
      if (includeTime)
      {
        date = pad(d.getUTCHours()) + ":" +
        pad(d.getUTCMinutes()) + ":" +
        pad(d.getUTCSeconds()) + "." +
        pad(d.getUTCMilliseconds()) + fieldSeparator;
      }
    }

    var category:String = includeCategory ?
        ILogger(event.target).category + fieldSeparator : "";

    // Connection and Method specific to C# .NET applicaton Flex2TracePanel
    lc.send( "_flex2tracepanel", "logMessage", date + category + event.message, level);
  }

  private function pad(num:Number):String
  {
    return num > 9 ? num.toString() : "0" + num.toString();
  }

}
}
Image from book

The TracePanel.mxml now can include the new LocalConnectionTraceTarget.as class as a potential target for the loggers. The LocalConnectionTraceTarget class uses the LocalConnection to make a method call called "logMessage" on the "_flex2tracepanel" connection. The updates for the new LocalConnectionTraceTarget and checkbox for starting and stopping are found in Listing 26-3.

Listing 26-3: TracePanel.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
  title="Trace Panel"
  paddingBottom="10" paddingLeft="10"
  paddingRight="10" paddingTop="10"
  minHeight="360"
  minWidth="400"
  initialize="init()"
  showCloseButton="true"
  close="close()"
  layout="vertical">
  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.logging.LogEventLevel;
      import mx.collections.ArrayCollection;
      import mx.managers.PopUpManager;

      public var isOpen:Boolean = false;

      [Bindable]
      private var targets:ArrayCollection;

      private var target:TracePanelTarget;
      private var target2:LocalConnectionTraceTarget;
      private function init():void
      {
        target = new TracePanelTarget( txtOutput );
        target.filters=["*"];
        target.level = LogEventLevel.ALL;
        target.includeDate = true;
        target.includeCategory = true;
        target.includeLevel = true;

        target2 = new LocalConnectionTraceTarget();
        target2.filters=["*"];
        target2.level = LogEventLevel.ALL;

        Log.getLogger( "TracePanel" ).debug( "initilization" );
      }

      private function close():void
      {
        isOpen = false;
        PopUpManager.removePopUp( this );
      }

      private function changeTarget():void
      {
        if( !chkFlag.selected ) {
          Log.addTarget( target );
          Log.getLogger( "TracePanel" ).info( "Turned logging on!" );
        } else {
          Log.getLogger( "TracePanel" ).info( "Turning logging off!" );
          Log.removeTarget( target );
        }
      }
      private function changeFlex2Target():void
      {
        if( !chkFlex2TracePanel.selected ) {
          Log.addTarget( target2 );
          Log.getLogger( "TracePanel" ).info( "Turned logging on!" );
        } else {
          Log.getLogger( "TracePanel" ).info( "Turning logging off!" );
          Log.removeTarget( target2 );
        }
      }

      private function filterTarget():void
      {
        Log.getLogger( "TracePanel" ).info( "Filter change!" );
        Log.removeTarget( target );
        Log.removeTarget( target2 );
        target.filters = idFilter.text.split( "," );
        if( target.filters == null )
          target.filters = ["*"];
        target2.filters = idFilter.text.split( "," );
        if( target2.filters == null )
          target2.filters = ["*"];
        Log.addTarget( target );
        Log.addTarget( target2 );
      }

    ]]>
  </mx:Script>

  <mx:Form>
    <mx:FormItem label="Filter Categories:">
      <mx:TextInput
        id="idFilter"
        text="*"
        change="filterTarget()" />
    </mx:FormItem>
    <mx:FormItem label="Turn Local Logging Off:">
      <mx:CheckBox
        id="chkFlag"
        selected="false"
        change="changeTarget()" />
    </mx:FormItem>
    <mx:FormItem label="Turn Flex2 Trace Panel Logging Off:">
      <mx:CheckBox
        id="chkFlex2TracePanel"
        selected="false"
        change="changeFlex2Target()" />
    </mx:FormItem>
  </mx:Form>
  <mx:HBox
      width="100%"
      horizontalAlign="center">
    <mx:Button
      label="Clear Output"
      click="txtOutput.text = ''" />
  </mx:HBox>
  <mx:Label
    text="Output Console" />
  <mx:TextArea
    id="txtOutput"
    updateComplete="txtOutput.verticalScrollPosition =
txtOutput.maxVerticalScrollPosition + 1;"
    width="100%" height="100%" />
</mx:TitleWindow>
Image from book

Now the CustomLoggerMain.mxml application will execute both the TracePanelTarget and LocalConnectionTraceTarget, once the TracePanel title window has been called. The C# application will constantly look at the memory space for any LocalConnection messages made by calling logMessage on the connection named _flex2tracepanel.

Follow these steps to create the C# application:

  1. Open Microsoft Visual C# 2005 (Express Edition).

  2. Create a project, selecting the Windows Application project template.

  3. Name the project Flex2TracePanel and click the OK button.

  4. Change the name of Form1.cs to Flex2TracePanel.cs.

  5. Right-click the Flex2TracePanel.cs file and select View Code.

  6. Copy the code from Listing 26-4 into the file.

    Listing 26-4: Flex2TracePanel.cs

    Image from book

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Threading;
// Used for DllImport
using System.Runtime.InteropServices;

namespace Flex2TracePanel
{
  public partial class frmMain : Form
  {
    private string CONNECTION_NAME = "_flex2tracepanel";
    private string METHOD_NAME = "logMessage";
    private int DEBUG_LEVEL = (int)MessageLevel.Error;

    public frmMain()
    {
      InitializeComponent();
    }

    private void Flex2TracePanel_Load(object sender, EventArgs e)
    {
      txtOutput.AutoScrollOffset = new Point(0, txtOutput.Height);
    }

    // Mutex for the Control of process
    private Mutex mut;
    // Pointer to the Memory of the Process
    private IntPtr hMapFile = IntPtr.Zero;

    private string lastArg1;
    private int lastArg2;
    private unsafe void pollMutex()
    {
      // false = don't take ownership
      // "MacromediaMutexOmega" = name of mutex
      if( mut == null )
        mut = new Mutex(false, "MacromediaMutexOmega");

      try
      {
        // Wait 5 seconds
        if (mut.WaitOne(5000, false))
        {
          // Has control of mutex
          try
          {
                // OpenFileMapping method comes from the imported dll
            hMapFile = OpenFileMapping((int)MapAccess.FileMapAllAccess, false,
"MacromediaFMOmega");
            // MapViewOfFile method comes from the imported dll
            IntPtr baseMapAddress = MapViewOfFile(hMapFile,
(int)MapAccess.FileMapAllAccess,0, 0, 0);
            if (baseMapAddress != null)
            {
              output("Reading MapViewOfFile!", (int)MessageLevel.Info);
              byte* buffer = (byte*)baseMapAddress.ToPointer();
              //String hexStr = "";
              // Make sure memory address is valid

              // Is byte 16 a AMF String (0x02) identifier
              if ( buffer != null && (int)buffer[16] == 2)
              {
                int currentPoint = 16 + 2;
                /** Find LocalConnection connection name **/
                // 16 will always be a AMF String value 0x02
                // next 2 bytes define length so we pick up the tail end one
                int len = (int)buffer[currentPoint];
                // Move pointer to start reading string
                currentPoint++;

                // Convert bytes into String
                string connectionName = "";
                for (int i = 0; i < len; i++)
                {
                  // No char check, Assume values are valid
                  connectionName += (char)ushort.Parse(buffer[currentPoint+i]
.ToString("X2"),
System.Globalization.NumberStyles.HexNumber);
                }
                // Move pointer to next AMF data type
                currentPoint += len;

                if (CONNECTION_NAME == connectionName)
                {
                  // AMF String (0x02) has two Length bytes that are Big Endian
                  // Therefore you will see alot of + 2 pointers to get the Length
                  // I am only reading the last Length byte and assuming the length
will not be longer

                  // Skip Protocol String by getting protocal string length and
adding 2 bytes for the length
                  output(" Protocol len: " + (int)buffer[currentPoint + 2]);
                  currentPoint += (int)buffer[currentPoint + 2] + 3;
                  // Move to Method Name strings length bytes
                  currentPoint += 2;

                  // Get Method Name
                  int lenMethod = (int)buffer[currentPoint];
                  // Move pointer to start reading string
                  currentPoint++;

                  string methodName = "";
                  for (int i = 0; i < lenMethod; i++)
                  {
                    // No char check, Assume values are valid
                    methodName += (char)ushort.Parse(buffer[currentPoint +
i].ToString("X2"), System.Globalization.NumberStyles.HexNumber);
                  }
                  // Move pointer to next AMF data type
                  currentPoint += lenMethod;
                  output("ConnectionName: " + connectionName + " MethodName: " +
methodName + " len: " + lenMethod);
                  if (METHOD_NAME == methodName)
                  {
                    // Method arguments are in reverse order
                    // You have to know how many parameters there are
                    // Trace Logging Level
                    int arg2 = 0;
                    // Trace Message
                    string arg1 = "";

                    // AMF Number (0x00) is Big Endian 64 bit so need to convert

                    // Check to make sure Arg2 is a Number
                    if (0 == (int)buffer[currentPoint])
                    {
                      // Move to read Number
                      currentPoint++;
                      string strAMFNumber = "";
                      for (int i = 0; i < 8; i++)
                      {
                        // Reverse Binary String and then do Endian switch
                        string hexValue = buffer[currentPoint + i].ToString("X2");
                        string binaryStr = Convert.ToString(Convert.ToInt32
(hexValue, 16), 2).PadLeft(8, '0');
                        char[] chars = binaryStr.ToCharArray();
                        Array.Reverse(chars);
                        string reversed = new string(chars);

                        strAMFNumber += Convert.ToString(Convert.ToInt32(reversed,
2), 16).PadLeft(2,'0'); ;
                        //output("1: " + reversed + " - " + binaryStr);
                      }
                      currentPoint += 8;
                      //output("strAMFNumber: " + strAMFNumber);
                      UInt64 realNumber = convertAMFNumber
(UInt64.Parse(strAMFNumber, System.Globalization.NumberStyles.HexNumber));

                      arg2 = (int)realNumber;

                      // Check to make sure Arg1 is a String
                      if (2 == (int)buffer[currentPoint])
                      {
                        currentPoint += 2;
                        // Get String len
                        int lenArg1 = (int)buffer[currentPoint];
                        // Move pointer to start reading string
                        currentPoint++;

                        for (int i = 0; i < lenArg1; i++)
                        {
                          // No char check, Assume values are valid
                          arg1 += (char)ushort.Parse(buffer[currentPoint +
i].ToString("X2"), System.Globalization.NumberStyles.HexNumber);
                        }
                      }
                      if (arg1 != lastArg1 || arg2 != lastArg2)
                      {
                        // Prep real message
                        string msg = "";
                        string levelStr = "MSG";
                        if (arg2 == 2)
                          levelStr = "DEBUG";
                        if (arg2 == 4)
                          levelStr = "INFO";
                        if (arg2 == 6)
                          levelStr = "WARN";
                        if (arg2 == 8)
                          levelStr = "ERROR";
                        if (arg2 == 1000)
                          levelStr = "FATAL";

                        msg = "[" + levelStr + "]: " + arg1;

                        // Send message
                        output(msg, (int)MessageLevel.ValidMessage);
                      }
                      lastArg1 = arg1;
                      lastArg2 = arg2;
                    }
                    else
                    {
                      output("Method level argument must be a Number!",
(int)MessageLevel.Error);
                    }
                  }
                }
              }
            }
            else
            {
              output("MapViewOfFile failed!");
            }
          }
          finally
          {
            // Release ownership of the mutex object.
            mut.ReleaseMutex();
            output("Release Mutex!");
          }
        }
        else
        {
          // Reached timeout try again
          output("Mutex Timed out!");
          Thread.Sleep(500);
        }

      }
      catch (AbandonedMutexException ame)
      {
        // Mutex was abandoned
        output("Mutex was abandoned!");
        Thread.Sleep(500);
      }
      Thread.Sleep(500);

      // Infinite Loop, handled by Thread Suspend/Resume
      pollMutex();
}

    private void output(string str)
    {
      output(str, (int)MessageLevel.Debug);
    }

    delegate void OutputCallback(string str, int level);
    private void output(string str, int level )
    {
      // To Turn on internal code messages change to true
      if (DEBUG_LEVEL <= level)
      {
        if (this.txtOutput.InvokeRequired)
        {
          OutputCallback d = new OutputCallback(output);
          this.Invoke(d, new object[] { str, level });
        }
        else
        {
          txtOutput.Text += str + Environment.NewLine;
        }
      }}
    /**
     *  Convert Big Endian to Little Endian
     */
    private UInt64 convertAMFNumber(UInt64 AMFNumber)
    {
      AMFNumber = (AMFNumber >> 56) |
            ((AMFNumber << 40) & 0x00FF000000000000) |
            ((AMFNumber << 24) & 0x0000FF0000000000) |
            ((AMFNumber << 8) & 0x000000FF00000000) |
            ((AMFNumber >> 8) & 0x00000000FF000000) |
            ((AMFNumber >> 24) & 0x0000000000FF0000) |
            ((AMFNumber >> 40) & 0x000000000000FF00) |
            (AMFNumber << 56);
      return AMFNumber;
    }

    private Thread pollThread;
    private void chkPoll_CheckedChanged(object sender, EventArgs e)
    {
      if (chkPoll.Checked)
      {
        output("Create Poll Thread");
        if (pollThread == null)
        {
          output("Create Thread");
          pollThread = new Thread(new ThreadStart(pollMutex));
          pollThread.Start();
        }
        else
        {
          pollThread.Resume();
        }
      }
      else
      {
        pollThread.Suspend();
      }

    }

    private void btnClear_Click(object sender, EventArgs e)
    {
      txtOutput.Text = "";
    }

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern IntPtr OpenFileMapping(
       int dwDesiredAccess,
       bool bInheritHandle,
       String lpName);

    [DllImport("kernel32", SetLastError = true)]
    public static extern IntPtr MapViewOfFile(
       IntPtr hFileMappingObject,
       int dwDesiredAccess,
       int dwFileOffsetHigh,
       int dwFileOffsetLow,
       int dwNumBytesToMap);

    public enum MapAccess
    {
      FileMapCopy = 0x0001,
      FileMapWrite = 0x0002,
      FileMapRead = 0x0004,
      FileMapAllAccess = 0x001f,
    }

    public enum MessageLevel
    {
      Error = 6,
      Info = 4,
      Debug = 2,
      All = 0,
      ValidMessage = 12,
    }

    private void txtOutput_TextChanged(object sender, EventArgs e)
    {
      SetScrollPos(txtOutput.Handle, 1, txtOutput.Lines.Length - 1, true);
      SendMessage(txtOutput.Handle, EM_LINESCROLL, 0, txtOutput.Lines.Length - 1);
    }

    const int EM_LINESCROLL = 0x00B6;
    [DllImport("user32.dll")]
    static extern int SetScrollPos(IntPtr hWnd, int nBar,
                     int nPos, bool bRedraw);
    [DllImport("user32.dll")]
    static extern int SendMessage(IntPtr hWnd, int wMsg,
                     int wParam, int lParam);

    private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (pollThread != null)
      {
        pollThread.Resume();
        pollThread.Abort();
      }

    }

  }
}
    Image from book

  7. Open up the Flex2TracePanel.Designer.cs file.

  8. Copy the code from Listing 26-5 into the file.

    Listing 26-5: Flex2TracePanel.Designer.cs

    Image from book

namespace Flex2TracePanel
{
  partial class frmMain
  {
    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed;
otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
      if (disposing && (components != null))
      {
        components.Dispose();
      }
      base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
      this.txtOutput = new System.Windows.Forms.TextBox();
      this.chkPoll = new System.Windows.Forms.CheckBox();
      this.btnClear = new System.Windows.Forms.Button();
      this.SuspendLayout();
      //
      // txtOutput
      //
      this.txtOutput.Anchor = ((System.Windows.Forms.AnchorStyles)
((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
            | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
      this.txtOutput.Location = new System.Drawing.Point(0, 26);
      this.txtOutput.Multiline = true;
      this.txtOutput.Name = "txtOutput";
      this.txtOutput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
      this.txtOutput.Size = new System.Drawing.Size(503, 371);
      this.txtOutput.TabIndex = 0;
      this.txtOutput.TextChanged += new System.EventHandler
(this.txtOutput_TextChanged);
      //
      // chkPoll
      //
      this.chkPoll.AutoSize = true;
      this.chkPoll.Location = new System.Drawing.Point(3, 5);
      this.chkPoll.Name = "chkPoll";
      this.chkPoll.Size = new System.Drawing.Size(152, 17);
      this.chkPoll.TabIndex = 1;
      this.chkPoll.Text = "Listen for LocalConnection";
      this.chkPoll.UseVisualStyleBackColor = true;
      this.chkPoll.CheckedChanged += new System.EventHandler
(this.chkPoll_CheckedChanged);
      //
      // btnClear
      //
      this.btnClear.Location = new System.Drawing.Point(162, 1);
      this.btnClear.Name = "btnClear";
      this.btnClear.Size = new System.Drawing.Size(54, 23);
      this.btnClear.TabIndex = 2;
      this.btnClear.Text = "Clear";
      this.btnClear.UseVisualStyleBackColor = true;
      this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
      //
      // frmMain
      //
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
      this.ClientSize = new System.Drawing.Size(504, 395);
      this.Controls.Add(this.btnClear);
      this.Controls.Add(this.chkPoll);
      this.Controls.Add(this.txtOutput);
      this.Name = "frmMain";
      this.Text = "Flex 2 Trace Panel";
      this.FormClosing += new System.Windows.Forms.FormClosingEventHandler
(this.frmMain_FormClosing);
      this.Load += new System.EventHandler(this.Flex2TracePanel_Load);
      this.ResumeLayout(false);
      this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.TextBox txtOutput;
    private System.Windows.Forms.CheckBox chkPoll;
    private System.Windows.Forms.Button btnClear;
  }
}
    Image from book

  9. Open up the Program.cs file.

  10. Copy the code from Listing 26-6 into the file.

    Listing 26-6: Program.cs

    Image from book

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Flex2TracePanel
{
  static class Program
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run(new frmMain());
    }
  }
}
    Image from book

  11. Select the Project Image from book Flex2TracePanel Properties menu item.

  12. With the project Properties page open, select the Build tab.

  13. Click the “Allow unsafe code” checkbox.

  14. Save the file by pressing Ctrl+S or selecting File Image from book Save Selected Items.

  15. You are now ready to build the project and run the application.

  16. Press F5 or select Debug Image from book Start Debugging to run the project application.

Listing 26-4 is rather long, but it helps demonstrate specific code functionality. Explanations appear after the listing. Listing 26-4 also contains in-code comments that help describe specific lines of code.

The pollMutex() method makes it all work. The method repeatedly makes a call on itself, asking for control of the mutex and then accessing the memory. It will create a mutex handler, and then call mut.WaitOne( 5000, false ) to wait five seconds to receive control of the mutex.

If the mutex is received, it will access MacromediaFMOmega and read the LocalConnection message. The message stored in the LocalConnection memory area is formatted as an AMF message and must be decoded. To know if the current message in the LocalConnection is a valid message for the current listener, the decoded message is searched for the correct connection name, method name, and corresponding parameters.

If the mutex is not received, it tries again in a half a second by calling Thread.Sleep(500);. Then the process starts again.

The output() method handles displaying the text in the text area. Any message coming into the output( str, level ) method call is checked first to see a LocalConnection message defined by calling output with the MessageLevel.ValidMessage value. The other levels are for internally debugging the application. The OutputCallback is a function declared as delegate type that handles inserting a method call coming from unmanaged code into the manage method call stack. This keeps calls coming from unmanaged code from creating a race condition or other unwanted side effects.

The rest of the methods in the file help with AMF decoding, and define constants, and application events.

The Flex2TracePanel.Designer.cs shown in Listing 26-5 defines the placement, events, and default values of the application’s controls. The separation of the design code and business logic into two files is the typical method of creating a C# application within the Microsoft Visual Studio products. The default application executable class is defined in Program.cs, shown in Listing 26-6.

With the C# .NET application and the Flex application running at the same time, you will see the LocalConnection trace messages show up in the Flex2TracePanel C# application text box.


Summary

Flex leverages many different kinds of classes to communicate with external applications. Starting with direct communications to the Flash Player’s container applications and on up to talking with remote services, the Flash Player is robust when it comes to integrating with external applications. This chapter provided an example to show how to have SWFs created for the new and old ActionScript virtual machines talk to each other, as well as how to create a C# .NET tracing utility using Flash Player LocalConnection.

Appendix A describes the major features introduced in the newly released update for Flex 2. The release update is called Flex 2.0.1. The discussion in the appendix touches on run-time CSS support, the ASDoc tool, and how to use the new Module classes.


Appendix A: Flex 2.0.1

Overview

The first major update to Flex 2.0.1 promises many bug fixes, as well as new class additions to the Flex Framework. This appendix covers the following new features:

  • Run-time CSS support

  • ASDoc tool

  • Building modular Flex applications

The Flex 2.0.1 update was released in January 2007. All the examples in this appendix require the Flex Builder 2.0.1 or Flex SDK 2.0.1 update.


Run-time CSS Support

The ability to load and apply style sheets at run-time is the first feature introduced in Flex 2.0.1 that this appendix covers. The StyleManager class gained two new methods that load and unload SWFs containing style information. The names of the methods are loadStyleDeclarations() and unloadStyleDeclarations().

To create style SWFs easily, Flex Builder 2 also received new functionality called “Compile CSS to SWF.” This is located by right-clicking a CSS file in your project and checking the Compile CSS to SWF context menu item. When the menu item is checked, the CSS files will be automatically compiled into an SWF and put into the bin folder.

The code in Listing A-1, Listing A-2, and Listing A-3 demonstrates how to create two different CSS files and switch between them and the default style, all at run-time.

Listing A-1: RuntimeCSSMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="vertical">

  <mx:Script>
    <![CDATA[
      import mx.controls.Alert;

    import mx.styles.StyleManager;
    import mx.events.StyleEvent;

    private var lastCSS:String;
    private function changeCSS( name:String ):void
    {
      // If you do not unload the last style
      // previous style settings will be in effect
      unloadCSS( false );
      var styleEvent:IEventDispatcher =
        StyleManager.loadStyleDeclarations( name, true );
      lastCSS = name;
    }
    private function unloadCSS( updateFlag:Boolean ):void
    {
      if( lastCSS )
        StyleManager.unloadStyleDeclarations( lastCSS, updateFlag );
    }
    ]]>
  </mx:Script>

  <mx:Panel id="pnlApp" title="Sample Application"
    paddingBottom="10" paddingLeft="10"
    paddingRight="10" paddingTop="10"
    layout="vertical" horizontalAlign="center">
    <mx:Label
      text="Please fill out the form below and click on Login!" />
  <mx:Form>
    <mx:FormItem label="Username:">
      <mx:TextInput id="txtUsername" />
    </mx:FormItem>
    <mx:FormItem label="Password:">
      <mx:TextInput id="txtPassword" displayAsPassword="true" />
    </mx:FormItem>
  </mx:Form>
    <mx:Button id="btnTrace" label="Login" styleName="sLogin" />
  </mx:Panel>
  <mx:HBox>
    <mx:Button id="btnUnload" cornerRadius="0"
      click="unloadCSS( true )"
      label="one"
      fillColors="[#7C929D,#CCCCCC]" />
  <mx:Button id="btnBlue" cornerRadius="0"
    click="changeCSS( 'blueCSS.swf' )"
    label="two"
    fillColors="[#336699,#5588BB]" />
  <mx:Button id="btnRed" cornerRadius="0"
    click="changeCSS( 'redCSS.swf' )"
    label="three"
    fillColors="[#993333,#BB5555]" />
  </mx:HBox>
</mx:Application>
Image from book
Listing A-2: blueCSS.css
Image from book

/* CSS file */
Application {
     backgroundImage: "";
     backgroundColor: #336699;
}

Panel {
     cornerRadius: 0;
     backgroundColor: #DDDDDD;
     borderStyle: none;
}

.sLogin {
     fillColors: #777777,#000000;
     color: #DDDDDD;
}
Image from book
Listing A-3: redCSS.css
Image from book

/* CSS file */
Application {
     backgroundImage: "";
     backgroundColor: #993333;
}

Panel {
     cornerRadius: 6;
     backgroundAlpha: 0.2;
     backgroundColor: #DDDDDD;
}

Label {
     color: #FFFFFF;
     fontWeight: bold;
     fontStyle: italic;
}
Image from book

Create a Flex Builder project and put the Listing A-1, Listing A-2, and Listing A-3 files into the project root folder. Ensure that the CSS files have the Compile CSS to SWF context menu item selected and then run the application. Figure A-1 shows the initial state of the application and the three buttons on the bottom labeled one, two, and three. Button two (center) and button three (far right) are implemented to load the blueCSS.swf and redCSS.swf dynamically when each respective button is clicked. The but-ton two style is shown in Figure A-2, and button three’s style is shown in Figure A-3.

Image from book
Figure A-1: Default style
Image from book
Figure A-2: Button two’s style
Image from book
Figure A-3: Button three’s style

It is important to note that if the code did not unload the previous style each time the button were clicked, it would be possible to have leftover styles hanging around. For example, comment out the unloadCSS ( false ) and lastCSS = name; code lines in the RuntimeCSSMain.mxml, as shown here:

...
    private function changeCSS( name:String ):void
    {
      // If you do not unload the last style
      // previous style settings will be in effect
      // unloadCSS( false );
      var styleEvent:IEventDispatcher =
        StyleManager.loadStyleDeclarations( name, true );
      //lastCSS = name;
    }
...

Now, run the application and click button three (far right) first, then button two (center). The redCSS.swf sets the Label’s font color style to white and the font weight to bold. When clicking button two, the blueCSS.swf is loaded, but the Label’s style is not defined explicitly. Therefore, it is not reset, and stays bold and white.

With the ability to load style resources at run-time, developers now have more options to approach lazy-loading SWF applications. This will be a hot new feature.


ASDoc Tool

The Adobe Flex 2 Language Reference documentation found on the Adobe Web site was created with a tool called ASDoc. Flex 2.0.1 provides developers the ASDoc command-line tool to create documentation for their own components and classes. The command-line executable is called asdoc and is located in the bin directory, along with the mxmlc and compc compilers. The tool generates HTML files that describe package, property, method, and other class information through syntax written as comments in the code. The syntax uses a number of specific ASDoc tags to tell asdoc how to generate the documentation.

ASDoc Tags and Syntax

The following table lists the tags used in this appendix’s example code. The example logging code created in Chapter 19 will be modified to demonstrate ASDoc’s capabilities.

Open table as spreadsheet
ASDoc Tag Syntax | Description
/** */ | Comment the block starting with /** and ending with */. This syntax tells ASDoc to read text and tags inside the command block.
/** | Text wrapped in a comment block not preceded by a tag will be read as the main description.
<p></p> | Used for each description paragraph that precedes the first paragraph.
<code></code> | Used around text inside the comment blocks to define a specific style for the ASDoc to output for that specific text.
@private | The specific code will not be included in the ASDoc output.
@param paramName description | Defines descriptions for each parameter in the method. You can declare multiple @param values in a code block.
@default value | The text describing the default value for the property.
@see classname [display text] | The classname defines other classes in the documentation that will be linked. ASDoc puts output under the “See also” area.
@return description | Description of the value the method will return.

Documenting the Logger Classes

Follow these steps to learn about the process of documenting classes:

  1. Open Adobe Flex Builder 2.

  2. Create a new Flex Basic Project and call it ProfessionalFlexLogging.

  3. Create the following folders in the root of the project:

    1. /professional/

    2. /professional/flex2/

    3. /professional/flex2/logging/

  4. Copy the following files from Chapter 19 and Chapter 27 into the /professional/flex2/logging/ folder:

    1. LocalConnectionTraceTarget.as

    2. LogController.mxml

    3. TracePanel.mxml

    4. TracePanelTarget.as

  5. Copy the CustomLoggerMain.mxml file into the root of the project.

  6. Open CustomLoggerMain.mxml and change the following line of code:

    xmlns:logger="*"

    to

    xmlns:logger="professional.flex2.logging.*"

  7. Open LocalConnectionTraceTarget.as and change package to package professional.flex2.logging.

  8. Open TracePanelTarget.as and change package to package professional.flex2.logging.

The next code snippet outlines code examples highlighting ASDoc comment syntax. The full code listings are located later in the appendix. To start, open the TracePanelTarget.as file and add the following comment block to the constructor method:

...
     /**
       *      Constructor.
       *
       *      @param console Reference to a <code>TextArea</code>
       *                 object that will display the output
       *                of the messages.
       */
    public function TracePanelTarget( console:TextArea ) {
          super();
          this.console = console;
    }
...

The first block of text will be picked up as the first paragraph. The @param tag defines the parameter of the constructor. The best way to see what the comment syntax does is to compile the documentation and see what it looks like. Continue on to the next section to learn how to use the asdoc compiler. The second part of learning how to document the logger classes continues in the section after that, “Documenting the Logger Classes – Continued”.

Using the ASDoc Compiler

The ASDoc tool is a command-line tool with multiple compile arguments. The important ones to understand are –doc-sources, –doc-classes, and –source-path. The first two give you two options for compiling the documentation, by source file or by class name. If you navigate to the ProfessionalFlexLogging Flex Project created earlier in the appendix, the following are available source files:

  • CustomLoggerMain.mxml

  • /professional/flex2/logging/LocalConnectionTraceTarget.as

  • /professional/flex2/logging/LogController.mxml

  • /professional/flex2/logging/TracePanel.mxml

  • /professional/flex2/logging/TracePanelTarget.as

You would use the full name or directory pattern syntax to determine the value of –doc-sources. The following are the comparable class names:

  • CustomLoggerMain

  • professional.flex2.logging.LocalConnectionTraceTarget

  • professional.flex2.logging.LogController

  • professional.flex2.logging.TracePanel

  • professional.flex2.logging.TracePanelTarget

When configured to compile a specific class, the ASDoc tool will also compile all the classes that it references. Finally, the –source-path is needed to tell the ASDoc where to start looking for source files. The –source-path compile argument is like class path values used in other compilers. To run the following example asdoc command-line calls, open up a command prompt and navigate to the ProfessionalFlexLogging project folder on the file system:

// Output set to docs folder
// Create documentation for class CustomLoggerMain
// Classpath set to ./ or the same folder
asdoc –output docs –doc-classes CustomLoggerMain –source-path ./

// Output set to targets folder
// Create documentation for the two Target classes
asdoc –output targets –doc-classes professional.flex2.logging
.LocalConnectionTraceTarget professional.flex2.logging
.TracePanelTarget –source-path ./

// Output set to logging folder
// Create documentation for all sources files under the professional folder
//  this will not pick up CustomLoggerMain
asdoc –output logging –doc-sources ./professional/ -source-path

Documenting the Logger Classes – Continued

You are equipped to create the documentation for TracePanelTarget.as and view how the comments look in the outputted HTML. Run the following command:

asdoc –output docs –doc-classes professional.flex2.logging.TracePanelTarget
–source-path ./

Open up the index.html in a browser. The index.html is located in the docs folder that the ASDoc tool created.

The ASDoc tool does provide limited ability to document MXML files as well. The comment syntax blocks are constrained to being processed inside the <mx:Script></mx:Script> code tags of an MXML file. Open up the TracePanel.mxml file and add the following ASDoc comments:

...
/**
 *  Property used in connection with Popup functionality.
 *  The value defines the popup state of the control.
    *
    *  @default false
    */
    public var isOpen:Boolean = false;
...

The @default comment tag is used to document that the isOpen property is defaulted to false. Run asdoc on the whole project by using the following command and see the results:

asdoc –output docs –doc-classes CustomLoggerMain –source-path ./

Open up the index.html and click the TracePanel class located in the panels on the left. You’ll find the isOpen property detail containing the following text: “The default value is false.” You can now add more documentation comments and view the results. Listing A-4, Listing A-5, and Listing A-6 show the source files implemented with ASDoc comments. Copy the source files over to your project and play with different comment tag syntaxes.

Listing A-4: LocalConnectionTraceTarget.as
Image from book

package professional.flex2.logging
{

import flash.events.StatusEvent;
import flash.net.LocalConnection;

import mx.controls.TextArea;
import mx.core.mx_internal;

import mx.logging.ILogger;
import mx.logging.LogEvent;
import mx.logging.targets.LineFormattedTarget;

use namespace mx_internal;

/**
 * The <code>LocalConnectionTraceTarget</code> extends the
 * <code>LineFormattedTarget</code> class to provide
 * a basic output mechanism.  This target uses
 * <code>LocalConnection</code> to output the trace
 * messages to any other application using
 * <code>LocalConnection</code> listening on
 * <code>_flex2tracepanel</code>.
 *
 * @see mx.logging.targets.LineFormattedTarget
 */
public class LocalConnectionTraceTarget extends LineFormattedTarget {

  /**
   *  Constructor.
   */
public function LocalConnectionTraceTarget() {
  super();

  lc = new LocalConnection();
  lc.addEventListener(StatusEvent.STATUS, statusEventHandler);
}

/**
 *  @private
 */
private var lc:LocalConnection;

/**
 *  @private
 *  @internal Need to keep Flex 2 from throwing unhandled
 *        status errors
 */
private function statusEventHandler(event:StatusEvent):void {
  ; // Handles Event Status Calls
}

/**
 *  The <code>internalLog</code> method handles the
 *  sending of messages.
 *
 *  @param event <code>LogEvent</code> sent to a
 *         <code>ILogger</code> from the <code>Log</code> class.
 */
override public function logEvent(event:LogEvent):void
{
  var level:int = event.level;

  var date:String = ""
  if (includeDate || includeTime)
  {
    var d:Date = new Date();
    if (includeDate)
    {
      date = Number(d.getUTCMonth() + 1).toString() + "/" +
      d.getUTCDate().toString() + "/" +
      d.getUTCFullYear() + fieldSeparator;
    }
    if (includeTime)
    {
      date = pad(d.getUTCHours()) + ":" +
      pad(d.getUTCMinutes()) + ":" +
      pad(d.getUTCSeconds()) + "." +
      pad(d.getUTCMilliseconds()) + fieldSeparator;
    }
  }

  var category:String = includeCategory ?
      ILogger(event.target).category + fieldSeparator : "";

    // Connection and Method specific to C# .Net applicaton Flex2TracePanel
    lc.send( "_flex2tracepanel", "logMessage", date + category + event.message,
level);
  }

  /**
   *  The pad method adds leading 0's to single digit numbers.
   *
   *  @return The string representation of two digit leading 0 number.
   */
  private function pad(num:Number):String
  {
    return num > 9 ? num.toString() : "0" + num.toString();
  }

}
}
Image from book
Listing A-5: TracePanelTarget.as
Image from book

package professional.flex2.logging
{

import mx.core.mx_internal;
import mx.controls.TextArea;
import mx.logging.targets.LineFormattedTarget;

use namespace mx_internal;

/**
 * The <code>TracePanelTarget</code> extends the
 * <code>LineFormattedTarget</code> class to provide
 * a basic output mechanism.  This target requires a
 * reference to a <code>TextArea</code> object. The
 * <code>TracePanelTarget</code> uses the reference to
 * the <code>TextArea</code> object to output message
 * line by line.
 *
 * @see mx.logging.targets.LineFormattedTarget
 */
public class TracePanelTarget extends LineFormattedTarget {

  /**
   *  Constructor.
   *
   *  @param console Reference to a <code>TextArea</code>
   *           object that will display the output
   *           of the messages.
   */
  public function TracePanelTarget( console:TextArea ) {
    super();
    this.console = console;
  }

  /**
   *  @private
   */
  private var console:TextArea;

  /**
   *  The <code>internalLog</code> method handles the
   *  sending of messages.
   *
   *  @param message The message to be logged by this target.
   */
  override mx_internal function internalLog(message:String):void
  {
    console.text += message + "\n";
  }

}
}
Image from book
Listing A-6: TracePanel.as
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:mx="http://www.adobe.com/2006/mxml"
  title="Trace Panel"
  paddingBottom="10" paddingLeft="10"
  paddingRight="10" paddingTop="10"
  minHeight="360"
  minWidth="400"
  initialize="init()"
  showCloseButton="true"
  close="close()"
  layout="vertical">
  <mx:Script>
    <![CDATA[
      import mx.logging.Log;
      import mx.logging.LogEventLevel;
      import mx.collections.ArrayCollection;
      import mx.managers.PopUpManager;

      /**
       *  Property used in connection with Popup functionality.
       *  The value defines the popup state of the control.
       *
       *  @default false
       */
      public var isOpen:Boolean = false;

      /**
       *  @private
       */
      [Bindable]
      private var targets:ArrayCollection;

      /**
       *  @private
       */
      private var target:TracePanelTarget;

      /**
       *  @private
       */
      private var target2:LocalConnectionTraceTarget;

      /**
       *  @private
       */
      private function init():void
      {
        target = new TracePanelTarget( txtOutput );
        target.filters=["*"];
        target.level = LogEventLevel.ALL;
        target.includeDate = true;
        target.includeCategory = true;
        target.includeLevel = true;

        target2 = new LocalConnectionTraceTarget();
        target2.filters=["*"];
        target2.level = LogEventLevel.ALL;

        Log.getLogger( "TracePanel" ).debug( "initialization" );
      }

      /**
       *  @private
       */
      private function close():void
      {
        isOpen = false;
        PopUpManager.removePopUp( this );
      }

      /**
       *  @private
       */
      private function changeTarget():void
      {
        if( !chkFlag.selected ) {
          Log.addTarget( target );
          Log.getLogger( "TracePanel" ).info( "Turned logging on!" );
        } else {
          Log.getLogger( "TracePanel" ).info( "Turning logging off!" );
          Log.removeTarget( target );
        }
      }

      /**
       *  @private
       */
      private function changeFlex2Target():void
      {
        if( !chkFlex2TracePanel.selected ) {
          Log.addTarget( target2 );
          Log.getLogger( "TracePanel" ).info( "Turned logging on!" );
        } else {
          Log.getLogger( "TracePanel" ).info( "Turning logging off!" );
          Log.removeTarget( target2 );
        }
      }

      /**
       *  @private
       */
      private function filterTarget():void
      {
        Log.getLogger( "TracePanel" ).info( "Filter change!" );
        Log.removeTarget( target );
        Log.removeTarget( target2 );
        target.filters = idFilter.text.split( "," );
        if( target.filters == null )
          target.filters = ["*"];
        target2.filters = idFilter.text.split( "," );
        if( target2.filters == null )
          target2.filters = ["*"];
        Log.addTarget( target );
        Log.addTarget( target2 );
      }

    ]]>
  </mx:Script>

  <mx:Form>
    <mx:FormItem label="Filter Categories:">
      <mx:TextInput
        id="idFilter"
        text="*"
        change="filterTarget()" />
    </mx:FormItem>
    <mx:FormItem label="Turn Local Logging Off:">
      <mx:CheckBox
        id="chkFlag"
        selected="false"
        change="changeTarget()" />
    </mx:FormItem>
    <mx:FormItem label="Turn Flex2 Trace Panel Logging Off:">
      <mx:CheckBox
        id="chkFlex2TracePanel"
        selected="false"
        change="changeFlex2Target()" />
    </mx:FormItem>
  </mx:Form>
  <mx:HBox
      width="100%"
      horizontalAlign="center">
    <mx:Button
      label="Clear Output"
      click="txtOutput.text = ''" />
  </mx:HBox>
  <mx:Label
    text="Output Console" />
  <mx:TextArea
    id="txtOutput"
    updateComplete="txtOutput.verticalScrollPosition =
txtOutput.maxVerticalScrollPosition + 1;"
    width="100%" height="100%" />
</mx:TitleWindow>
Image from book
Tip

The best way to find examples of ASDoc comment syntax and usage is to look at the Flex Framework source files.

To go beyond just basic documentation creation, ASDoc provides a list of optional command-line arguments. These options provide functionality to customize the documentation and metadata. To obtain a list of available options, enter the following at the command prompt:

asdoc –help –list or asdoc –help –advanced


Building Modular Flex Applications

The needs to break up large application code and reuse code across many applications are key factors that led Adobe to spend the time providing classes that help make creating modular applications very easy. Splitting up an application into separate modular SWFs that can be loaded and unloaded by an application is similar to Runtime Shared Libraries (RSLs). The difference is that RSLs are statically linked at compile time, and module SWFs are loaded at run-time. This allows for smaller initial download sizes and short load times for applications. There is a slight overhead incurred by breaking up the SWFs and loading them separately, but the total size of all the modules compared to a single SWF application is a nominal increase of size.

The new classes provided in the mx.modules package make everything happen. Each module SWF is required to extend the mx.modules.ModuleBase class, typically done by creating a new MXML file with a root tag of <mx:Module>. The following example shows a application loading and unloading modules with the help of a button. Listing A-7 is the main application, and Listing A-8, Listing A-9, and Listing A-10 are the three modules called RuntimeCSSModule, DateWidget, and PowWidget. The first two modules are loaded when the application is first loaded. After the application is loaded, the user proceeds to click the button. Each button click event calls a method that switches between loading/unloading the RuntimeCSSModule and DateWidget and loading/unloading the PowWidget.

Listing A-7: ModularApplicationMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
 <mx:Script>
         <![CDATA[
                import mx.modules.ModuleManager;

                private var flag:Boolean = true;
                private var dynamicModule:ModuleLoader;

                private function changeWidgets():void
                {
                        if( flag ) {
                               if( dynamicModule == null ) {
                                       dynamicModule = new ModuleLoader();
                                       dynamicModule.url = "PowWidget.swf";
                                       this.addChild( dynamicModule );
                               }
                               mlRuntimeCSS.unloadModule();
                               mlDateWidget2.unloadModule();

                               dynamicModule.loadModule();
                        } else {
                               mlRuntimeCSS.loadModule();
                               mlDateWidget2.loadModule();

                               dynamicModule.unloadModule();
                        }
                        flag = !flag;
                }
          ]]>
 </mx:Script>
 <mx:Button label="Change Widgets"
          click="changeWidgets()" />
 <mx:ModuleLoader id="mlRuntimeCSS"
          url="RuntimeCSSModule.swf" />
 <mx:ModuleLoader id="mlDateWidget2"
          url="DateWidget.swf" />

</mx:Application>
Image from book
Listing A-8: RuntimeCSSModule.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Module
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="vertical">

  <mx:Script>
    <![CDATA[
         import mx.controls.Alert;

         import mx.styles.StyleManager;
         import mx.events.StyleEvent;

         private var lastCSS:String;
         private function changeCSS( name:String ):void
         {
              // If you do not unload the last style
              // previous style settings will be in effect
              unloadCSS( false );
              var styleEvent:IEventDispatcher =
                   StyleManager.loadStyleDeclarations( name, true );
              lastCSS = name;
              //styleEvent.addEventListener( StyleEvent.ERROR, showError );
              //styleEvent.addEventListener( StyleEvent.COMPLETE, completed );
         }
         private function unloadCSS( updateFlag:Boolean ):void
         {
              if( lastCSS )
                   StyleManager.unloadStyleDeclarations( lastCSS, updateFlag );
         }
         public function completed( event:StyleEvent ):void
         {
              Alert.show( event.type );
         }
   ]]>
 </mx:Script>

 <mx:Panel id="pnlApp" title="Sample Application"
   paddingBottom="10" paddingLeft="10"
   paddingRight="10" paddingTop="10"
   layout="vertical" horizontalAlign="center">
   <mx:Label
     text="Please fill out the form below and click on Login!" />
    <mx:Form>
         <mx:FormItem label="Username:">
              <mx:TextInput id="txtUsername" />
         </mx:FormItem>
         <mx:FormItem label="Password:">
              <mx:TextInput id="txtPassword" displayAsPassword="true" />
         </mx:FormItem>
    </mx:Form>
   <mx:Button id="btnTrace" label="Login" styleName="sLogin" />
 </mx:Panel>
 <mx:HBox
      horizontalAlign="center"
      width="100%">
 <mx:Button id="btnUnload" cornerRadius="0"
   click="unloadCSS( true )"
   label="one"
   fillColors="[#7C929D,#CCCCCC]" />
 <mx:Button id="btnBlue" cornerRadius="0"
     click="changeCSS( 'blueCSS.swf' )"
     label="two"
     fillColors="[#336699,#5588BB]" />
 <mx:Button id="btnRed" cornerRadius="0"
   click="changeCSS( 'redCSS.swf' )"
   label="three"
   fillColors="[#993333,#BB5555]" />
 </mx:HBox></mx:Module>
Image from book
Listing A-9: DateWidget.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Module
     xmlns:mx="http://www.adobe.com/2006/mxml"
     backgroundColor="#CCCCCC"
     backgroundAlpha="0.5"
     paddingBottom="15"
     paddingTop="15"
     paddingLeft="15"
     paddingRight="15"
     layout="vertical">
     <mx:Label text="Select A Date:" />
     <mx:DateField id="myDate" />
     <mx:TextInput text="{ myDate.selectedDate.toDateString() }" />
</mx:Module>
Image from book
Listing A-10: PowWidget.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Module
     xmlns:mx="http://www.adobe.com/2006/mxml"
     backgroundColor="#EEEEEE"
     borderStyle="solid"
     borderThickness="3"
     layout="vertical">

     <mx:Form>
     <mx:Script>
            <![CDATA[
                 private function getValue( base:String, exp:String ):String
                 {
                      if( Number( base ) > 1 && Number( exp ) > 1 )
                           return Math.pow( Number( base ), Number( exp )
).toString();
                      else
                           return "invalid value";
                  }
            ]]>
     </mx:Script>
     <mx:FormItem label="Base:">
          <mx:TextInput id="txtBase" />
     </mx:FormItem>
     <mx:FormItem label="Exponent:">
          <mx:TextInput id="txtExp" />
     </mx:FormItem>
     <mx:FormItem label="Value:" fontWeight="bold">
          <mx:TextInput id="txtValue"
               text="{ getValue( txtBase.text, txtExp.text ) }"/>
    </mx:FormItem>
  </mx:Form>
</mx:Module>
Image from book

Listing A-8 is a modified RuntimeCSSMain.mxml file from the example code earlier in the appendix. This is to demonstrate how easy it is to take an existing application and modify it to work as a module. The only changes needed are making the root tag <mx:Module> and adding horizontalAlign="center" to the HBox.

Running the ModularApplicationMain.mxml should produce the applications shown in Figure A-4 and Figure A-5.

Image from book
Figure A-4: Application with the RuntimeCSSModule and DateWidget modules loaded
Image from book
Figure A-5: Application with the PowWidget module loaded

The example shows the basics of constructing a modular application. The ModuleLoader class also provides events and methods that help with loading and unloading modules. The ModuleLoader supports the following module events: loading, urlChanged, setup, ready, error, progress, and unload. To load a module with ModuleLoader class, all you need to do is set the url property and unload the module calling the unloadModule() method, as shown in the changeWidgets method of Listing A-7. The code in Listing A-11 shows a modified ModularApplicationMain application that sends all events to a single method that outputs trace statements. The trace statements contain information about the control that sent the event and the type of the event itself.

Listing A-11: Modifed ModularApplicationMain.mxml
Image from book

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
  <mx:Script>
    <![CDATA[
      import mx.events.FlexEvent;
      import mx.events.ModuleEvent;
      import mx.modules.ModuleManager;

      private var flag:Boolean = true;
      private var dynamicModule:ModuleLoader;

      private function changeWidgets():void
      {
        if( flag ) {
          if( dynamicModule == null ) {
            dynamicModule = new ModuleLoader();
            dynamicModule.url = "PowWidget.swf";
            dynamicModule.addEventListener( FlexEvent.LOADING, eventHandler );
            dynamicModule.addEventListener( ModuleEvent.PROGRESS, eventHandler );
            dynamicModule.addEventListener( ModuleEvent.READY, eventHandler );
            dynamicModule.addEventListener( ModuleEvent.SETUP, eventHandler );
            dynamicModule.addEventListener( ModuleEvent.UNLOAD, eventHandler );
            this.addChild( dynamicModule );
          }
          mlRuntimeCSS.unloadModule();
          mlDateWidget2.unloadModule();
          dynamicModule.loadModule();
        } else {
          mlRuntimeCSS.loadModule();
          mlDateWidget2.loadModule();
          dynamicModule.unloadModule();
        }

        flag = !flag;
      }

      private function eventHandler( event:Event ):void
      {
        trace( "Control: " + event.currentTarget + " type: " + event.type );
      }
    ]]>
  </mx:Script>
  <mx:Button label="Change Widgets"
    click="changeWidgets()" />
  <mx:ModuleLoader id="mlRuntimeCSS"
    url="RuntimeCSSModule.swf"
    loading="eventHandler( event )"
    progress="eventHandler( event )"
    ready="eventHandler( event )"
    setup="eventHandler( event )"
    unload="eventHandler( event )" />
  <mx:ModuleLoader id="mlDateWidget2"
    url="DateWidget.swf"
    loading="eventHandler( event )"
    progress="eventHandler( event )"
    ready="eventHandler( event )"
    setup="eventHandler( event )"
    unload="eventHandler( event )" />
</mx:Application>
Image from book

The modified application is required to be run in connection with a debug Flash Player. Watching the trace statements in the output console as the modules are loaded and unloaded will give you a good visual of how the events ready, setup, and progress relate to each other.


Summary

The first update since Flex 2’s big release has a lot of code fixes, as well has feature upgrades. The need to address load times and the initial user experience are major issues. The new features in Flex 2.0.1 provide developers the tools to approach problems with more options than ever before. This appendix examined three key Flex 2.0.1 features: run-time CSS support, the ASDoc tool, and creating modular applications.


Index

A

absolute positioning, 12 2
accessibility, 18 9
component, 189
built-in, 189
customizing, 189–190
enabling, 189
accessible option, 49 4
accordion container, 62, 449, 48 1
history management in, 177
accordion headers, 6 2
acknowledge event, 26 9
action effects, 170.
See also specific action effects
transitions and, 170
Action Message Format (AMF), 7, 34, 65, 24 7
security, 433
ActionScript 2.0 Migration page, 36 6
ActionScript 3.0, 27–30, 75–84, 363–38 7
adapter, 277
applications, 373
display list object instantiation tree, 375
Flex Builder applications v., 373, 374
object hierarchy in, 375
running, 373–374
classes, 367
Flash Player, 366, 367–371
Flex Framework, 367, 371
code, 363
considerations, 372
collection in, 109–110
compatibility with previous versions, 366–367
components, 305–318
advanced, 315–318
creation, 313–314, 315–318
development, 79–80
elements, 305–312
method invocation, 77
properties, 307–309
simple, 313–315
types, 80
visual, 77–78
control access in, 75–77
error handling, 408–415
Flex 2.0 v., 367
garbage collector, 551
JavaScript garbage collector and, 551
history, 363–364
Flash Player 9 and, 363–364
introspection in, 81–84
JavaScript v., 364
language foundation, 371
for Flash Player, 371
for Flex Framework, 371
Language Reference documentation, 374
libraries, 248, 561–571
methods, 377–381
MXML separation from, 78–79
new features in, 364–366
programming, 363–387
date types and classes in, 389–426
Project, 44, 45
validation with, 207–208
ActionScript Messaging adapter, 58 7
ActionScript to CFC wizard, 60 5
ActionScript Virtual Machine (AVM), 363, 62 2
AVM1, 622
AVM1/AVM2 SWF communication, 622
ExternalInterface and, 622–625
AVM2, 364
compatibility issues, 366–367, 622
ActionScript-to-Java conversion, 250–25 2
ActionScript-to-SOAP types, 25 4
activate phase, 480
Active Record CFC, 60 4
adapters, 268.
See also specific adapters
FMS and, 268, 277
message, 268
addChild ( ) method, 77, 78, 37 7
AddChildAction, 170
addChildAt ( ) method, 77, 37 7
addCommand ( ) method, 54 4
addEventListener ( ) method, 8 6
addItem ( ) method, 40 6
addObject method, 180
addtoCreationQueue method, 45 7
AddtoCreationQueueExample.mxml, 457–45 8
Adobe Flash Player 9. See Flash Player 9
Adobe Flex 2.0. See Flex 2.0
Adobe Labs, 56 1
ActionScript 3.0 libraries on, 561
resources, 561
Advanced ActionScript 3 with Design Patterns (Lott, Patterson &), 43 6
AdvancedMonths component, 294, 29 5
AdvancedMonths.mxml, 293–29 4
Ajax, 4.
See also Flex-Ajax Bridge
all logging level, 260
AMF. See Action Message Format
AMF0 protocol, 24 7
AMFPHP, 247, 57 4
Apache Ant, 44 1
Apollo. See Engagement Platform technology, Adobe
appendChild ( ) method, 42 1
application deployment, 47 9
definition, 479
Flex, 435–436, 479–527
methodologies, 479
application(s), Flex, 429–460
building, 435–436
Cairngorm Framework and, 565
code for reusability, 435
deployment environment planning and, 436
design pattern and, 435–436
directory structure determination for, 436
YouTube library and, 565–571
compiling, 439–442
debugging, 461–478.
See also debugging.
deferred component creation and, 453–455
deferred creation and, 449–451
deployment, 435–436, 479–527
compiling for, 493–497
considerations, 479–481
FDS2 on Tomcat, 500–508
Flex 2 SDK, RSL and, 488–493
options, 485
problems, 497–500
RSL, 485–487
run-time data access and, 498
server-side/client-side caching, 481–485
troubleshooting tips, 497–500
wrappers and, 508–526
directory structure, 429–432
proxy server and, 498–499
rich media integration and, 613
building, 613–617
inner workings of, 617–620
security, 432, 445–447
Flash Player and, 432–433
network, 432–433
open Web technology and, 433
startup order, 447–449
startup performance, 447
improvement of, 447–460
SWC files in, 562–564
ActionScript libraries and, 562–564
application frameworks, 53 2
Application type selector, 133–13 4
Application.application property, 7 7
applicationComplete, 44 7
ApplicationController.as, 54 4
mx:Application tag, 540
applications. See specific applications
architectural frameworks, 53 2
area charts, 31, 21 5
high-low areas, 215
overlaid, 215
sample code, 215
stacked, 215
AreaChart component, 21 5
AreaSeries, 21 5
array(s), 399–40 8
adding/removing items from, 400–401
associative, 399, 403–407
constructing, 403–405
sorting keys/values in, 405–407
cloning, 408
filtering, 402, 403
indexed, 399–403
creating, 399
multidimensional, 399, 407
sorting/finding items of, 401–402
Array class, 106, 107, 10 8
complex data type, 390
ArrayCollection class, 10 6
ArrayCollection data type, 57 8
[ArrayElementType] metadata tag, 32 1
AS3 Corelib, by Adobe, 43 3
assets, 17 5
embedding, 175–177
Library Build Path with, 334
associative arrays, 399, 403–40 7
constructing, 403–405
sorting keys/values in, 405–407
User class and, 404
asterisk symbol, 343, 34 4
AsyncMessage object, 269, 270, 27 1
Atom and RSS libraries, 56 2
attribute identifier (@) operator, 420, 42 3
Auto Update, Flash Player, 52 1
Express Install v., 521
automatic positioning, 12 2
AVM. See ActionScript Virtual Machine
AVM2. See ActionScript Virtual Machine
AVM2.mxml, 62 4
axis labels, 230–23 1
column chart with, 230
sample code, 229–230
axis properties, 231.
See also specific properties
axis renderers, 230–23 1
sample code, 230–231
axis rotation, 239–240
candlestick chart and, 239, 240
sample code, 239, 240
axis title, 230
sample code, 230
axis types, 231–23 2


Previous Page
Next Page

Index

B

backgroundImage, 142
backreference group, 41 7
bar charts, 31, 216–21 8
clustered, 217
high-low area, 216
overlaid, 216
sample code, 216–217
stacked, 217, 218
BarChart component, 21 6
BarSeries, 21 6
batch-write-size property, 27 7
Bates, Bert, 43 6
Bean CFC, 60 4
behaviors, 72, 103, 12 7
applying, 127
creation, 103
using, 128–131
benchmark option, 49 4
BI systems. See business intelligence systems
[Bindable] metadata tag, 192–193, 321–32 3
binding, 53 7
to component properties, 193–194
data, 64–65, 191–199
simple, 322
data model to custom component, 196–198
external XML file and, 195–196
one-way, 191
to variables, 192–193
mx:Binding tag, 191–19 2
BindWithGettersandSetters.mxml, 322–32 3
Birthdate component, 29 7
BirthdateMain.mxml, 29 6
Birthdate.mxml, 295–29 6
interface and, 302
Bitmap class, Flash, 37 6
code example, 381–382
BitmapData, 61 2
Blue Diamond, 2 1
body, 33, 267.
See also message(s)
bookmarks, 5 7
Boolean data type, 390
Border class, 14 2
borderMetrics, 14 2
brackets ([]) operator, 420, 42 3
breakpoints, 19, 20, 47 5
stepping and, 475
Breakpoints view, 22, 42, 472, 473, 47 4
bridgeName, 550, 551, 554, 55 5
bubble charts, 31, 218–21 9
sample code, 218–219
BubbleChart component, 21 8
bubbling phase, 85, 89–90
build tools, 44 1
Business Delegate, 546–54 7
business intelligence (BI) systems, 8
busy cursor, 15 8
Button class, 30 6
Button control, 63, 80, 12 4
downSkin and, 104
overSkin and, 104
upSkin and, 104
ButtonBar control, 10 7
ButtonLabel.as, 32 5
ByteArray class, Flash, 366, 40 8


Previous Page
Next Page

Index

C

C icon, 22
caching
client-side, 481
deployment and, 481–485
DMS item, 286
server-side, 481
deployment and, 481–485
Cairngorm Committee, 54 7
Cairngorm Event Dispatcher, 543, 544–54 5
Cairngorm Framework, 531–54 7
articles on, 531, 532
design patterns, 541–547.
See also specific design patterns.
Flex application and, 565
YouTube library in, 565–571
RIAs and, 531
RPCs and, 545
support for, 547
version 2.1, 531
view and, 537
Weather application and, 533–547
CairngormEvent class, 54 3
Calendar class, 39 3
date manipulation, 393–395
calendar dates/time values, 39 1
callbacks, 18 3
callLater ( ) method, 458–45 9
CallLaterExample.mxml, 459–460
Camera class, 61 2
camera, Web, 61 2
candlestick charts, 31, 226–22 7
axis rotation and, 239, 240
close value, 226
fill, 226
high value, 226
low value, 226
open value, 226
sample code, 226–227
CandlestickSeries, 226–22 7
Canvas container, 80
capturing phase, 84, 88–8 9
CartesianChart class, 23 6
Cascading Style Sheets (CSS), 69–70
component styling with, 101–103, 132
case type, of strings, 39 9
CategoryAxis, 229, 23 1
categoryField property, axis, 23 1
cell editing process, 14 7
events in, 149–150
prevention of, 151–152
CFC to ActionScript wizard, 60 5
CFCs. See ColdFusion components
CFML. See ColdFusion Markup Language
Channel objects, 249, 250
channels, 249, 269, 27 5
message, 249–250, 268, 269
ChannelSet objects, 249, 250
Charles by xk72, 433, 58 3
charting, Flex, 8, 213–24 3
advanced features, 232–244
classes, 229–232.
See also specific classes.
components, 31–32
effects, 240–241
examples, 213–229, 241–244
styling, 232–244
types, 31–32
ChartItem, 23 2
ChartItemEvent, 23 2
charts, Flex.
See also specific charts
events, 232–234
sample code, 233–234
examples, 213–229, 241–244
legend, 232
mx.charts, 3 1
CircleLabel component, 314, 31 5
class mappings, 281–28 3
distributed data and, 281–283
class name, 30 6
class selector, 69, 70, 13 3
classes. See specific classes
CLI. See Common Language Infrastructure
client-side-detection template, 50 8
client-side-detection-with-history template, 50 9
cloning arrays, 40 8
cluster element, 28 5
clustering. See software clustering
C#.NET language, 621, 62 6
C#.NET Windows application
LocalConnection and, 627–641
steps to create, 631
co-browsing applications, 7
code
assistance, 57
folding, 57
hints, 57, 328
Design view and, 329
managed, 627
unmanaged, 627
ColdFusion 7.0.2, 247, 267, 57 3
configuring, 591–593
extension package, 597–606, 606
extensions for Flex Builder 2 and, 597–606
Flex 2 and, 573–606
Flex Messaging Event Gateways and, 583–587
structure of messages in, 585–587
Flex Messaging event gateways and, 583
ColdFusion Components (CFCs), 575.
See also specific CFCs
ColdFusion Event Gateway adapter, 267, 27 7
using, 587–591
ColdFusion Markup Language (CFML), 57 6
collection(s), 106, 109–11 1
in ActionScript, 109–110
change events, 115–117
features of, 109
filtering, 113–114
interfaces, 111–115
in MXML, 109
sorting, 112–113
CollectionEvent class, 11 5
mx.collections, 30
ColorPicker control, 10 7
column charts, 31, 220–22 1
axis labels, 230
clustered, 220, 221
gradient fill, 241–244
code for, 241–243
high-low, 220
mixed series chart and, 237
overlaid, 220, 221
sample code, 220
stacked, 220
ColumnChart component, 220
setAxisLabel function and, 230
COM interoperability. See Component Object Model interoperability
ComboBox control, 63, 80, 106, 124, 290
command class, 54 1
command pattern, 54 1
command-line debugger, 47 5–478.
See also debugging
Commitment pass, 120
Common Language Infrastructure (CLI), 62 7
communication
Flex/JavaScript, 183–187
with wrapper HTML page, 183–187
comparison operators, 39 6
compc compiler, 33 2
compc.exe, 430
compilation
of Flex applications
deployment phase, 493–497
testing phase, 439–442
compilers, 444, 48 6
compc, 332
deployment options, 494
Flex Builder project, 493
configuration options, 509
MXMLC command-line, 493, 511–512
property settings, 486
types, 493
Web-tier, 493
CompileTest.mxml, 440, 44 1
compile-time errors, ActionScript, 408–410
SortedMap class and, 409, 410
component(s).
See also specific components
accessibility, 189
customizing, 189–190
ActionScript, 305–318
advanced, 315–318
creation, 313–314, 315–318
development, 79–80
elements, 305–312
method invocation, 77
properties, 307–309
simple, 313–315
types, 80
visual, 77–78
compiling, 332–340
Flex Builder and, 332–338
Flex SDK and, 332
composite, 293, 295
MXML, 295–297
custom, 106, 163
binding data model to, 196–198
deploying, 338–340
events in, 319–321
extending, 105–106
Flex, 319–340
properties, 305–318
history management, 177
added, 177
built-in, 177
instantiation, 99–101
as item renderer, 146–147
layout, 120–121, 122–123
manual forcing, 123
rules, 122–123
life cycle, 101
events in, 101
metadata tags in, 321–331
method invocation, 77
modification, at run-time, 104–105
panel, 15
positioning, 120, 122–123
printing, 180, 181
properties, 193
binding to, 193–194
sizing, 97–98, 120, 121–124
styling, 101–103, 132
template, 297
creation, 297–298
MXML, 297–301
view, 15, 42
Component Object Model (COM) interoperability, 62 7
composite components, 293, 29 5
MXML, 295–297
concat ( ) method, 397, 40 8
concatenation, 39 7
Console view, 21, 4 2
constraint-based layout, 98, 121, 123–12 4
consumers, 33, 248, 267, 26 9
components, 272
creation, 272–273
selector property, 273, 274
Contact.xml file, 195, 19 6
containers, 61.
See also specific containers
drag-and-drop support for, 172–175
multi-view, 449
contributor option, 49 4
controls, 61, 124.
See also specific controls
basic, 124
characteristics, 124
data provider-based, 124
mx.controls, 30, 30 6
convenience variables, 47 6
copying arrays. See cloning arrays
Corelib library, 56 2
Create CFC wizard, 604–60 5
CFC data access styles, 604
Create, Manage, and Run Configurations dialog box, 51, 5 2
createComponentFromDescriptor, 454–45 5
CreateComponent.html, 556–55 8
createComponentsFromDescriptors, 452–45 3
createCursor ( ) method, 11 4
creation queuing, 45 5
creationComplete event, 101, 44 9
creationIndex property, 45 6
CreationIndexExample.mxml, 456–45 7
creationPolicy property, 45 1
working with, 451–452
CreationPolicyExample.mxml, 449–45 1
creator option, 49 4
credentials, 25 9
CreditcardValidator component, 67, 6 8
cross-domain, sandboxes and, 487, 49 9
crossdomain.xml file, 263, 48 7
cryptographic algorithms, 43 3
CSS. See Cascading Style Sheets
currentTarget property, 8 7
target property v., 88
cursor(s), 15 7
adding/removing, 157–158
busy, 158
Cursor Manager, 15 7
custom effects, 34 9–359.
See also effect(s)
custom error classes, 411–41 4
custom exception classes, 41 3
SortedMap class with, 413–414
custom formatters, 34 1–346.
See also formatter(s)
application running, 346
example, 345–346
reverse text, 345
custom loggers, 463, 464, 465–471, 62 7
custom tracing utility, 62 6
building, 626–627
custom validators, 200, 34 7–349.
See also validator(s)
CustomCircle.as, 330–33 1
customDate.parse, 39 1
CustomEffectApp.mxml, 35 2
CustomEffect.as, 350–35 1
CustomEffectInstance.as, 35 1
CustomLoggerMain.mxml, 46 5
modified, 470–471
results, 471
results, 469
CustomTweenEffect application results, 35 6
CustomTweenEffectapp.mxml, 356–35 7
CustomTweenEffect.as, 354–35 5
CustomTweenEffectInstance.as, 355–35 6


Previous Page
Next Page

Index

D

D icon, 22
DAO. See Data Access Object
DAO CFC, 60 4
DAO.cfc, 596–59 7
data, 19 1–211.
See also message(s) ;
XML , external data
access, 245–286
binding, 64–65, 191–199
descriptors, 117
distributed. See distributed data.
flat, 108
formatting, 68–69, 208–211
grid, 180
printing, 180, 182–183
models, 194–195
custom component bound by, 196–198
data bound to, 198–199
validation of, 201–203
paging, 33
push, 7, 34, 246, 286
serialization, 250–257.
See also serialization.
storage, 187
shared objects and, 187–188
synchronization. See synchronization, data.
validation, 67–68, 200–208, 446
errorString and, 203–204
simple, 203–204
Data Access Object (DAO), 59 5
.cfc, 596–597
Data Management Service, 32, 245–246, 247, 278–28 6
configuration, 284
destination, 284–286
file, 248
network-related properties, 285
data flow, 279
data push from servers to client, 286
distributed data, 280
application, 280–281
class mappings and, 281–283
item caching, 286
RPC v., 278–279, 591
transactions, 285–286
data providers, 106–109, 14 3
hierarchical, 108–109, 117–119
linear (listed-based), 108
List-based controls and, 106–107
remote, 119–120
XML, 117–119
Data Services. See Flex Data Services
data types, 38 9–390.
See also specific data types
and classes, 389–426
complex, 389, 390
primitive, 365, 389, 390
DataField control, 10 7
DataGrid control, 10 6
data-management-config.xml, 24 8
DataModel.as, 568–56 9
dataProvider property, axis, 23 1
DataService component, 591, 592, 59 3
Date class, 39 1
calendar dates/time values, 391
date values, 393
Calendar class and, 393–395
creation of, 391–392
display methods, 392
manipulation, 393–395
time values, 392
unit retrieval, 392–393
Date complex data type, 390
date option, 49 4
date values, 39 3
Calendar class and, 393–395
creation of, 391–392
display methods, 392
manipulation, 393–395
DateFormatter component, 68, 69, 80, 20 9
DateTimeAxis, 229, 23 2
deactivate phase, 480
Debug icon, 441, 44 2
debug option, 49 4
debugging, 461–47 8
command-line, 475–478
commands for, 477–478
configuring, 476
invoking, 475–476
fdb, 475–478
Flash Debug Player and, 462–463
Flex Builder tools, 22, 23, 471–475
logging level, 260
view configuration, 42
Debugging perspective, 19, 20, 41, 471, 472–47 5
breakpoints, 19, 20, 475
stepping and, 475
Breakpoints view, 22, 42, 472, 473, 474
configuring, 472–474
Console view, 21, 42
Debug view, 472, 475
Expressions view, 22, 23, 42, 472, 474
Flex Builder 2 and, 19–23, 36
invoking, 472
Variables view, 21–22, 42, 472, 473, 474
deep copy, 40 8
default constructor, 306–30 7
default sizing, 97, 121–12 2
[DefaultProperty] metadata tag, 32 4
default-script-limits option, 49 4
deferred component creation, 453–45 5
deferred creation, 449–45 1
DeferringComponents_2.mxml, 454–45 5
DeferringComponents.mxml, 45 3
delay time(s), 15 6
for tooltips, 156
delete operator, 404, 42 3
deployment, 479.
See also application(s), Flex , deployment
application, 479
definition, 479
directory structures, 7, 442
basic customized, 443
Eclipse Flex Builder 2 Plugin, 443
Flex Builder 2 and, 443
FDS2, 500–508
configuration, 506–508
integrated Web-compiling environment, 439
precompile environment, 438
Tomcat and, 500–506
Flex 2 SDK, 488–493
components, 339, 340
environment, 437
Flex application, 435–436, 479–527
Flex Builder 2.0, 443–445
components, 339
methodologies, 479
SWC files, 338
Flex Builder and, 340
Flex SDK and, 340
descendant accessor (..) operator, 420, 42 3
describeType ( ) method, 82–8 3
description option, 49 4
design editor, 3 5
Design mode, 15–19, 4 1
developing with, 54–58
Properties view, 15–19, 42
design patterns, 435–43 6
books for, 436
Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides &), 43 6
Design view, code hints and, 32 9
destinations, 33, 258, 269, 53 7
configuration, 265–266
Data Management Service configuration, 284–286
FMS, 275
configuration, 275–277
network properties, 276
service-related properties, 276–277
message, 268
properties, 266–267
security and, 258–259
subscribe to, 273
Detection Kit, 48 1
“Developing Flex RIAs with Cairngorm Micro-Architecture,” 531–532
Development perspective, 14–19, 4 1
Design mode, 15–19, 41
developing with, 54–58
Source mode, 14–15, 41
Outline view, 14, 15, 41
development view configuration, 41–4 2
device fonts, 134–13 5
Dictionary class, Flex Framework, 403, 404, 40 5
directory structures
deployment, 442
basic customized, 443
Eclipse Flex Builder 2 Plugin, 443
Flex Builder 2 and, 443
FDS2, 439
Flex application, 429–432
determining, 436
installation
Eclipse Flex Builder 2 Plugin, 431
FDS2, 431–432
Flex 2 SDK, 430
Flex Builder, 431
Tomcat, 502
dispatchEvent ( ) method, 86, 320
display classes, 38 1
core, 381
code examples, 381–387
display container, 37 5
display list, 37 5
advantages, 375–376
API, 365
manipulation, 377
object instantiation tree, 375
objects, 365
display objects, 37 4
finding, 379
working with, 376–381
display programming, 374–38 7
displayName property, axis, 23 1
DisplayObject class
Flash, 75
appearance/spatial properties, 377–379
event handling, 380–381
functionality, 376–380
as UI components base, 376
Flex, 78, 85, 142
class hierarchy and, 96
DisplayObjectContainer class
Flash, 375
appearance/spatial properties, 377–379
display list manipulation, 377
event handling, 380–381
functionality, 376–381
Flex, 96
class hierarchy and, 96
Dissolve effect, 12 9
distributed data
class mappings and, 281–283
data synchronization and, 283–284
Document Object Model (DOM), 36 4
Level 3 event model, 365
Document Type Definition (DTD), 51 4
doDrag ( ) method, 17 2
doLater ( ) method, 458.
See also callLater ( ) method
DOM. See Document Object Model
dot (.) operator, 420, 42 3
doubleClickEnabled property, 9 6
doValidation method, 34 7
downSkin style property, 70
Button control with, 104, 140–141
drag-and-drop operation, 171–17 5
containers and, 172–175
custom, 173–174
list controls and, 171–172
dragComplete event, 17 5
dragDrop event, 17 5
dragEnter event, 17 5
DragEvent class, 17 3
dragExit event, 17 5
DragManager class, 171, 17 2
dragOver event, 17 5
DragSource class, 17 3
DrawCircles.as file, 47, 4 8
DrawShapes class, Flash, 37 3
DrawShapes.as, 373, 37 4
drill-down charts, 234–23 6
pie chart and, 236
sample code, 234–235
DropDownEvent class, 8 5
drop-in method, 144–14 5
DTD. See Document Type Definition
Durable property, 27 7
durable-store-manager property, 27 7
dynamic linking, 49 2
dynamic-url, 26 7


Previous Page
Next Page

Index

E

E4X, 365 , 420.
See also XML
classes, 420–426
introduction, 420
XML creating/destroying with, 420–423
XML namespaces and, 425–426
XML navigating with, 423–425
XML type conversion and, 426
easing functions, 130–13 1
Eclipse, 6
Flex Builder 2 and, 9, 10, 36
Navigator panel, 442
RDS support plugin, 597–603
Eclipse Flex Builder 2 Plugin, 10, 3 6
compiling with, 441–442
deployment directory structure, 443
installation directory structure, 431
ECMAScript Edition 4 , 364, 420
standards, 365
editable cell, 14 7
editable property, 14 7
editedItemRenderer property, 150
editor, 40
Editor panel, 1 5
Editor view, 15, 4 1
debugging, 42
source/design, 41
editorDataField property, 14 8
editorHeightOffset, 14 8
editorWidthOffset, 14 9
editorXOffset, 14 9
editorYOffset, 14 9
effect(s), 72, 103, 127.
See also specific effects
built-in, 349
charting, 240–241
composite, 129–130
creating, 349–359
custom, 349–359
example, 350–352
embedded fonts with, 129
extending, 349
tooltip, 156–157
transitions and, 167
triggers, 357
custom, 357–359
[Effect] metadata tag, 326–327, 35 7
EffectInstance class, 350
extending, 350
EJB. See Enterprise Java Bean
elements.
See also user interface(s) ;
specific elements
UI, 161–190
XML, 418
EmailTextInput component, 31 3
in action, 314
[embed] tag, 324–325, 51 8
attributes, 518
parameters, 518–520
wrappers and, 518–520
embedding, 175–17 7
assets, 175–177
fonts, 129, 134, 176
benefits, 135
downsides, 135–136
effects and, 129
FlashType, 137–140
images, 175
sound files, 176–177
SWF files, 176–177
EmployeeAssembler.cfc, 59 5
example, 595–596
methods of, 595
enabled property
UIComponent, 96
validator, 200
Engagement Platform technology, Adobe, 62 6
Enterprise Java Bean (EJB), 50 4
equality operators, 39 6
Erickson, Renaun, 24 7
error(s)
ActionScript, 408–415
compile-time, 408–410
complex data type, 390
custom, 411–414
exception handling, 414–415
run-time, 408, 410–411
types of, 408
custom, 262–263
formatter, 210–211, 346
logging level, 260
strings, 211
custom, 211
synchronous, 410
ErrorReportingEnable property, 46 2
errorString, 203–20 4
event(s), 84.
See also specific events
chart, 232–234
class, 85
target property of, 87–88
in components, 319–321
custom, 319–321
dispatching, 319–321
flow (propagation), 84–85, 88–90
bubbling phase, 85, 89–90
capturing phase, 84, 88–89
targeting phase, 85, 89
handling, 84–93, 98–99, 446
Flash DisplayObject class and, 380–381
keyboard, 92–93
listeners, 84, 98
mouse, 85, 93
object, 84, 85
priorities, 90–91
subclassing, 85, 91–92
tooltip, 154–155
usage, 86–87
validation, 204
testing, 204–207
event gateways, 58 3
[Event] metadata tag, 320, 325–326, 35 7
EventDispatcher class, 85–8 6
class hierarchy and, 96
Flash, 377, 380–381
event.preventDefault ( ) method, 15 1
EventSample.mxml, 325–32 6
mx.events, 8 5
every ( ) method, 40 3
exception classes, custom, 41 3
SortedMap class with, 413–414
exception handling, 41 4–415.
See also error(s)
exec ( ) method, 41 7
executables, 430
explicit sizing, 97, 121, 12 2
Express Install, Flash Player, 520–52 1
Auto Update v., 521
FDS2 and configuration of, 525–526
using, 520–521
wrapper editing, and, 521–525
on FDS2, 525–526
express-installation template, 50 9
express-installation-with-history template, 50 9
expressions, regular. See regular expressions
Expressions view, 22, 23, 42, 472, 47 4
Extended Architecture (XA) protocol, 50 4
Extensible Application Markup Language. See XAML
Extensible Markup Language. See XML
External API, 621–62 2
external application integration, 621–64 1
ExternalInterface, 26, 183, 366, 367, 54 9
AVM1/AVM2 SWF communication and, 622
FA Bridge and, 621, 622
LocalConnection v., 625–626
Externalizable interface, 25 5


Previous Page
Next Page

Index

F

FA Bridge. See Flex-Ajax Bridge
Fade effect, 12 9
failover, 26 1
fast views, 5 2
fault event, 269, 27 2
fdb, 475–478.
See also debugging
configuring, 476
debugger commands, 477–478
.exe, 430
invoking, 475–476
session, 477–478
FDS. See Flex Data Services
FDS2. See Flex Data Services
FDS2 Express, 43 7
file-store-root property, 27 7
fill, candlestick chart, 22 6
filter ( ) method, 40 3
filtering
collection(s), 113–114
messages, 273–274
filtering arrays, 402, 40 3
filters, 170
transitions and, 170–171
financial charting components, 226, 228.
See also candlestick charts ;
HighLowOpenClose charts
findAny ( ) method, 11 5
findFirst ( ) method, 11 5
finding display objects, 37 9
finding/sorting array items, 401–40 2
findLast ( ) method, 11 5
Flash authoring tool, 367, 37 4
Flash Debug Player, 462–46 3
locations, 462
properties, 462
Flash Media Server, 61 2
flash packages, 365, 36 7
names, 367, 371
classes with, 367–371
Flash Player 9, 5– 6
ActionScript as language foundation for, 371
API, 364
changes, 364
features, 365–366
Auto Update, 521
Express Install v., 521
classes, 367–379.
See also specific classes.
compatibility issues, 366–367
Detection KIt, 527
Express Install, 521–522
wrapper editing and, 521–526
history/timeline, 6
ActionScript 3.0 and, 363–364
process structure, 626
sandboxes. See sandboxes, Flash Player.
security/technology concerns, 432
Flex and, 432–433
text updates, 366
updating, 526
without Express Install, 526–527
Flash Professional 9 preview, 367, 371, 37 2
download, 367
Flash Remoting, 573, 60 6
monitoring/testing tools for, 583
third-party plugins, 574
Updater, 573–574
using, 573–583
Flash Satay, 514, 51 5
flash.accessibility.*, 36 7
flash.display.*, 367, 36 8
flash.display.Graphics package, 141, 36 8
flash.errors.*, 36 7
flash.events.*, 31, 85, 365, 367, 36 8
flash.external.*, 36 9
flash.filters.*, 36 9
flash.geom.*, 36 9
flash.media.*, 36 9
flash.net.*, 31, 369, 370
flash.printing.*, 36 9
flash.profiler.*, 36 9
flash.system.*, 369, 370
flash.text.*, 370, 37 1
FlashType fonts, 136–140
embedding, 137–140
SWF creation and, 137–138
flash.ui.*, 370, 37 1
flash.utils.*, 370, 37 1
flash.xml.*, 370
flat data, 10 8
Flex 2 Framework, 30–3 1
ActionScript as language foundation for, 371
application directory structure and, 429–432
classes, 371.
See also specific classes.
Dictionary class, 403, 404, 405
packages, 30–31
Flex 2.0
ActionScript 3.0 v., 367
applications. See application(s), Flex.
basics, 25–34
class hierarchy, 95–96
ColdFusion 7.0.2 and, 573–606
earlier versions, 5
event model in, 84–93
features, 5
introduction to, 3–8
JavaScript communication with, 183–187, 549
OpenLaszlo v., 3
programming model, 25
ActionScript, 27–30, 75–84
Flex 2 Framework, 30–31
MXML, 25–26, 61
SDK, 3, 6, 245, 247
building applications for, 436–437
components compiled with, 332
components deployed with, 339, 340
deployment, 488–493
deployment environment, 437
FDS2 v., 437–439
installation directory structure, 430
RPC components with, 247
RSLs and, 332, 339
SWC files and, 332, 340
UI. See user interface(s).
visual components, 54, 95–104
class hierarchy and, 96
Flex Builder 2.0, 6, 9
applications
ActionScript applications v., 373, 374
compiling, 23
multiple, 45–48
running, 24, 50–52
build tools, 36
code editing in, 57–58
ColdFusion extensions for, 597–606
compiling components with, 332–338
compiling with, 441–442
configuration options, 509
Debugging perspective, 19–23, 36.
See also Debugging perspective.
debugging tools, 22, 23, 471–475
deploying components with, 339
deployment, 443–445
directory structure, 443
Development perspective, 14–19
Design mode, 15–19, 41
Source mode, 14–15, 41
Eclipse and, 9, 10, 36
features, 35–36
Help system, 36, 37
Dynamic, 38, 40
library, 37, 38
search scope, 38, 39
installation directory structure, 431
introduction to, 9–24
navigation features, 36
perspectives, 14, 40, 41
plugin version (Eclipse), 10, 36.
See also Eclipse Flex Builder 2 Plugin.
project compiler, 493
project creation, 10–13
automatic/manual, 49
external resources linked in, 49
library in, 13
multiple applications in, 45–48
naming of, 12
storage location in, 11
type of, 11
project types, 44–45
requirements
Mac, 9
Windows, 9
RSLs and, 336–338, 339
shortcuts in, 58
stand-alone version, 10, 36
Start Page, 36, 37
SWC files within, 332–335
using, 35–58
workbench, 40–41, 44
customizing, 52–54
Flex charting. See charting, Flex
Flex components. See component(s)
Flex data. See data
Flex Data Service assembler, 59 1
CFCs, 604
Flex Data Services (FDS2), 7, 32, 24 5
alternatives, 34
building for, 437–439
components, 7–8
configuration, 248–249
files, 248–249
deployment, 500–508
configuration, 506–508
Tomcat and, 500–508
deployment environment
integrated Web-compiling, 439
precompile, 438
directory structure, 439
Express, 437
features, 32
Flash Player Express Install on, 525–526
Flex 2 SDK v., 437–439
RIAs and, 245, 286
RPC components with, 247
Flex Library Project, 44, 45, 48 8
creation, 332–333, 488
naming, 333
Flex Messaging Event Gateways, 58 3
ColdFusion 7.0.2 and, 583–587
structure of messages in, 585–587
Flex projects, 44, 4 5
creation of, 10–13
Flex Weather application. See Weather application, Flex
Flex2TracePanel.as, 632–63 8
code functionality, 632, 638–639
in-code comments, 632
Flex2TracePanel.Designer.cs, 639–64 1
Flex-Ajax (FA) Bridge, 549–55 9
download, 550
examples, 551–555
ExternalInterface and, 621, 622
Flex Component creation, 555–559
JavaScript and, 555–559
Flex Validators and, 551–555
memory consumption issues, 551
requirements for, 550–551
FlexCoders mailing list, 54 7
flex-config.xml, 46 4
FlexDisplayObject interface, 14 2
Flex/JavaScript communication, 183–18 7
FlexMxmlServlet, 48 2
FlexPrintJob, 180
FlexUnit library, 56 2
flex-Webtier-config.xml, 46 4
Flickr library, 56 2
Flickr service, 66, 6 7
FLUORINE, 57 4
FLV stream, 386, 38 7
FMS. See Message Service, Flex
focusIn, 358, 35 9
focusOut, 35 8
font licenses, 13 6
@font-face declaration, 13 9
fonts, 135.
See also specific fonts
embedding, 129, 134, 176
benefits, 135
downsides, 135–136
effects and, 129
FlashType, 137–140
TTF, 176
forEach ( ) method, 40 3
for…in loops, 81–8 2
formatString, 68, 6 9
formatter(s).
See also specific formatters
built-in, 208–209, 341
components, 68–69
custom, 341–346
errors, 210–211, 346
extending, 344
formatting, data, 68–69, 208–21 1
frameworks, 532.
See also Cairngorm Framework ;
Flex 2 Framework
application, 532
architectural, 532
articles on, 532
Freeman, Elisabeth, 43 6
Freeman, Eric, 43 6
Front Controller, 540, 54 3
Weather Application and, 543–544
fscommand ( ) functionality, 62 1
fully integrated environment (IDE), 3 5
Function complex data type, 390
Function objects, 40 2


Previous Page
Next Page

Index

G

Gamma, Eric, 43 6
garbage collectors, 435, 55 1
integration between JavaScript and ActionScript, 551
getBirthdate method, 29 7
getBitmapData method, 61 2
getChildAt ( ) method, 7 6
getChildByName ( ) method, 7 6
getItem ( ) method, 40 6
getLogger ( ) method, 46 3
getStyle ( ) method, 128, 13 3
getters, 308, 30 9
icon, 22
getText ( ) method, 7 6
getTotal method, 30 3
results, 304
GetVideosByTagCommand.as, 56 7
GetVideosByTagEvent.as, 56 8
GetWeatherByLocation.as, 541–54 2
GetWeatherByLocationEvent.as, 54 3
global security constraint, 25 8
global type selector, 13 4
GlowingTextInput.as, 357–35 8
glowOffEffect, 35 7
glowOnEffect, 35 7
Google Code, 433
gradient fill, 241–24 4
column chart and, 241–244
sample code for, 241–243
graphical skins, 71, 104, 140–14 1
graphical user interfaces (GUIs), 53 2
Green Circle, 2 1
Grid container, 6 1
grid data, 180
printing, 180, 182–183
grid lines, 23 1
sample code, 231
groups, 417–418.
See also specific groups
regular expressions and, 417–418
using, 417–418
GUIs. See graphical user interfaces


Previous Page
Next Page

Index

H

hasEventListener ( ) method, 86
HashMap, 26 2
HBox container, 61, 80
Head First Design Patterns (Freeman, Bates, Sierra &), 43 6
headers, 33, 267.
See also message(s)
property, 271
headless server, 494, 49 5
height property, 96, 10 5
Helm, Richard, 43 6
hideDelay property, 15 6
hideEffect property, 15 6
HighLowOpenClose (HLOC) charts, 32, 228–22 9
sample code, 228–229
ticks, 228
history management, 177–180
Accordion, 177
components and adding, 177
components with built-in, 177
TabNavigator, 177
ToggleButtonBar, 177–178
History Manager, 48 1
disable, 481
HitData, 23 2
HLOC charts. See HighLowOpenClose charts
HorizontalList control, 10 7
HTML wrapper preferences, 44 4
HTTP service properties, 26 7
HTTPService component, 7, 65, 80
defining, 263–264
Flickr service and, 66, 67
YouTube and, 119–120


Previous Page
Next Page

Index

I

ICollectionView interface, 111, 112–11 4
filtering collections in, 113–114
sorting collections in, 112–113
ICommand interface, 54 2
[IconFile] metadata tag, 32 7
Icons
C, 22
D, 22
Getter, 22
S, 22
id property, 9 6
IDE. See fully integrated environment
IExternalizable interface, 25 5
IL. See Intermediate Language
IList interface, 11 1
IllegalOperationError, 41 1
images, 17 5
embedded, 175
import statements, 30 6
IMXMLObject, 303–30 4
incremental option, 49 4
indexed arrays, 399–40 3
creating, 399
Index.mxml, 29 1
indexOf ( ) method, 397, 40 2
info logging level, 260
sample code, 260–261
initialize event, 10 1
inline method, 144, 145–14 6
insert ( ) method, 11 5
[Inspectable] metadata tag, 327–32 8
install phase, 480
[InstanceType] metadata tag, 32 8
int data type, 365, 390
InteractiveObject class, class hierarchy and, 9 6
interfaces, 302.
See also specific interfaces
Intermediate Language (IL), 62 7
introspection API, 82–8 4
introspection, in ActionScript, 81–8 4
Invalidating interface, 14 2
invoke ( ) method, 277, 27 8
IResponder interface, 54 2
item caching, Data Management Service, 28 6
item editor(s), 14 7
benefits, 143
returning data from, 148
size/position, 148–149
item renderer(s), 14 3
component as, 146–147
custom, 144–147
benefits, 143
list control with, 144
drop-in method, 144–145
inline method, 144, 145–146
ItemClickEvent class, 8 5
itemEditBegin event, 147, 149–150
itemEditBeginning event, 147, 149–150
itemEditEnd event, 147, 149–150
itemEditorInstance property, 150
iteration::two, 53 1
IViewCursor interface, 114–11 5


Previous Page
Next Page

Index

J

J2EE server. See Java 2 Enterprise Edition server
Jakarta project, 50 1
Java 2 Enterprise Edition (J2EE) server, 7
Java Development Kit (JDK), 50 1
Java Flash Remoting, 24 7
Java Messaging Service (JMS), 7, 33, 246, 26 9
adapter, 268, 269, 277
messaging, 267
Java Open Transaction Manager (JOTM) package, 50 4
Java servlets, 48 2
Java Web applications, 24 5
java.lang.reflect package, 8 1
JavaScript, 18 3
ActionScript 3.0 v., 364
Flex communication, 183–187, 549
Flex Component creation with FA Bridge and, 555–559
garbage collector, 551
ActionScript garbage collector and, 551
Java-to-ActionScript conversion, 252–25 4
JDK. See Java Development Kit
JGroups, 26 1
JMS. See Java Messaging Service
Johnson, Ralph, 43 6
join ( ) method, 40 3
JOTM package. See Java Open Transaction Manager
package
JRun Web Server, 500, 50 1


Previous Page
Next Page

Index

K

keyboard events, 92–9 3
KeyNotFoundException.as, 41 3
KeyNotUniqueException.as, 412–41 3
keySet ( ) method, 406, 40 7
keys/values, associative arrays and, 405–40 7
keywords, 37 2
list, 372
reserved, 372
special context, 372


Previous Page
Next Page

Index

L

Label control, 65
labelFieldVar, 293, 29 4
labelFunction property, axis, 229, 23 1
Langdon, Kevin, 43 3
language, ActionScript. See programming, ActionScript
language option, 49 4
lastIndex property, 41 7
lastIndexOf ( ) method, 397, 40 2
launch configuration, 5 1
layout controls, 16 1
Layout Manager, 120–12 1
Layout pass, 12 1
LayoutManagerClient interface, 14 2
legals, 3
legend, chart, 23 2
length property, 39 5
libraries, ActionScript 3.0, 561–571.
See also specific libraries
Adobe Labs and, 561
Flex application building, 565
Flex application with building, 565–571
list of, 562
types of, 562
Library Build Path, 33 3
assets/classes added to, 334
line charts, 31, 222–22 3
sample code, 222
LinearAxis, 23 2
LineChart control, 10 7
LineFormattedTarget, 46 3
LineSeries component, 22 2
LinkBar control, 10 7
LinkBar navigator, 62, 6 3
list control, 106, 14 3
with custom item renderer, 144
drag-and-drop functionality, 171–172
List-based controls, 106–10 7
data providers and, 106–107
listener property, validator, 200
Loader class, Flash, 365, 37 6
code example, 382–383
loadMovie ( ) method, 51 7
localCompare ( ) method, 39 6
LocalConnection, 621, 63 8
C#.NET Windows application and, 627–641
ExternalInterface v., 625–626
LocalConnectionTraceTarget.as, 627–62 8
local-trusted sandbox, 43 4
local-with-filesystem sandbox, 43 4
local-with-networking sandbox, 43 4
“Log4j error on Flex startup,” 461
log4j tool, 46 1
LogAxis, 23 2
LogController.mxml, 469–470
LoggerButton.mxml, 46 6
loggers, 463, 46 4
custom, 465–471, 627
logging, 25 9
API, 463–464
using, 465
client-side, 464–465
compiler, 464
configuration, 259
Flash Debug Player and, 462–463
levels, 260.
See also specific logging levels.
overview, 461
Web-tier, 464
LoginEvent class, 9 1
lookahead groups, 41 7
Lott, Joey, 43 6
low-level data access, 36 6


Previous Page
Next Page

Index

M

Macromedia Flash Player 9. See Flash Player 9
MacromediaFMOmega, 626, 627, 63 8
MacromediaMutexOmega, 626, 62 7
main class, 37 5
Main.mxml, 537–53 8
“man in the middle” attack, 43 2
managed code, 62 7
mx.managers.IHistoryClient, 17 7
map ( ) method, 40 3
Mappr library, 56 2
MaskedTextInput, 80
match ( ) method, 39 8
max-cache-size property, 27 6
max-file-size property, 27 7
maxRadius property, 21 8
MaxWarnings property, 46 2
McLellan, Drew, 51 5
MD5, 43 3
Measurement pass, 120
Menu control, 10 7
MenuBar control, 10 7
message(s), 33, 26 7
adapter, 268.
See also adapters.
adding info to, 271–272
body, 33, 267
broker, 269
channels, 249–250, 268, 269.
See also channels.
destinations, 268.
See also destinations.
endpoint, 268
event, 272
filtering, 273–274
flow of, 268
header, 33, 267
sending, 270–271
message agents, 3 3
Message Service, Flex (FMS), 7, 33, 245, 246, 248, 26 9
adapters, 268, 277
custom, 277–278
configuration, 274–275
file, 248, 274–275
destinations, 275
configuration, 275–277
network properties, 276
service-related properties, 276–277
message services, 26 7
MessageLevel.ValidMessage value, 63 9
MessageService.PushMessageToClients ( ) method, 27 8
MessageService.PushMessageToPeer ( ) method, 27 8
message-time-to-live property, 27 6
messaging, Flex
architecture, 268–274
basics, 267–268
messaging-config.xml, 24 8
metacharacters, 41 6
metadata tags, 321.
See also specific metadata tags
in components, 321–331
list, 340
metasequences, 41 6
method closures, 36 4
methods, 309–311.
See also specific methods
ActionScript, 377–381
defining, 309–311
override, 311–312
Microphone class, 61 2
Midnight Coders, 34, 24 7
MiniDebugTarget, 46 3
mixed series charts, 236–23 7
column chart and, 237
sample code, 236–237
Model Locator pattern, 53 5
Weather application with, 535–537
modeling, data, 194–19 5
ModelLocator.as, 53 6
mx:Model tag, 194–19 5
MouseEvent class, 85, 93, 31 5
Move effect, 16 9
moveNext ( ) method, 11 4
movePrevious ( ) method, 11 4
MovieClip class, Flash, 375, 37 6
multidimensional arrays, 399, 40 7
multiple axis charts, 237–23 9
sample code, 238, 239
multiple pages, printing, 181–18 2
MultipleExample, 38 4
MultiRowTabs component, 31 8
MultiRowTabs.as, 315–31 7
mutex, 626, 638, 63 9
MXML, 25–26, 6 1
ActionScript separation from, 78–79
collection in, 109
components, 73
advanced, 293–295
composite, 295–297
creation, 289–304
custom, 73
properties/methods added to, 294–295
scoping, 291–292
simple, 289–290
styling, 292
template, 297–301
interfaces, 302
creating, 302
using, 302
naming conventions, 74
request restrictions, 446
syntax, 74
mxmlc.exe, 430, 43 9
compiling, 440–441
command-line, 440–441
drag-and-drop, 440, 441
wrappers and, 511–512
MyButton.as, 32 4
MyCustomItemRenderer.mxml, 146, 14 7
MyHBox.mxml, 29 1
myIcon class, 32 5
myLableStyle, 10 3
MyObjectComp.mxml, 30 3
myTextInput, 7 7
myVideo.mxml, 488, 48 9


Previous Page
Next Page

Index

N

name qualifier (: :) operator, 420, 42 5
named groups, 41 7
Namespace class, 420, 42 5
namespaces, 63–64, 36 5
navigator containers, 6 2
Navigator view
debugging, 42
source/design, 41
negative lookahead group, 41 7
network security, 432–43 3
new operator, 7 7
nextPage ( ) method, 18 2
nodes, 41 8
noncapturing group, 41 7
[NonCommittingChangeEvent] metadata tag, 328–330
NonCommittingChangeEventSample.mxml, 329–330
none logging level, 260
nonvisual components, 80
no-player-detection template, 40 9
no-player-detection-with-history template, 50 9
Null data type, 390
null operator, 40 4
NullKeyException.as, 41 2
Number data type, 36 5
NumericAxis, 22 9


Previous Page
Next Page

Index

O

Object class, class hierarchy and, 9 6
object introspection, 8 1
[object] tag, 51 8
attributes, 518
parameters, 518–520
wrappers and, 518–520
object types, 36 4
object-oriented programming (OOP), 53 2
ObjectUtil’s getClassInfo ( ) method, 83–8 4
Odeo library, 56 2
OOP. See object-oriented programming
open definition feature, 5 3
Open Source Flash Remoting gateway, 24 7
open Web technology, 43 3
OpenAMF project, 24 7
OpenLaszlo, 3
Flex 2.0 v., 3
operators. See specific operators
optional views, 42, 4 3
Orange Box, 2 1
ordered creation, 455–45 8
outline view, 14, 15, 41, 5 3
output ( ) method, 63 9
OutputCallback, 63 9
override methods, 311–31 2
overSkin style property, 70
Button control with, 104, 140–141


Previous Page
Next Page

Index

P

package statements, 305
paging element, 28 5
panels, 41.
See also specific panels
Parallel effect, 129, 130
parentApplication property, 7 7
parentDocument property, 7 7
PasswordValidator, 34 7
results, 348
sample application with, 348–349
PasswordValidator.as, 347–34 8
patterns, string, 39 8
Patterson, Danny, 43 6
percentage-based sizing, 97, 12 1
percentageHeight property, 9 7
percentageWidth property, 9 7
perspectives, 14, 40, 41.
See also Debugging perspective ;
Development perspective
changing, 52
PhoneBooth application, Apple, 61 2
PhoneFormatter, 210
pie charts, 32, 223–22 4
doughnut, 224
drill-down chart and, 236
sample code, 223–224
stacked, 224
standard, 224
PieChart component, 22 3
play ( ) method, 128, 350, 35 2
playerglobal.swc file, 48 7
plot charts, 32, 225–22 6
sample code, 225
PlotChart component, 22 5
point-to-point messaging, 26 8
pollMutex ( ) method, 63 8
pop ( ) method, 400
PopUpMenuButton control, 10 7
positive lookahead group, 41 7
preinitialize event, 101, 447, 44 9
preventDefault ( ) method, 15 1
primitive data types, 365, 389, 390
PrintDataGrid component, 18 2
printing, 180–18 3
components, 180
grid data, 180, 182–183
multiple pages, 181–182
private methods, 30 9
private properties, 307, 308, 30 9
Problems view, 4 2
producers, 33, 248, 267, 26 9
components, 269
creation, 269–270
production-mode option, 49 4
Program.cs, 639, 64 1
programmatic skins, 71–72, 104, 141–14 3
superclass for, 142–143
ProgrammaticSkin class, 141, 14 2
programming, ActionScript 3.0, 363–387.
See also ActionScript 3.0
coding considerations, 372
core language features, 364–365
data types and classes in, 389–426
display programming in, 374–387
getting started with, 367–374
introduction, 363–367
properties, ActionScript component, 307–309.
See also specific properties
defining, 307–309
private, 308, 309
standard, 307–308
Properties view, Design mode, 15–19, 4 2
Alphabetical property view options, 17, 19
Category property view options, 17, 18
Standard property view options, 15–17
Common section, 15, 16
Layout section, 17, 18
Style section, 17
PropertyChangeEvent class, 11 6
protected methods, 30 9
protected properties, 30 7
proxy server
definition, 498
Flex application deployment and, 498–499
Proxy Service configuration file, 24 8
proxy-config.xml, 24 8
public methods, 30 9
public properties, 30 7
Publish Application Source Wizard, 49, 50
publisher option, 49 4
Publish-subscribe messaging, 7, 33–34, 245, 26 8
flow, 268
push ( ) method, 400


Previous Page
Next Page

Index

Q

QName class, 420 , 42 4


Previous Page
Next Page

Index

R

RDS. See Remote Development Services
RDS support plugin, Eclipse, 597–60 3
readExternal ( ) method, 25 5
Real-time Messaging Protocol (RMTP), 24 8
RectangularBorder class, 14 2
Red Square, 2 1
reflection, 80–8 1
reflective programming, 8 1
RegExp, 41 5
class, 415
using, 416–417
complex data type, 390
regular expressions, 365, 41 5
ActionScript, 415–418
groups and, 417–418
strings and, 415–416
release phase, 47 9
Remote Data Services (RDS)
configuration, 597, 598
Dataview, 599
Fileview, 601
Query Viewer, 600
view options, 598
Visual Query Builder, 600
Remote Development Services (RDS), 59 7
Remote object properties, 26 6
Remote Procedure Call (RPC) services, 7–8, 34, 65–66, 245, 246–24 7
Cairngorm Framework and, 545
calling, 264
handling results and, 264–265
components, 7–8, 65, 119–120, 263–264
defining, 263–264
with FDS, 247
with Flex 2 SDK, 247
with RPC services, 246
configuration, 265
destination, 265–266
file, 248
Data Management Service v., 278–279, 591
remote sandbox, 43 4
[RemoteClass] metadata tag, 330
RemoteObject components, 7–8, 34, 65, 119, 575, 57 6
for AMFO, 247
defining, 263, 264
remoting-config.xml, 24 8
removeAllChildren ( ) method, 7 8
removeBusyCursor ( ) method, 15 8
removeChild ( ) method, 78, 37 7
RemoveChildAction, 170
removeChildAt ( ) method, 78, 37 7
removeCursor ( ) static method, 15 7
removeItem ( ) method, 40 6
Repeater component, 107, 16 1
execution process, 162–165
using, 161–162
replace ( ) method, 39 8
request restrictions, MXML, 44 6
required property, validator, 200
requiredFieldError property, validator, 200
Resize effect, 167, 16 9
restricted tags, MXML, 44 6
reverse ( ) method, 35 2
ReverseFormatter, 345–34 6
RIAs. See Rich Internet Applications
Rich Internet Applications (RIAs)
benefits, 4–5
Cairngorm Framework and, 531
definition, 3
FDS and, 245, 286
history, 4
rich media and, 620
Web applications v., 534
rich media, 60 9
RIAs with, 620
rich media integration, 609–620
audio, 610
Flex application with, 613
building, 613–617
inner workings of, 617–620
video, 610–611
RMTP. See Real-time Messaging Protocol
rollout event, 35 2
rollOver event, 35 2
root node, 41 8
Rotate effect, 129, 16 9
RPC services. See Remote Procedure Call services
RSLs. See Runtime Shared Libraries
RSS and Atom libraries, 56 2
Run configuration panel, Flex, 44 5
Run icon, 441, 44 2
run-time errors, ActionScript, 408, 410–41 1
run-time exceptions, 36 4
ActionScript, 414–415
Runtime Shared Libraries (RSLs), 33 2
Flex applications and deployment of, 485–487
Flex Builder and, 336–338, 339
Flex SDK and, 332, 339
URL properties, 337


Previous Page
Next Page

Index

S

S icon, 22
sandboxes, Flash Player, 43 4
cross-domain consideration and, 487, 499
local-trusted, 434
local-with-filesystem, 434
local-with-networking, 434
types, 434
sans device font, 13 5
Scale-9, 71, 14 1
scaleX property, 350
scaleY property, 350
scope, 26 6
scoping, 29 1
MXML components, 291–292
scrubDelay property, 15 6
SDK. See Flex 2.0 , SDK ; software development kit
sealed classes, 36 4
Search dialog box, 5 4
search ( ) method, 39 8
Search view, 4 2
SearchForm.mxml, 56 9
Secure Socket Layer (SSL), 43 3
securities, 22 6
security
constraint, 258
global, 258
destinations and, 258–259
Flash Player, 432–433, 434–435
Flex applications, 432, 445–447
Flash Player and, 432–433
network security and, 432–433
open Web technology and, 433
security sandbox, 434, 49 9
Security.allowDomain ( ), 44 6
seek ( ) method, 11 5
Sequence effect, 129, 130
serialization, 250
ActionScript-to-Java conversion, 250–252
ActionScript-to-SOAP types, 254
custom, 255–257
data, 250–257
Java-to-ActionScript conversion, 252–254
SeriesInterpolate event, 240
SeriesSlide event, 240
SeriesZoom event, 240–24 1
serif device font, 13 5
Service Capture, 433, 58 3
service configuration files, 248–24 9
Service Locator, 540, 545–54 6
ServiceAdapter.HandleSubscriptions ( ) method, 27 8
ServiceAdapter.Manage ( ) method, 27 8
Services Browser, 60 6
servlets, 48 2
container, 500
Java, 482
session-timeout property, 27 6
setAxisLabel function, 230
setBusyCursor ( ) method, 15 8
setChildIndex ( ) method, 37 7
setCredentials ( ) method, 25 9
setCursor ( ) static method, 15 7
SetPropertyAction, 170
setRemoteCredentials ( ) method, 25 9
setSelection ( ) method, 7 7
setStyle ( ) method, 102, 128, 13 3
SetStyleAction, 170
setters, 308, 30 9
SHA-1, 43 3
shallow copy, 40 8
Shape class, Flash, 365, 37 6
code example, 382–383
shared objects, 187–18 8
saving/reloading data from, 187–188
SharedObject, 43 4
shift ( ) method, 400
showDelay property, 15 6
showEffect property, 15 6
Sierra, Kathy, 43 6
Simple Object Access Protocol (SOAP), 6 5
SimpleBinding.mxml, 32 2
SimpleButton class, Flash, 37 6
code example, 383–384
SimpleMonths component, 29 1
SimpleStyledMonths component and, 293
SimpleMonthsMain.mxml, 290
SimpleMonths.mxml, 290
SimpleStyleClient interface, 14 2
SimpleStyleMonths.mxml, 29 2
singleton pattern, 53 5
sizing, 97–98, 120, 121–12 4
default, 97, 121–122
explicit, 97, 121, 122
percentage-based, 97, 121
properties, 121
skinning, 140
skins, 70, 10 4
graphical, 71, 104, 140–141
programmatic, 71–72, 104, 141–143
superclass for, 142–143
mx.skins package, 14 2
mx.skins.halo package, 14 2
slice ( ) method, 397, 400, 40 8
sniffer program, 510
SOAP. See Simple Object Access Protocol
soap, 26 7
Socket class, Flash, 36 5
software clustering, 26 1
sample code, 261
software development kit (SDK), 3.
See also Flex 2.0 , SDK
some ( ) method, 40 3
Sort class, 11 2
sort ( ) method, 401, 40 2
SortedMap class, 40 6
compile-time errors, 409, 410
with custom exception classes, 413–414
SortField class, 11 2
sorting keys/values, 405–40 7
sorting/finding items, of arrays, 401–40 2
sortOn ( ) method, 401, 40 2
Sothink SWF Decompiler, 432, 44 7
sound files, 17 6
embedding, 176–177
source, 266, 53 7
Source mode, 14–15, 4 1
source property, validator, 200
splice ( ) method, 400
functions of, 400–401
split ( ) method, 39 8
Sprite class, 365, 37 4
class hierarchy and, 96
SSL. See Secure Socket Layer
stage, 374, 37 5
standard properties, 307–30 8
startup order, Flex application, 447–44 9
StartUpOrder.mxml, 447–44 8
states, 165.
See also view states
States panel, 1 5
States view, 15, 4 2
StateSelector.mxml, 7 3
stepping, breakpoints and, 47 5
string(s), 395–39 9
case type of, 399
characters in, 395–396
combining, 397
comparison of, 396
length property, 395
patterns within, 398
regular expressions and, 415–416
representations of objects, 396–397
substrings within, 397–398
uppercase/lowercase conversion, 399
String class, 395.
See also string(s)
String data type, 390
string logging level, 260
style(s), 13 1
applying, 131
chart, 241
examples, 241–243
tooltips and, 154
using, 132–133
[Style] metadata tag, 330–33 1
mx:Style tag, 70, 540
styleName property, 9 7
StyleSample.mxml, 33 1
subclassing events, 85, 91–9 2
substr ( ) method, 39 7
substring(s), 39 7
by character position, 397–398
by delimiter, 398
within strings, 397–398
substring ( ) method, 39 7
Sun Web site, 50 1
super keyword, 311–31 2
superclass, 14 2
programmatic skin with, 142–143
super.play, 350
swapChildren ( ) method, 37 7
swapChildrenAt ( ) method, 37 7
SWC files, 12, 27, 2 8
creation, 332
Flex Builder and, 332–335
Flex SDK and, 332
deploying, 338
Flex Builder and, 340
Flex SDK and, 340
Flex application with, 562–564
ActionScript libraries and, 562–564
SWF files, 13 7
AVM1/AVM2
ExternalInterface and, 622–625
creation, 137
FlashType fonts and, 137–138
embedding, 176
mx:SWFLoader, 44 6
SWFObject, 48 1
switching workspaces, 43–4 4
SwitchSymbolFormatter class, 34 1
customization, 341–344
# symbol, 34 3
* symbol, 343, 34 4
synchronization, data, 32, 27 9
conflicts, 279
distributed data and, 283–284
synchronous errors, 410


Previous Page
Next Page

Index

T

Tab container, 48 1
TabBar container, 6 2
TabBar control, 10 7
TabNavigator container, 62, 44 9
history managment in, 177
mx:TabNavigator, 44 9
TabSkin class, 31 5
tags. See metadata tags
Tamarin, 36 4
Tamper Data add-on, 43 3
target node, 8 4
target property, 8 8
currentTarget property v., 88
targeting phase, 85, 8 9
targets, 463, 46 4
Tasks view, 4 2
TCP Monitor application, 510
template components, 29 7
creation, 297–298
MXML, 297–301
testing.
See also debugging
debugging and, 461
validation events, 204–207
text editor, 3 5
TextEvent class, 8 5
TextField class, Flash, 37 6
code example, 386–387
TextInput component, 31 3
extension, 319–320
TextInput control, 63, 80, 12 4
tooltip for, 153
TextInputLengthEventSample.mxml, 320–32 1
TextInputWithCountEvent custom component, 320
TextInputWithCountEvent.as, 319–320
this keyword, 7 6
multiple access, 291, 292
Thread.Sleep, 63 9
throttle-inbound property, 27 6
throttle-outbound-property, 27 6
ticks, 22 8
TileList control, 10 6
time values, 39 2
unit retrieval, 392–393
title option, 49 4
title property, axis, 23 1
ToggleButtonBar container, 6 2
history management added to, 177–178
ToggleButtonBar control, 10 7
toLowerCase ( ) method, 39 9
Tomcat, 500–50 1
directory structure, 502
FDS2 deployment on, 500–508
installation, 501
Website, 501
tooltip(s), 152–15 3
creation, 153
delay times for, 156
effects, 156–157
enabling/disabling, 155
events, 154–155
manager, 155
styles with, 154
for TextInput control, 153
toolTip property, 97, 15 3
ToolTipEvent class, 15 4
ToolTipManager class, 15 5
top node, 41 8
toString ( ) method, 39 6
toUpperCase ( ) method, 39 9
trace ( ) methods, 446, 464, 46 5
deletion, 446–447
TraceOutputFileEnable property, 462, 46 3
TraceOutputFileName property, 462, 46 3
TracePanel.mxml, 466–468, 62 8
checkbox for starting/stopping in, 629–631
updates for, 629–631
TracePanelTarget.as, 46 8
TraceTarget, 46 3
transactions, Data Management Service, 285–28 6
transition(s), 16 7
action effects and, 170
effects as, 167
filters and, 170–171
using, 167–171
view states with, 167–169
Tree control, 10 6
trigger(s), 103, 12 7
custom effect, 357–359
trigger property, validator, 200
triggerBinding event, 32 9
triggerEvent property, validator, 200
TrueTypeFont (TTF) families, 13 5
embedded, 176
try…catch…finally statements, 411, 414, 41 5
TTF families. See TrueTypeFont families
TweenEffect class, 35 3
custom, 354
example, 354–357
extending, 353
TweenEffectInstance class, 35 3
extending, 353–354
type selector, 69, 70, 13 3
typewriter device font, 13 5


Previous Page
Next Page

Index

U

UFO. See Unobtrusive Flash Objects
UI. See user interface(s)
UIComponent
class, 80, 95
class hierarchy and, 96
properties, 96–97
methods, 314
implementing/overriding, 314
uint data type, 365, 390
undefined value, 390
Uniform Resource Identifier (URI), 365, 42 5
uninstall phase, 480
UnitsVO.as, 53 5
unmanaged code, 62 7
Unobtrusive Flash Objects (UFO), 48 1
unshift ( ) method, 400
update phase, 480
updateComplete event, 10 1
updateDisplayList ( ) method, 14 2
upSkin style property, 70
Button control with, 104, 140–141
URI. See Uniform Resource Identifier
url, 26 7
URL properties, RSL, 33 7
URLLoader class, Flash, 365, 36 6
URLStream class, Flash, 36 6
User class, 25 5
associative arrays and, 404
user interface(s) (UI)
building, 95–125
components, 80, 124
controls, 63
customizing, 127–159
elements, 161–190
userVO property, 9 1
UseTemplate1.mxml, 29 9
results of, 301
UseTemplate2.mxml, 300
results, 301
mx.utils, 3 1


Previous Page
Next Page

Index

V

ValidateButton component, 30 9
Validate.mxml- Source for Validation SWF Library, 55 4
validateNow ( ) method, 12 3
ValidateSample.html- HTML Wrapper file, 552–55 3
validation
ActionScript and, 207–208
data, 67–68, 200–208
data model, 201–203
events, 204
testing, 204–207
validator(s).
See also specific validators
built-in, 200–201
components, 67–68
custom, 200, 347–349
extending, 347
FA Bridge, JavaScript and, 551–555
properties, 200
Value Object CFC, 59 4
value objects (VOs), 53 4
Weather application and, 534–535
value types, 389–390
complex, 389, 390
primitive, 389, 390
values. See specific values
values ( ) method, 40 7
values/keys, associative arrays and, 405–40 7
variables, 19 2
binding to, 192–194
Variables view, 21–22, 4 2
VBox container, 61, 63, 80, 19 7
Video class, Flash, 37 6
VideoDisplay control, 61 2
VideoListView.mxml, 570
VideoPlayer.mxml, 570–57 1
view, 53 7
Cairngorm Framework and, 537
view states, 16 5
transitions applied to, 167–169
using, 165–166
views, 41.
See also specific views
viewSourceURL property, 44 6
disable, 446
ViewStack navigator container, 62, 6 3
mx:ViewStack, 44 9
visible property, 9 7
Visual C# 2005 Express Edition, Microsoft, 62 1
IDE, 627
link, 621
visual components
ActionScript, 77–78
Flex 2.0, 54, 95–104
class hierarchy and, 96
Visual Studio development tools, Microsoft, 62 6
Vlissides, John, 43 6
void data type, 390
VOs. See value objects


Previous Page
Next Page

Index

W

W3C reports. See World Wide Web Consortium reports
WAR file, 50 3
warn logging level, 260
Weather application, Flex, 53 3
Cairngorm Framework and, 533–547
entry point for, 537
Front controller pattern in, 543–544
Model Locator of, 535–537
VO and, 534–535
weather property, 536, 53 7
WeatherDelegate class, 542, 54 6
WeatherDelegate.as, 54 6
WeatherView component, 53 7
WeatherView.mxml, 538–540
WeatherVO.as, 534–53 5
Web applications, RIAs v., 534
Web Developer Extension for Firefox, 510
Web service properties, 26 7
Web technology, open, 43 3
WebORB, 34, 247, 57 4
WebService component, 7, 65, 80, 11 9
defining, 263–264
Webster, Steven, 531, 53 2
while loop, 18 2
width property, 97, 10 5
Wikipedia, 44 1
Windows Presentation Foundation (WPF), 4
Windows Presentation Server Everywhere (WPF/E), 4
workbench. See Flex Builder 2.0 , workbench
worker classes, 54 1
working sets, 5 3
workspaces, 41, 43–4 4
switching, 43–44
World Wide Web Consortium (W3C) reports, 51 4
WPF. See Windows Presentation Foundation
WPF/E. See Windows Presentation Server Everywhere
wrapper(s)
creation, 508–509
Web standards support and, 514–517
definition, 508
editing, 521
Express Install option and, 521–525
[embed] tag and, 518
attributes, 518
parameters, 518–520
features, 509
configuration, 509, 510
defining, 510–511
features added to, 512–514
Flex application deployment and, 508–525
HTML page, 178–179
communication with, 183–187
migrating/transferring files and, 509–510
MXMLC compiler and, 511–512
[object] tag and, 518
attributes, 518
parameters, 518–520
XHTML, 514–517
writeExternal ( ) method, 255, 25 7
wsdl, 26 7


Previous Page
Next Page

Index

X

x property, 97, 10 4
XA protocol. See Extended Architecture protocol
XAML (Extensible Application Markup Language), 4
XHMTL
1.0 language, 514
code, 514
wrapper, 514–517
xk72, 43 3
XML (Extensible Markup Language), 3, 41 8
data provider, 117–119
documents, 418
parts, 418, 419
E4X, 365, 420
classes, 420–426
introduction, 420
XML creating/destroying with, 420–423
XML namespaces and, 425–426
XML navigation with, 423–425
XML type conversion and, 426
external data, 195
external file
binding to, 195–196
introduction to, 418–419
namespaces, 63–64
XML complex data type, 390
XML User Interface Language (XUL), 4
XMLList class, 420
XMLList complex data type, 390
mx:XML tag, 195, 19 6
XUL. See XML User Interface Language


Previous Page
Next Page

Index

Y

y property, 97, 10 4
Yellow Diamond, 2 1
YouTube
API, 562
HTTP service component and, 119–120
library, 562, 571
Cairngorm Framework and, 565
Flex application with, 565–571


Previous Page
Next Page

Index

Z

zero argument constructor, 30 7
ZipCodeValidator, 200
Zoom effect, 129, 17 6


List of Figures

Chapter 2: Introducing Flex Builder 2.0

Figure 2-1: Creating a new Flex project
Figure 2-2: Selecting the type of project
Figure 2-3: Defining the storage location of project files
Figure 2-4: Naming the main application file
Figure 2-5: Adding a library during project creation
Figure 2-6: Adding a library to an existing project
Figure 2-7: The Development perspective in Source mode
Figure 2-8: Outline view of Development perspective in Source mode
Figure 2-9: The Development perspective in Design mode
Figure 2-10: The Common section of the Properties view
Figure 2-11: The Style section of the Properties view
Figure 2-12: The Layout section of the Properties view (note that the controls shown will not be available if the application is not using absolute layout)
Figure 2-13: The Category view of the Properties view
Figure 2-14: The Alphabetical view of the Properties view
Figure 2-15: Switching to Flex Debugging perspective
Figure 2-16: Adding a breakpoint
Figure 2-17: Variables view of the Debugging perspective
Figure 2-18: Breakpoints view of the Debugging perspective
Figure 2-19: Expressions view of the Debugging perspective
Figure 2-20: Running an application in debug mode
Figure 2-21: Running an application

Chapter 3: Flex 2.0 Basics

Figure 3-1: "Hello World" application rendered in the Flash Player
Figure 3-2: Flow of data from message producer to message consumer
Figure 3-3: Publish-subscribe message flow

Chapter 4: Using Flex Builder 2.0

Figure 4-1: Flex Start Page
Figure 4-2: Flex Help application
Figure 4-3: Dialog windows used to create and select a search list
Figure 4-4: Search result on the term “debugging”
Figure 4-5: Help view search mode
Figure 4-6: Dynamic Help view
Figure 4-7: Prompt asking if you would like to switch perspectives
Figure 4-8: Dialog window that pop ups when selecting other views
Figure 4-9: Switching workspaces
Figure 4-10: Workspace switch dialog box
Figure 4-11: Three Flex Builder project types
Figure 4-12: Chapter4.mxml file
Figure 4-13: New MXML Application dialog window
Figure 4-14: Sideways triangle located over the top-left area of the MXML file icon
Figure 4-15: Selecting Flex applications
Figure 4-16: Selecting the DrawCircles.as file
Figure 4-17: Running the DrawCircles application
Figure 4-18: New Folder Wizard
Figure 4-19: Publish Application Source Wizard
Figure 4-20: Generated publish source application
Figure 4-21: Opening the launch configuration
Figure 4-22: Main tab of the Create, Manage, and Run Configurations dialog box
Figure 4-23: Changing perspectives
Figure 4-24: Views and editors in various docking positions
Figure 4-25: Search dialog box
Figure 4-26: Proper layout of the controls on the stage and Flex Properties view

Chapter 5: Programming Languages

Figure 5-1: A ViewStack container and LinkBar navigator
Figure 5-2: Photos retrieved from Flickr
Figure 5-3: Data validation application
Figure 5-4: Data formatting application
Figure 5-5: CSS application
Figure 5-6: Capturing phase
Figure 5-7: Bubbling phase

Chapter 6: Building User Interfaces

Figure 6-1: Class hierarchy from the Object class through to all visual components in Flex
Figure 6-2: Major events that are dispatched in a component’s creation life cycle
Figure 6-3: Three Button controls

Chapter 7: Customizing the User Interface

Figure 7-1: Entering text into the text field
Figure 7-2: Character Embedding dialog box
Figure 7-3: Three more text fields for each typeface
Figure 7-4: Graphical skins
Figure 7-5: List control with a custom item renderer
Figure 7-6: Tooltip for TextInput control

Chapter 8: Flex UI Topics

Figure 8-1: Using the Repeater control
Figure 8-2: Vertical Repeater control
Figure 8-3: Code execution when application initializes
Figure 8-4: Re-execution of the Repeater control when the Category 2 button is selected
Figure 8-5: Application in base state
Figure 8-6: Application after user clicks the Open Description button
Figure 8-7: Effect of Rotate
Figure 8-8: The rotation transition
Figure 8-9: A valid drop when over a target
Figure 8-10: An invalid drop when not over a target
Figure 8-11: The compiled results of Listing 8-6

Chapter 9: Flex Data

Figure 9-1: Results of using <mx:Binding>
Figure 9-2: Application after it initializes
Figure 9-3: Updating the Label
Figure 9-4: Slider set to 300
Figure 9-5: Slider set to 160
Figure 9-6: Data modeling
Figure 9-7: Adding a second instance of a component
Figure 9-8: Binding from components to the model
Figure 9-9: Validating a data model
Figure 9-10: The errorString when validation fails
Figure 9-11: The same example as Figure 9-10, but this time the data is valid
Figure 9-12: Validation popup
Figure 9-13: Validating with ActionScript
Figure 9-14: Using built-in formatters
Figure 9-15: Shows the PhoneFormatter’s error property changing on each keystroke

Chapter 10: Flex Charting

Figure 10-1: Area chart
Figure 10-2: Clustered bar chart
Figure 10-3: Stacked bar chart
Figure 10-4: Bubble chart
Figure 10-5: Clustered column chart
Figure 10-6: Overlaid column chart
Figure 10-7: Line chart
Figure 10-8: Pie chart
Figure 10-9: Plot chart
Figure 10-10: Candlestick chart
Figure 10-11: HLOC chart
Figure 10-12: Axis labels
Figure 10-13: Chart event
Figure 10-14: Drill-down chart
Figure 10-15: Mixed series chart
Figure 10-16: Multiple-axis chart
Figure 10-17: Axis rotation
Figure 10-18: Gradient fill

Chapter 11: Data Access

Figure 11-1: RPC components interact with RPC services
Figure 11-2: Flow of data from a producer to consumer
Figure 11-3: Publish-subscribe messaging flow
Figure 11-4: Flow of data between the server-side data resource and an Array Collection object

Chapter 12: Creating MXML Components

Figure 12-1: The SimpleMonths component
Figure 12-2: The this being accessed in multiple ways
Figure 12-3: SimpleMonths and SimpleStyledMonths components
Figure 12-4: All three versions of the AdvancedMonths component
Figure 12-5: The custom component’s method being called from the parent
Figure 12-6: The results of the Birthdate component’s getBirthdate method
Figure 12-7: The results of UseTemplate1.mxml
Figure 12-8: The results of UseTemplate2.mxml
Figure 12-9: The results of the getTotal method

Chapter 13: Flex Component Properties

Figure 13-1: The ValidateButton component in an invalid state
Figure 13-2: The ValidateButton component in a valid state
Figure 13-3: An Alert with the results of a call to the getProperties method
Figure 13-4: The button label with the parentheses added by the override method
Figure 13-5: The EmailTextInput component in action
Figure 13-6: Two instances of the CircleLabel component
Figure 13-7: The MultiRowTabs component with seven tabs

Chapter 14: Flex Components

Figure 14-1: The custom event being dispatched
Figure 14-2: Simple data binding
Figure 14-3: The example with a length of less than 10
Figure 14-4: The formatter has executed when the length is 10
Figure 14-5: The custom event being dispatched
Figure 14-6: Code hints
Figure 14-7: Code hints when in Design view
Figure 14-8: Using the Style metadata tag
Figure 14-9: Creating a Flex library project
Figure 14-10: Naming the project
Figure 14-11: Adding classes to the library build path
Figure 14-12: Adding assets to the library build path
Figure 14-13: The compiled SWC file in the bin folder
Figure 14-14: The contents of the compiled SWC file
Figure 14-15: Adding an SWC file to the project’s library path
Figure 14-16: The SWC file after being added
Figure 14-17: Changing RSL URL properties
Figure 14-18: Compiled with the components embedded
Figure 14-19: Compiled using an RSL for the components
Figure 14-20: C:\RSLSample before compiling the ValidateButtonMain with RSL
Figure 14-21: The newly compiled ValidateButtonmain.swf

Chapter 15: Custom Formatter, Validator, and Effect Components

Figure 15-1: Formatting a string with the # symbol
Figure 15-2: Formatting a string with the * character
Figure 15-3: ReverseFormatter in action
Figure 15-4: Displaying a formatter error
Figure 15-5: PasswordValidator results
Figure 15-6: Default state of button
Figure 15-7: Button upon rollover
Figure 15-8: CustomTweenEffect application
Figure 15-9: Result of clicking the button
Figure 15-10: Custom effect application
Figure 15-11: Result of clicking the All On button

Chapter 16: Overview of ActionScript Programming

Figure 16-1: How the application should look
Figure 16-2: Display list object instantiation tree
Figure 16-3: Bitmap map class taking an image and creating a color-inverted copy
Figure 16-4: Loading the same image and applying a mask so that only the Wrox logo shows
Figure 16-5: Resulting three frames of the SWF
Figure 16-6: Using the TextField class to display the status of an FLV stream

Chapter 18: Building and Deploying Flex Applications

Figure 18-1: Flex 2 SDK deployment environment
Figure 18-2: FDS2 precompile deployment environment
Figure 18-3: FDS2 integrated Web-compiling deployment environment
Figure 18-4: FDS2 directory structure
Figure 18-5: The compiled Flex application
Figure 18-6: Drag-and-drop MXML compiling
Figure 18-7: Flex Builder Run and Debug buttons
Figure 18-8: Right-clicking an MXML application to compile and run
Figure 18-9: Flex compiler / HTML wrapper preferences
Figure 18-10: Run configuration panel

Chapter 19: Debugging and Testing

Figure 19-1: The results of CustomLoggerMain.mxml
Figure 19-2: The results of the modified CustomLoggerMain.mxml with the LogController.mxml component
Figure 19-3: Debug application toolbar icon
Figure 19-4: Breakpoint on line 29 of CustomLoggerMain.mxml
Figure 19-5: Breakpoint view
Figure 19-6: Variables view
Figure 19-7: Find Variable dialog box
Figure 19-8: Expressions view

Chapter 20: Deploying Flex Applications

Figure 20-1: The Navigator view of the Flex project
Figure 20-2: Flex Compiler property settings
Figure 20-3: Creating a Flex Library Project in Flex Builder 2
Figure 20-4: Adding and defining elements for the compilation phase
Figure 20-5: Compiling the library within the assets folder
Figure 20-6: Selecting the Library Project
Figure 20-7: Folder structure on the deployment server
Figure 20-8: Selecting the J2EE Web application option
Figure 20-9: Starting the Web server
Figure 20-10: Launching the examples
Figure 20-11: Copying all the necessary files
Figure 20-12: Location of files
Figure 20-13: Validating the code

Chapter 21: Using the Cairngorm Framework

Figure 21-1: Example Weather application using the Cairngorm Framework

Chapter 22: Using the Flex-Ajax Bridge

Figure 22-1: A JavaScript alert showing the Flex validation messages
Figure 22-2: Page when it loads
Figure 22-3: Page after the createButton method has been run

Chapter 23: Using the ActionScript 3.0 Libraries

Figure 23-1: New Flex Project opening screen
Figure 23-2: Assigning a name and path
Figure 23-3: Set build paths
Figure 23-4: Add SWC button
Figure 23-5: Completed application

Chapter 24: Using ColdFusion/Flex Connectivity

Figure 24-1: ColdFusion Flash Remoting Service option
Figure 24-2: The additional compiler arguments for ColdFusion Flash Remoting
Figure 24-3: RDS Configuration
Figure 24-4: RDS view options
Figure 24-5: RDS Dataview
Figure 24-6: RDS Query Viewer
Figure 24-7: Visual Query Builder
Figure 24-8: RDS Fileview
Figure 24-9: The first step in the install process
Figure 24-10: Confirmation that CF_FB_Extensions.zip is to be installed
Figure 24-11: Install All option
Figure 24-12: CFC Value Object Wizard

Chapter 25: Rich Media Integration

Figure 25-1: Rich media application
Figure 25-2: New state of the application

Chapter 26: Integration with External Applications

Figure 26-1: Button, TextInput, and TextArea on the Flash Stage
Figure 26-2: Application running with sample messages

Appendix A: Flex 2.0.1

Figure A-1: Default style
Figure A-2: Button two’s style
Figure A-3: Button three’s style
Figure A-4: Application with the RuntimeCSSModule and DateWidget modules loaded
Figure A-5: Application with the PowWidget module loaded


List of Listings

Chapter 4: Using Flex Builder 2.0

Listing 4-1: DrawCircles.as

Chapter 8: Flex UI Topics

Listing 8-1: Basic Repeater
Listing 8-2: Advanced Repeater
Listing 8-3: Two-State View
Listing 8-4: Advanced Transitions Example
Listing 8-5: List Control Drag and Drop
Listing 8-6: Custom Drag-and-Drop Operation
Listing 8-7: Sample Wrapper HTML Page
Listing 8-8: A Simple Print Job
Listing 8-9: A Simple Multipage Print Job
Listing 8-10: PrintDataGrid Sample
Listing 8-11: Flex to JavaScript
Listing 8-12: HTML with JavaScript
Listing 8-13: Flex Code to Test JavaScript
Listing 8-14: HTML Wrapper to Let Flex Know JavaScript Is Ready
Listing 8-15: Saving a Shared Object

Chapter 9: Flex Data

Listing 9-1: Binding to Contact.xml File with <mx:Model>
Listing 9-2: Binding to Contact.xml File with <mx:XML>
Listing 9-3: Custom Component Contact.mxml
Listing 9-4: Binding to Contact.xml File with <mx:Model> and a Custom Component
Listing 9-5: Binding from the Components to the Model
Listing 9-6: Built-in Validator Classes
Listing 9-7: Binding to a Data Model
Listing 9-8: Simple Data Validation
Listing 9-9: Testing Validation Events
Listing 9-10: Validating with ActionScript

Chapter 10: Flex Charting

Listing 10-1: ChartData.as
Listing 10-2: Area Chart
Listing 10-3: Bar Chart
Listing 10-4: Bubble Chart
Listing 10-5: Column Chart
Listing 10-6: Line Chart
Listing 10-7: Pie Chart
Listing 10-8: Plot Chart
Listing 10-9: Candlestick Chart
Listing 10-10: HLOC Chart
Listing 10-11: Chart Event
Listing 10-12: Drill-Down Chart
Listing 10-13: Mixed Series Chart
Listing 10-14: Multiple-Axis Chart
Listing 10-15: Gradient fill

Chapter 11: Data Access

Listing 11-1: User.as
Listing 11-2: User.java

Chapter 12: Creating MXML Components

Listing 12-1: SimpleMonths.mxml
Listing 12-2: SimpleMonthsMain.mxml
Listing 12-3: Index.mxml
Listing 12-4: MyHBox.mxml
Listing 12-5: SimpleStyledMonths.mxml
Listing 12-6: AdvancedMonths.mxml
Listing 12-7: Birthdate.mxml
Listing 12-8: BirthdateMain.mxml
Listing 12-9: TemplateLayoutComp.mxml Template Component
Listing 12-10: UseTemplate1.mxml
Listing 12-11: UseTemplate2.mxml
Listing 12-12: IBirthdate.as Interface Example
Listing 12-13: Birthdate.mxml Component Using IBirthdate as the Interface
Listing 12-14: MyObjectComp.mxml
Listing 12-15: IMXMLObjectExample.mxml

Chapter 13: Flex Component Properties

Listing 13-1: Adding Private Properties with Getters and Setters
Listing 13-2: Adding a Custom Method
Listing 13-3: Overriding a Method
Listing 13-4: EmailTextInput Component
Listing 13-5: CircleLabel Component
Listing 13-6: MultiRowTabs.as

Chapter 14: Flex Components

Listing 14-1: TextInputWithCountEvent.as
Listing 14-2: TextInputLengthEventSample.mxml
Listing 14-3: SimpleBinding.mxml
Listing 14-4: BindWithGettersAndSetters.mxml
Listing 14-5: MyButton.as
Listing 14-6: Main.mxml
Listing 14-7: ButtonLabel.as
Listing 14-8: EventSample.mxml
Listing 14-9: Adding the Effect Metadata Tag
Listing 14-10: Adding labelChangedEffect to the Component Instantiation MXML Tag
Listing 14-11: MyComponent.mxml
Listing 14-12: NonCommittingChangeEventSample.mxml
Listing 14-13: CustomCircle.as
Listing 14-14: StyleSample.mxml

Chapter 15: Custom Formatter, Validator, and Effect Components

Listing 15-1: Customizing the SwitchSymbolFormatter Class
Listing 15-2: Passing the * Character as the Format Character
Listing 15-3: Custom Formatter that Will Reverse the Text
Listing 15-4: Sample Application Running the Custom Formatter
Listing 15-5: PasswordValidator.as
Listing 15-6: Sample Application Using PasswordValidator
Listing 15-7: CustomEffect.as
Listing 15-8: CustomEffectInstance.as
Listing 15-9: CustomEffectApp.mxml
Listing 15-10: CustomTweenEffect.as
Listing 15-11: CustomTweenEffectInstance.as
Listing 15-12: CustomTweenEffectApp.mxml
Listing 15-13: GlowingTextInput.as Component

Chapter 16: Overview of ActionScript Programming

Listing 16-1: DrawShapes.as

Chapter 17: Data Types and Classes

Listing 17-1: Methods of Creating Dates
Listing 17-2: Calendar Class
Listing 17-3: User Class
Listing 17-4: SortedMap Class
Listing 17-5: SortedMap Class
Listing 17-6: NullKeyException.as
Listing 17-7: KeyNotUniqueException.as
Listing 17-8: KeyNotFoundException.as
Listing 17-9: SortedMap Class with Custom Exception Classes
Listing 17-10: Users.xml

Chapter 18: Building and Deploying Flex Applications

Listing 18-1: StartUpOrder.mxml
Listing 18-2: CreationPolicyExample.mxml
Listing 18-3: DeferringComponents.mxml
Listing 18-4: DeferringComponents_2.mxml
Listing 18-5: CreationIndexExample.mxml
Listing 18-6: AddToCreationQueueExample.mxml
Listing 18-7: CallLaterExample.mxml

Chapter 19: Debugging and Testing

Listing 19-1: CustomLoggerMain.mxml
Listing 19-2: LoggerButton.mxml
Listing 19-3: TracePanel.mxml
Listing 19-4: TracePanelTarget.as
Listing 19-5: LogController.mxml
Listing 19-6: Modified CustomLoggerMain.mxml

Chapter 21: Using the Cairngorm Framework

Listing 21-1: WeatherVO.as
Listing 21-2: UnitsVO.as
Listing 21-3: ModelLocator.as
Listing 21-4: Main.mxml
Listing 21-5: WeatherView.mxml
Listing 21-6: GetWeatherByLocationCommand.as
Listing 21-7: GetWeatherByLocationEvent.as
Listing 21-8: ApplicationController.as
Listing 21-9: WeatherDelegate.as

Chapter 22: Using the Flex-Ajax Bridge

Listing 22-1: Including the SWF in the HTML Page
Listing 22-2: ValidateSample.html - the HTML Wrapper File
Listing 22-3: Validate.mxml - the Source for the Validation SWF Library
Listing 22-4: Component.mxml
Listing 22-5: CreateComponent.html

Chapter 23: Using the ActionScript 3.0 Libraries

Listing 23-1: Main.mxml
Listing 23-2: GetVideosByTagCommand.as
Listing 23-3: ApplicationController.mxml
Listing 23-4: GetVideosByTagEvent.as
Listing 23-5: DataModel.as
Listing 23-6: SearchForm.mxml
Listing 23-7: VideoListView.mxml
Listing 23-8: VideoPlayer.mxml

Chapter 25: Rich Media Integration

Listing 25-1: Main.mxml

Chapter 26: Integration with External Applications

Listing 26-1: AVM2.mxml
Listing 26-2: LocalConnectionTraceTarget.as
Listing 26-3: TracePanel.mxml
Listing 26-4: Flex2TracePanel.cs
Listing 26-5: Flex2TracePanel.Designer.cs
Listing 26-6: Program.cs

Appendix A: Flex 2.0.1

Listing A-1: RuntimeCSSMain.mxml
Listing A-2: blueCSS.css
Listing A-3: redCSS.css
Listing A-4: LocalConnectionTraceTarget.as
Listing A-5: TracePanelTarget.as
Listing A-6: TracePanel.as
Listing A-7: ModularApplicationMain.mxml
Listing A-8: RuntimeCSSModule.mxml
Listing A-9: DateWidget.mxml
Listing A-10: PowWidget.mxml
Listing A-11: Modifed ModularApplicationMain.mxml