Programming Flex 3: Chapter 20, Embedding Flex Applications in a Browser
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9
This code loops through the elements in the _navigationData collection to find the one
that corresponds to the fragment. It then sets the page title and the
current state for the application.
Note: Remember that with some browsers you will see the correct behavior only when running the application from a web server.
At this point, the application will allow you to click the buttons
to navigate to different sections. However, if you try to use deep
linking or the browser's Back button, you will find that neither one
works. That is because the application is handling only the event. To enable
the Back button and deep linking features all you need to do is handle
the browserUrlChange event in the
same way you handled the applicationUrlChange event. Therefore, you
need to add only one line of code to the creationCompleteHandler() method:
_browserManager.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, urlChangeHandler);
In the preceding section, you saw how to build an application in
which BrowserManager mediated all
state changes at the application level. However, you might want to build
an application that has state changes occurring within screens, not just
between them. In this section, we'll continue the example application
from the previous section. We'll enable state changes in the accordion
component on the Authors screen to be managed by BrowserManager.
The first change we'll make is to change the URL fragment when the user clicks on an accordion section. Example 20-6 shows these changes to AuthorsScreen.mxml.
Example 20-6. AuthorsScreen.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.BrowserChangeEvent;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
private var _browserManager:IBrowserManager =
BrowserManager.getInstance();
private function changeAuthorHandler(event:Event):void {
_browserManager.setFragment("Authors/" +
authorsAccordion.selectedIndex);
}
]]>
</mx:Script>
<mx:Accordion id="authorsAccordion" width="400" height="400"
change="changeAuthorHandler(event);">
<mx:VBox label="Joey Lott" />
<mx:VBox label="Chafic Kazoun" />
</mx:Accordion>
</mx:Canvas>
You can see that when the user clicks on an accordion section the
URL fragment updates to Authors/0 or
Authors/1 depending on which section
the user clicks.
If you run the application now, you'll see that clicking on one of
the accordion sections actually causes an error. That's because Authors/0 and Authors/1 cannot be found in the navigational
data at the application level. Therefore, we need to make a change to
the urlChangeHandler() method in the
application MXML file. Instead of simply using the fragment as is, we'll
extract each piece using the slash as the delimiter. Example 20-7 shows the changes.
Example 20-7. Updated urlChangeHandler()
private function urlChangeHandler(event:BrowserChangeEvent):void {
var fragment:Array = _browserManager.fragment.split("/");
var item:Object;
for(var i:int = 0; i < _navigationData.length; i++) {
if(_navigationData.getItemAt(i).section == fragment[0]) {
item = _navigationData.getItemAt(i);
navigation.selectedIndex = i;
}
}
_browserManager.setTitle(item.title);
currentState = item.section;
}
Now the application works again without error. However, it still
doesn't handle state changes within the Authors screen correctly when
the user clicks the Back or Forward button or uses deep linking. There
are lots of strategies for how to handle setting state in these cases.
We'll tackle the issue by defining an interface called IScreen that will allow fragment data to be
passed to screens from the application level. Example 20-8 shows IScreen.
Example 20-8. IScreen.as
package {
public interface IScreen {
function setScreenFragment(value:String):void;
}
}
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.
Next we'll update AuthorsScreen.mxml to implement IScreen. Example 20-9 shows the new
AuthorsScreen.mxml.
Example 20-9. AuthorsScreen.mxml implementing IScreen
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" implements="IScreen">
<mx:Script>
<![CDATA[
import mx.events.BrowserChangeEvent;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
[Bindable]
private var _accordionIndex:int;
private var _browserManager:IBrowserManager =
BrowserManager.getInstance();
public function setScreenFragment(value:String):void {
if(value == "") {
_accordionIndex = 0;
}
else {
_accordionIndex = parseInt(value);
}
}
private function changeAuthorHandler(event:Event):void {
_browserManager.setFragment("Authors/" +
authorsAccordion.selectedIndex);
}
]]>
</mx:Script>
<mx:Accordion id="authorsAccordion" width="400" height="400"
change="changeAuthorHandler(event);" selectedIndex="{_accordionIndex}">
<mx:VBox label="Joey Lott" />
<mx:VBox label="Chafic Kazoun" />
</mx:Accordion>
</mx:Canvas>
All we did was implement IScreen, and in the setScreenFragment() method we parsed the index
value and assigned it to a bindable _accordionIndex property, which will set the
accordion's selectedIndex
correctly.
Next we need to update the urlChangeHandler() method of the application
again. This time we'll test whether the selected screen implements
IScreen, and if it does we'll pass
along the fragment. Example 20-10 shows this new
code.
Example 20-10. Updated urlChangeHandler()
private function urlChangeHandler(event:BrowserChangeEvent):void {
var fragment:Array = _browserManager.fragment.split("/");
var item:Object;
for(var i:int = 0; i < _navigationData.length; i++) {
if(_navigationData.getItemAt(i).section == fragment[0]) {
item = _navigationData.getItemAt(i);
navigation.selectedIndex = i;
}
}
_browserManager.setTitle(item.title);
currentState = item.section;
var screen:UIComponent = this[item.component];
if(screen is IScreen) {
(screen as IScreen).setScreenFragment(fragment[1]);
}
}
If you test the application, you'll see that you can navigate between the accordion sections using the Back and Forward browser buttons.
One of the big drawbacks of BrowserManager is that Adobe has tied BrowserManager to the Flex HTML templates.
Therefore, if you use BrowserManager,
the easiest way to deploy the application is to use the Flex HTML
template. As we stated earlier in this chapter, the Flex HTML templates
are not ideal, and we generally advise that you not use them, if
possible. However, in this case, using the Flex templates is the
simplest solution. You need to use one of the templates with history management enabled. Then, when you deploy
the application, you need to deploy the HTML file, the .swf file, and the history directory containing history.js,
history.css, and historyFrame.html. If you omit any of those
files, the application will not work correctly.
Because we think that SWFObject is a far better way to embed Flex applications,
we think it's important to explain how to use BrowserManager applications with SWFObject as
well. Although it is possible, it does require that you make a few edits
to the JavaScript code provided
by Adobe. This is not due to any failure on the part of SWFObject, but
rather because of oversights in the history.js code.
When embedding a BrowserManager
application using SWFObject, you should embed the application normally.
In addition to the normal HTML and JavaScript code, you'll need to
include history.css and history.js. An example that does this
follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Flex Example</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="swfobject.js"></script>
<link rel="stylesheet" type="text/css" href="history/history.css"/>
<script src="history/history.js" language="javascript"></script>
<script type="text/javascript">
swfobject.registerObject("flexApplication", "9.0.0");
</script>
</head>
<body>
<div>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
width="400" height="400" id="flexApplication">
<param name="movie" value="Example.swf" />
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="Example.swf"
width="400" height="400">
<!--<![endif]-->
<param name="allowScriptAccess" value="always" />
<p>This site is best viewed as a Flex application, which requires
Flash Player 9. For users who prefer not to use Flash Player
we have provided a <a href='textVersion.html'>text-only
version of the site</a/>.</p>
<!--[if !IE]>-->
</object>
<!--<![endif]-->
</object>
</div>
</body>
</html>