Adobe Flex 3 Help

Using the HistoryManager

The Flex History Manager lets users navigate through a Flex application by using the web browser's back and forward navigation commands. For example, a user can navigate through several Accordion container panes in a Flex application, and then click the browser's Back button to return the application to its previous states.

The HistoryManager class provides a subset of functionality that is provided by the BrowserManager class and deep linking. In general, you should use the BrowserManager class and deep linking for maintaining state in an application and manipulating URLs and browser history, but the HistoryManager class can be useful under some circumstances, such as if you are maintaining a Flex 2.x application. For more information about deep linking and the BrowserManager class, see About deep linking.

History management is implemented as a set of files that are referenced in the application's wrapper. By default, Adobe Flex Builder generates a wrapper that supports history management, but you can disable it. When you deploy an application that uses the HistoryManager, you must also deploy the history management files such as history.css, history.js, and historyFrame.html. These are the same files that are used by the BrowserManager for deep linking support. For more information, see Deploying applications that use deep linking.

History management is automatically supported by the Accordion and TabNavigator navigator containers. You can also use the HistoryManager class in ActionScript to provide custom history management for other objects in an application. History management is disabled by default for the ViewStack navigator container.

When history management is enabled, as the user navigates within different navigator containers in an application, each navigation state is saved. Selecting the web browser's Back or Forward button displays the previous or next navigation state that was saved. History management keeps track of where you are in an application, but it is not an undo and redo feature that remembers what you have done.

Note: When history management is enabled for a particular component, such as a navigator container, only the state of the navigator container is saved. The state of any of the navigator container's child components is not saved unless history management is specifically added for that component.

Using standard history management

You can disable or enable history management for a navigator container by setting the container's historyManagementEnabled property to false or true, respectively. The following example shows a TabNavigator container with history management disabled:

<mx:TabNavigator historyManagementEnabled="false">

Note: When writing an application that uses deep linking, you cannot use the HistoryManager class. The deep linking functionality automatically sets the application's historyManagementEnabled property to false.

In the following example, the user's panel selections are saved for the first Accordion container because it uses default settings, but the second Accordion container has the historyManagementEnabled property explicitly set to false. When the user selects the web browser's back or forward command, the previous or next state is displayed for the first container, but not for the second.

<?xml version="1.0"?>
<!-- historymanager/DisableHistoryManagement.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600" height="800">

  <!-- History management is enabled by default for this Accordion. -->
  <mx:Accordion width="100%" height="50%">
     <mx:VBox label="History management is ENABLED">
        <mx:TextInput text="View 1"/>
     </mx:VBox>
     <mx:VBox label="View 2">
        <mx:TextInput text="View 2"/>
     </mx:VBox>
  </mx:Accordion>

  <!-- History management is disabled for this Accordion. -->
  <mx:Accordion historyManagementEnabled="false" width="100%" height="50%">
     <mx:VBox label="History management is DISABLED.">
        <mx:TextInput text="View 1"/>
     </mx:VBox>
     <mx:VBox label="View 2">
        <mx:TextInput text="View 2"/>
     </mx:VBox>
  </mx:Accordion>
</mx:Application>

The executing SWF file for the previous example is shown below:

You can disable history management for an entire application by setting the value of the historyManagementEnabled property to false on the <mx:Application> tag. When you initialize the BrowserManager to use deep linking, Flex does this for you.

Using custom history management

You can make any custom component history management-aware by performing the following operations on that component:

  1. Implement the mx.managers.IHistoryManagerClient interface.
  2. Register the component with the HistoryManager's register() method.
  3. Save the component's state when its state has changed.
  4. Implement the saveState() and loadState() methods of the IHistoryManagerClient interface. These methods have the following signatures:
    public function saveState():Object
    public function loadState(state:Object):void;
    
    

These steps are described in more detail in the following sections.

Implementing the IHistoryManagerClient interface

To implement the IHistoryManagerClient interface, you can use the implements tag attribute; for example:

<mx:CheckBox 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    implements="mx.managers.IHistoryManagerClient" 
    ...
>

Registering components with the HistoryManager

To register a component with the HistoryManager class, you call the HistoryManager class's register() method with a reference to a component instance that implements the IHistoryManagerClient interface; for example:

<mx:CheckBox 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        implements="mx.managers.IHistoryManagerClient" 
        creationComplete="mx.managers.HistoryManager.register(this);"
>

You typically do this when the component has finished initialization.

Saving the component's state

You save the state of the component when its state has changed so that the history manager has a state that it can return to. You typically do this in an event handler by calling the static HistoryManager.save() method.

The following example calls the boxChanged() method in the change event handler:

<mx:CheckBox 
    xmlns:mx="http://www.adobe.com/2006/mxml"
    implements="mx.managers.IHistoryManagerClient" 
    creationComplete="mx.managers.HistoryManager.register(this);"
    change="boxChanged(event)">
    <mx:Script><![CDATA[
        import mx.managers.HistoryManager;
        ...

        // Saves the box's current state.
        private function boxChanged(e:Event):void {
            HistoryManager.save();
        }            
    ]]></mx:Script>
