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);

Enabling BrowserManager to Manage Granular States

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.

buy button

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.

Deploying BrowserManager Flex Applications

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>

Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9

Next Pagearrow