Publishers of technology books, eBooks, and videos for creative people

Home > Blogs > Making Bookmark-able Flex Applications

Making Bookmark-able Flex Applications

One of the tricks to Rich Internet Applications is getting them to handle standard user requests in the same way as basic Web pages. One such issue involves making a Flash application respond appropriately when the user uses the back and forward buttons, the browser history, and their bookmarks. I'll tell you exactly how to do that in this post.

With a standard HTML page, unique URLs can provide links to specific content to be displayed, such as a certain product in an e-commerce site. The Web browser, which treats different URLs as different pages (even if the URL points to an anchored subsection of the page), uses the unique URLs to provide a viewing history as well as a bookmarking system. However, as a Flash application runs through a single HTML page, by default, all of the changes and activity within the Flash application will not be reflected in the URL, making it impossible to mark any specific Flash application arrangements. The solution is to use something called deep linking. Through deep linking, you can, from within a Flash application, read from and write to the fragment part of the browser's URL, the fragment being anything after a number sign. Historically, the fragment was used to point the browser to an anchored link within an HTML page, but the same principle can be applied in Flash content.

There are three key files for deep linking:

  • history.css
  • history.js
  • historyFrame.html

You should put unmodified copies—you don't even need to ever open them—of these three files in a folder named history, found in the same directory as the HTML page that will run the Flash application. If you're using Flash Builder, the IDE will do all this for you. If you're not using Flash Builder, you'll find these three files in the Flex SDK, under templates/swfobject/history.

In the HTML page that also contains the Flash application, you'll also need to include the CSS and JavaScript pages (but not the HTML frame)

<link href="history/history.css" type=";text/css" rel="stylesheet" />
script src="history/history.js" language="javascript"
And that's all you need to do special in your HTML page. Now let's look at your Flex code...

All of the relevant code will be in ActionScript, not MXML. First, you'll need to import three class definitions:

import mx.managers.BrowserManager;
import mx.managers.IBrowserManager;
import mx.events.BrowserChangeEvent;

The BrowserManager class defines the functionality. You'll use it to create an object of type IBrowserManager, which will be used to interact with the browser. The specific events to watch for are of type BrowserChangeEvent, so that definition needs to be imported, too. A BrowserChangeEvent event will occur whenever the user uses the back
and forward buttons, the browser's history, or the address bar itself to change the browser's URL.

Once you've imported the classes, you should then declare a variable of type IBrowserManager, outside of any function, that will act as the agent:

private var bMgr:IBrowserManager;

You'll want to assign a value to this variable in a function called when the application is initialized:

private function initialize():void {

bMgr = BrowserManager.getInstance();

}

The BrowserManager class's getInstance() method returns an instance of the BrowserManager class.

Next, within that same initialize() function, you'll want to invoke the init() method on the new object to start the process:

bMgr.init();

Finally, you should also add an event listener to the object to watch for URL changes:

bMgr.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, handleURLChange);

When a BROWSER_URL_CHANGE event happens, you'll want the Flex application to read in the current URL and adjust the application accordingly. But before I get to that code, let's look at how you'd create unique URLs for different application setups.

It's up to you, the developer, to decide what changes in the Flash application justify a bookmark. The submission of a form or the retrieval of some data would normally not be a logical choice, whereas the selection of a specific item (like a particular product being viewed in an e-commerce site) or navigating to a certain area would make sense. What you would do then is create event handlers for the components whose events justify the new bookmark (i.e., associate the event handler with the List, DataGrid, or navigation control). In the event handler, you first call the BrowserManager's setTitle() method to create a new page title for the current application standing:

bMgr.setTitle('Design Your Logo');

Next, call the setFragment() method, passing it a unique value for this state:

bMgr.setFragment('x=y');

If the application is currently displaying a specific product, you'd probably use the product's ID:

bMgr.setFragment('pid=2380');

If the application is showing a specific tab in a navigation component, you'd probably pass along the navigation child's id value:

bMgr.setFragment('tab=designLogo');

If you want to pass multiple pieces of information, separate each name=value pair with an ampersand:

bMgr.setTitle('Some Product Specifications');

bMgr.setFragment('pid=2380&tab=specs');

When the application calls setFragment(), the browser's URL will change automatically (Figure 1).


So that's how you alter the browser's URL to reflect changes in the application. You'll also need to create a function that reads in the browser's URL and adjusts the application accordingly. You would do this when the page first loads (like if the user came from a bookmark or direct link) or when the URL changes (from using the browser history).

The function that analyzes the URL will use a special utility to parse it, so that must be imported first:

import mx.utils.URLUtil;

Within the function, call the URLUtil class's stringToObject() method, which will parse a URL:

var fragment:Object =

URLUtil.stringToObject(bMgr.fragment, '&');

That code takes the fragment part of the URL (the part after the #) and turns it into a generic object. If the fragment contained pid=2380, then fragment.pid would have the value 2380. If the fragment contained pid=2380&tab=specs (as in the figure), then fragment.pid would equal 2380 and fragment.tab would equal specs. The application would then use this information to display the given product and tab.

So that's all there is to making your Flex-based applications respond to the user's requests (clicking back or forward, using the browser history, or otherwise changing the browser's URL) in a natural way. Once you understand the fundamentals, it's pretty straightforward; it's just up to you to decide how to use it.