</mx:CheckBox>

Implementing the loadState() and saveState() methods

To use the HistoryManager class for a registered component, you must implement the IHistoryManagerClient interface and include saveState() and loadState() methods to save and load the state information you want. The saveState() method returns an object that contains property:value pairs that represent the current navigation state of a component.

The HistoryManager class contains a load() method that calls the loadState() method for each registered component with an object identical to the one that the saveState() method returns.

Components that implement IHistoryManagerClient also must implement the loadState() method; components that extend UIComponent automatically inherit the loadState() method.

. The following example implements the loadState() and saveState() methods for a custom CheckBox control:

<?xml version="1.0"?>
<!-- historymanager/MyCheckBox.mxml -->
<mx:CheckBox 
     xmlns:mx="http://www.adobe.com/2006/mxml"
     label="Check me" 
     selected="false"
     implements="mx.managers.IHistoryManagerClient" 
     creationComplete="mx.managers.HistoryManager.register(this);"
     change="boxChanged(event)">

  <mx:Script><![CDATA[
        import mx.managers.HistoryManager;
        
        // Returns an object that contains property:value pairs that 
        // represent the current navigation state of a component.
        public function saveState():Object {
           return {selected:selected};
        }

        // Sets the selected property, depending on the state.
        public function loadState(state:Object):void {
           var newState:Boolean = state;

           if (newState != selected) {
            selected = newState;
           } else {
            if (newState) {
                selected = false;
            } else {
                selected = true;
            }
           }
        }
        
        // Saves the box's current state.
        private function boxChanged(e:Event):void {
           HistoryManager.save();
        }       
  ]]></mx:Script>

</mx:CheckBox>

The application that uses this control might look like the following (if the MXML files are in the same directory):

<?xml version="1.0"?>
<!-- historymanager/CheckBoxApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*">

  <local:MyCheckBox/>

</mx:Application>

The executing SWF file for the previous example is shown below:

When the user checks and unchecks the custom CheckBox control, they can use the browser's forward and back buttons to return to the previous state of the control.

An application's total navigation state is limited to the maximum URL size supported by the user's web browser, so you should write the saveState() method for a component to save the least amount of data possible. For example, you can write a saveState() method for a List control that saves just the selectedIndex property.

Using history management with a list-based control control

When using history management with a list-based control, you typically save the selected index of the control, and use that index to determine the state.

The following example is an MXML component, HistoryList.mxml, that registers with the HistoryManager and implements the saveState() and loadState() methods. The component lets the user browse through a List control.

<?xml version="1.0"?>
<!-- historymanager/HistoryList.mxml -->
<mx:List xmlns:mx="http://www.adobe.com/2006/mxml" 
  creationComplete="initList()" 
  change="listChanged()" 
  implements="mx.managers.IHistoryManagerClient"
>
  <mx:Script><![CDATA[
     import mx.managers.HistoryManager;

     // Register with the HistoryManager.
     private function initList():void {
        HistoryManager.register(this);
     }

     // Saves the application's current state.
     private function listChanged():void {
        HistoryManager.save()
     }

     // Save the List index.
     public function saveState():Object {
        return { selectedIndex: selectedIndex };
     }

     // Load the List index.
     public function loadState(state:Object):void {
        var newIndex:int = state ? int(state.selectedIndex) : -1;
        if (newIndex != selectedIndex)
        selectedIndex = newIndex;
     }
  ]]></mx:Script>
</mx:List>

The following example shows an application file that uses the HistoryList.mxml component.

<?xml version="1.0"?>
<!-- historymanager/HistoryListApp.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
xmlns:local="*" width="400" height="400" verticalGap="20">

    <mx:Script>
        <![CDATA[

            [Bindable]
            private var listData:Array = ["Flex", "Dreamweaver", 
                "Flash", "Breeze", "Contribute"];
        ]]>
    </mx:Script>

    <local:HistoryList id="list1" dataProvider="{listData}"
        width="120" height="120"/>

    <mx:TextInput id="text1" 
        text="{list1.selectedItem? list1.selectedItem : ''}"/>
</mx:Application>

The executing SWF file for the previous example is shown below:

In this example, you populate the HistoryList control with an Array of Strings. As you select an item in the HistoryList control, it also appears in the TextInput control. Use the browser's back button to cycle back through your selections.

Calling the HistoryManager class's static methods

When you use a ViewStack, Accordion, or TabNavigator container, the HistoryManager's save() method is invoked automatically when the user navigates through an application. When you register a component with the HistoryManager class, you must explicitly call the HistoryManager save() method to save the state of the component.

The save() method and the register() and unregister() methods, which let you register and unregister a component, are static methods that you can call from your ActionScript code. The following table describes these methods:

Method

Description

register(component)

Registers a component with the HistoryManager class; for example:

HistoryManager.register(myList);
save()

Saves the current navigation state of all components registered with the HistoryManager class; for example:

HistoryManager.save();
unregister(component)

Unregisters a component from the HistoryManager class; for example:

HistoryManager.unregister(myList);