Programming Flex 3: Chapter 20, Embedding Flex Applications in a Browser
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9
You already saw how to set the page title for the browser
using the init() method. However,
the init() method is designed to be
called just once, when the application starts. Normally, you'll want
to change the page title as the user interacts with the application.
You can change the page title at any time using the setTitle() method by simply passing it the
title as a parameter.
When working with BrowserManager, two events are of interest: applicationUrlChange and browserUrlChange. The applicationUrlChange event occurs when the
URL changes programmatically, such as when it is changed via the
setFragment() method. Otherwise,
when the URL changes because the user clicks the Back or Forward
button or because the user changes the URL in the address bar,
BrowserManager dispatches the
browserUrlChange event. Both events
are of type mx.events.BrowserChangeEvent. Typically,
you'll handle both events using the same method because most
applications should behave identically in all cases regardless of how
the URL changes.
Note: The browserUrlChange event
does not occur when testing applications locally using Internet Explorer. However, when run from a web
server, the event does get dispatched. That means that if you test
your application locally using Internet Explorer while developing
the application, you will not be able to use the Back and Forward
buttons or deep linking features, but it will work when deployed on
a web server. Consider testing using another browser, such as
Firefox.
In this section, we'll look at a simple example application that uses
BrowserManager to enable deep linking
and integration with the browser's Back and Forward buttons. The
application merely consists of four simple MXML application components
corresponding to four screens or pages within the application, and a
navigational button bar for navigating between the screens. The four
screens are called Home, Books, Authors, and Events.
We'll create these four components first. Three of the four
components will consist of nothing more than a label component. One of
them will contain an accordion component, and we'll later see how to
integrate that into BrowserManager as
well. You should define the Home screen component in HomeScreen.mxml using the code shown in Example 20-1.
Example 20-1. HomeScreen.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label text="Thank you for visiting O'Reilly's Flex site" />
</mx:Canvas>
Next, you can define the Books screen in BooksScreen.mxml, as shown in Example 20-2.
Example 20-2. BooksScreen.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label text="O'Reilly books catalog" />
</mx:Canvas>
The Authors screen is defined in AuthorsScreen.mxml, as shown in 20-3. This is the screen with the accordion.
Example 20-3. AuthorsScreen.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Accordion id="authorsAccordion" width="400" height="400">
<mx:VBox label="Joey Lott" />
<mx:VBox label="Chafic Kazoun" />
</mx:Accordion>
</mx:Canvas>
The Events screen is defined in EventsScreen.mxml, as shown in 20-4.
Example 20-4. EventsScreen.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Label text="Events this month" />
</mx:Canvas>
This excerpt is from Programming Flex 3. If you want to try your hand at developing rich Internet applications with Adobe's Flex 3, and already have experience with frameworks such as .NET or Java, this is the ideal book to get you started. Programming Flex 3 gives you a solid understanding of Flex 3's core concepts, and valuable insight into how, why, and when to use specific Flex features. Learn to get the most from this amazing and sophisticated technology.
Now we can assemble all the screens in the main application MXML file with a navigational button bar, as shown in 20-5.
Example 20-5. Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
creationComplete="creationCompleteHandler();" xmlns:local="*" currentState="Home">
<mx:Script>
<![CDATA[
import mx.core.UIComponent;
import mx.collections.ArrayCollection;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.events.BrowserChangeEvent;
import mx.events.ItemClickEvent;
private var _browserManager:IBrowserManager =
BrowserManager.getInstance();
private var _navigationData:ArrayCollection;
private function creationCompleteHandler():void {
_navigationData = new ArrayCollection();
_navigationData.addItem({section: "Home",
title: "O'Reilly Publishing", component: "homeScreen"});
_navigationData.addItem({section: "Books",
title: "O'Reilly Publishing - Our Catalog", component: "booksScreen"});
_navigationData.addItem({section: "Authors",
title: "O'Reilly Publishing - Meet the Authors", component: "authorsScreen"});
_navigationData.addItem({section: "Events",
title: "O'Reilly Publishing - Current Events", component: "eventsScreen"});
navigation.dataProvider = _navigationData;
_browserManager.init("Home", _navigationData.getItemAt(0).title);
}
private function itemClickHandler(event:ItemClickEvent):void {
}
]]>
</mx:Script>
<mx:VBox>
<mx:ToggleButtonBar id="navigation" labelField="section"
itemClick="itemClickHandler(event);" />
<mx:Canvas id="sections" />
</mx:VBox>
<mx:states>
<mx:State name="Home">
<mx:AddChild relativeTo="{sections}">
<local:HomeScreen id="homeScreen" />
</mx:AddChild>
</mx:State>
<mx:State name="Books">
<mx:AddChild relativeTo="{sections}">
<local:BooksScreen id="booksScreen" />
</mx:AddChild>
</mx:State>
<mx:State name="Authors">
<mx:AddChild relativeTo="{sections}">
<local:AuthorsScreen id="authorsScreen" />
</mx:AddChild>
</mx:State>
<mx:State name="Events">
<mx:AddChild relativeTo="{sections}">
<local:EventsScreen id="eventsScreen" />
</mx:AddChild>
</mx:State>
</mx:states>
</mx:Application>
In this code, we define an ArrayCollection called _navigationData, and we add four elements to
it. Each element corresponds to a screen in the application. Each
element has three properties: section, title, and component. The section corresponds to the name of the state
for the screen, the title is the page
title, and the component is the ID of
the screen component instance. Then we assign the _navigationData collection to the dataProvider property of the ToggleButtonBar instance. This will create
four buttons corresponding to the four screens.
At this point, nothing happens when you click the buttons because
we haven't defined the behavior. Typically, if you wanted to change the
state when the user clicked on a button, you would simply set the
currentState property. However, in
this case we want to route all requests for state changes through
BrowserManager. That means we need
to call setFragment()
instead. And that means the new, revised method now looks
like the following:
private function itemClickHandler(event:ItemClickEvent):void {
_browserManager.setFragment(event.item.section);
}
This code sets the fragment to the value of the section property of the dataProvider element corresponding to the
button. The result is that the fragment will be one of the following:
Home, Books, Authors, or Events, which just happen to also correspond to
the names of the states.
If you were to test the application at this point, you'd see that
the fragment does indeed update when you click the buttons, but the
application state doesn't change. To change the application state we
need to handle the applicationUrlChange event. We can do that by
first registering a listener for the event in the creationCompleteHandler() method with the
following code:
_browserManager.addEventListener(BrowserChangeEvent.APPLICATION_URL_CHANGE, urlChangeHandler);
Then we need only to define the urlChangeHandler() method. This new method
looks like the following:
private function urlChangeHandler(event:BrowserChangeEvent):void {
var fragment:String = _browserManager.fragment;
var item:Object;
for(var i:int = 0; i < _navigationData.length; i++) {
if(_navigationData.getItemAt(i).section == fragment) {
item = _navigationData.getItemAt(i);
navigation.selectedIndex = i;
}
}
_browserManager.setTitle(item.title);
currentState = item.section;
}