Switch On The Code RSS Button - Click to Subscribe
May
29

Flex BrowserManager - Browser History and the Back Button Fun

flex icon

So, how many times have you and I read something on the web that says you shouldn't use Flash/Flex because it breaks the back button? Well I for one say fooey to this. Today I am going to show you how to fix the back button in Flex 3 and add states to the browser history. Inside the Flex 3 framework there is a nice gem that can be used, it is a singleton (for more info check out our Singleton Tutorial) class called BrowserManager. This class allows us to change the url and receive notices when the user or browser changes the url.

So let's take a look at the example that we are going to build today. Below we have a simple application that have three buttons in the docked control bar at the top of the application area. Each of these buttons will change the color of the main area. But the magic happens when each one of these buttons is pressed you will notice the url in the browser also updates. It will change the ending of the url to reflect the current index of the selected area. You should now also be able to use your back button to go back to previously selected areas. Now the amazing thing is how simple it is to do this. Easier than doing this by using straight Javascript that is for sure. Ok, take a minute and play around. You can also examine and grab the BrowserManager Example Source.



Tackling the UI

First on our todo list is creating the basic ui. Our user interface is fairly basic. There are two main pieces to it. The ApplicationControlBar and the ViewStack are the two main UI components. Inside of the ViewStack we have three Canvas components with colorful backgrounds and labels. The ApplicationControlBar has a ToggleButtonBar inside which has its data provider set to the view stack, you can learn more about this at our ViewStack Tutorial. The basic code lies below.

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

  <mx:ApplicationControlBar dock="true"
    horizontalAlign="center">

    <mx:ToggleButtonBar dataProvider="{vs}"/>
  </mx:ApplicationControlBar>
  <mx:ViewStack id="vs" width="100%" height="100%">
    <mx:Canvas label="Area Uno" backgroundColor="#FF0000"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Uno"/>

    </mx:Canvas>
    <mx:Canvas label="Area Dos" backgroundColor="#00FF00"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Dos"/>

    </mx:Canvas>
    <mx:Canvas label="Area Tres" backgroundColor="#0000FF"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Tres"/>

    </mx:Canvas>
  </mx:ViewStack>
</mx:Application>

Adding the Correct Files

In order to get all the BrowserManager code to work we need to add some Javascript to the page which is used by the class to update the url and get the url. So, this means that the BrowserManager will not work if the end user doesn't have Javascript enabled. There is also a css file, which comes with the Flex framework, to include in the header. First, we look at the addition to html head for the css style.

<link rel="stylesheet" type="text/css" href="http://yoururl.com/history/history.css" />

The second piece is adding the Javascript script source. This Javascript file is one that comes standard with the Flex framework written by the Flex team. It does all the behind the scenes work for the BrowserManager. This is done simply with a html script tag which references a Javascript source file.

<script src="/files/history/history.js" language="javascript"></script>

This takes care of the items that are needed along the flash file for using the BrowserManager correctly.

Updating The Url

To update the browser url we first need to create a variable to hold our BrowserManager but there is one interesting tidbit here, the BrowserManager.getInstance() returns an IBrowserManager which means our variable needs to be of type, IBrowserManager. We also need to hook into the creationComplete event, in my case the function is named init. I will explain the function after the code, also here is the updated application opening tag.

<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="absolute" width="400" height="300"
  creationComplete="init()">

The script tag.

<mx:Script>
    <![CDATA[
      import mx.managers.IBrowserManager;
      import mx.managers.BrowserManager;
     
      private var browserManager:IBrowserManager;
     
      private function init():void
      {
        browserManager = BrowserManager.getInstance();
        browserManager.init("");
      }
    ]]>
  </mx:Script>

Now the crazy thing is that the BrowserManager also has a init which we call to get everything setup for updating and reading the browser url. We pass in a blank string to initialize the value of the url fragment (the end piece of the url, in our case is always #...). You also have the option of passing in a start value for the title of the page.

To actually do some updating we are going to hook into the change event on the our viewStack. I named this function updateUrl. This function will be a single call to the setFragment function on the IBrowserManager instance that we have. All we need to pass to the setFragment function is what to set the url fragment to. Which in our case we set it equal to "a=" and the current index of the view stack child that is showing. This updates the url in the browser and correspondingly adds a browser history state.

private function updateUrl():void
{
  browserManager.setFragment("a=" + vs.selectedIndex);
}

Parsing the Url

Next in line is actually using the url information that we are given. To begin using this information we need to add an event listener to the browser url change event, which we are going to do inside our init function. The updated init function is below.

private function init():void
{
  browserManager = BrowserManager.getInstance();
  browserManager.addEventListener(
    BrowserChangeEvent.BROWSER_URL_CHANGE,
    parseUrl
  )
  browserManager.init("");
}

As you can see above we named our handler function parseUrl. This function is going to take the fragment of the url and turn it into an object using the URLUtil class and its function stringToObject. We then set the selectedIndex of our view stack to the value we get from the url. The function code follows.

private function parseUrl(e:BrowserChangeEvent = null):void
{
  var o:Object =
    URLUtil.stringToObject(browserManager.fragment);
  vs.selectedIndex = o.a;
}

The final piece is that we manually call parseUrl at the end of the init function to make sure when the application is opened it goes to the correct view stack child. This completes all the code needed for this tutorial. The entire application code is below.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
  xmlns:mx="http://www.adobe.com/2006/mxml"
  layout="absolute" width="400" height="300"
  creationComplete="init()">

  <mx:Script>
    <![CDATA[
      import flash.net.navigateToURL;
      import mx.events.BrowserChangeEvent;
      import mx.utils.URLUtil;
      import mx.managers.IBrowserManager;
      import mx.managers.BrowserManager;
     
      private var browserManager:IBrowserManager;
     
      private function init():void
      {
        browserManager = BrowserManager.getInstance();
        browserManager.addEventListener(
          BrowserChangeEvent.BROWSER_URL_CHANGE,
          parseUrl
        )
        browserManager.init("");
        parseUrl();
      }
     
      private function
        parseUrl(e:BrowserChangeEvent = null):void
      {
        var o:Object =
          URLUtil.stringToObject(browserManager.fragment);
        vs.selectedIndex = o.a;
      }
     
      private function updateUrl():void
      {
        browserManager.setFragment("a=" + vs.selectedIndex);
      }
    ]]>
  </mx:Script>

  <mx:ApplicationControlBar dock="true"
    horizontalAlign="center">

    <mx:ToggleButtonBar dataProvider="{vs}"/>
  </mx:ApplicationControlBar>
  <mx:ViewStack id="vs" width="100%" height="100%"
    change="updateUrl()">

    <mx:Canvas label="Area Uno" backgroundColor="#FF0000"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Uno"/>

    </mx:Canvas>
    <mx:Canvas label="Area Dos" backgroundColor="#00FF00"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Dos"/>

    </mx:Canvas>
    <mx:Canvas label="Area Tres" backgroundColor="#0000FF"
      width="100%" height="100%">

      <mx:Label x="75" y="100"
        fontSize="22" text="Area Tres"/>

    </mx:Canvas>
  </mx:ViewStack>
</mx:Application>

That finishes today's tutorial. I hope everyone can take away something useful. One note, this will not work as is in IE6, at least in the version I tested. I am working on a workaround for this - if someone needs IE6 to work let me know and I will publish the fix(es). If anyone has any comments, questions, or suggestions just drop a line.



Posted in Flex, All Tutorials by The Fattest |

6 Responses

  1. Jason The Saj Says:

    Greetings,

    Not sure if you’re dealing with external interface and such issues in your browser compatibility.

    But I dealt with a number of issues in that region for handling “_blank”. Perhaps something insightful might be found in my research of that issue to help facilitate your working in IE. I was rather shocked to discover that such settings as wmode= transparent or opaque would actually make a difference in unrelated areas.

    http://thesaj.wordpress.com/2008/02/12/the-nightmare-that-is-_blank-part-ii-help/

    - The Saj

  2. amar shukla Says:

    hey it does’nt work as what you said …if we change the address manually in browser only then its possible to get back page using back button of IE

  3. The Fattest Says:

    amar, I said it doesn’t work in IE in the last paragraph

  4. amar shukla Says:

    ok fine buddy …it was my mistake .. ;)

  5. Omid Says:

    This blog is very cool :)
    But it seems doesn`t have CSS maintenance !

  6. Junior Infante Says:

    I wanted to know why this does not work in IE6. What changes had to be made in order for this to work?
    Great site

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

Powered by WP Hashcash