Changing the URL in the browser’s address bar does not
necessarily provide you with deep linking functionality. For example,
loading a bookmarked URL that specifies the panel would not start
the application on that panel. You must add code to the application
that parses the URL so that the application’s state reflects the
URL.
In this case, you add a listener for the browserURLChange event.
In that listener, you parse the URL and set the application state
according to the results. For example, if the URL includes a fragment
such as panel=2, then you write code that sets
the current panel with the selected index of 2.
The browserURLChange event is not triggered
when the application first loads. As a result, you must also check
the URL on startup with the application’s creationComplete event,
and trigger the parsing before the application finishes being rendered
on the screen.
The following is a simple example that sets the value of the
Accordion’s selectedIndex property to the value
of the index fragment in the URL. You request this
application by setting the value of the index fragment
on the URL, as the following example shows:
http://www.myurl.com/InitFrag.html#index=1
When the application starts up, the Accordion is opened to the
panel corresponding to the value of the index fragment:
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/InitFrag.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init(event);">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.managers.BrowserManager;
import mx.managers.IBrowserManager;
import mx.events.BrowserChangeEvent;
import mx.utils.URLUtil;
private var bm:IBrowserManager;
private function init(e:Event):void {
bm = BrowserManager.getInstance();
bm.init("", "Welcome!");
parseURL(e);
}
[Bindable]
private var indexFromURL:int;
private function parseURL(e:Event):void {
var o:Object = URLUtil.stringToObject(bm.fragment);
indexFromURL = o.index;
}
]]>
</fx:Script>
<mx:Accordion selectedIndex="{indexFromURL}">
<mx:VBox label="Panel 1">
<mx:Label text="Accordion container panel 1"/>
</mx:VBox>
<mx:VBox label="Panel 2">
<mx:Label text="Accordion container panel 2"/>
</mx:VBox>
<mx:VBox label="Panel 3">
<mx:Label text="Accordion container panel 3"/>
</mx:VBox>
</mx:Accordion>
</s:Application>
The following example expands on the example from Updating the URL. It reads the URL on startup, and opens the application
to the first, second, or third panel, depending on the value of
the panel fragment. It also sets the title of the
HTML page according to which panel is opened.
<?xml version="1.0" encoding="utf-8"?>
<!-- deeplinking/TabNavExample.mxml -->
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="initApp()"
height="250"
width="500">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import mx.events.BrowserChangeEvent;
import mx.managers.IBrowserManager;
import mx.managers.BrowserManager;
import mx.utils.URLUtil;
public var browserManager:IBrowserManager;
private function initApp():void {
browserManager = BrowserManager.getInstance();
browserManager.addEventListener(BrowserChangeEvent.BROWSER_URL_CHANGE, parseURL);
browserManager.init("", "Shipping");
}
private var parsing:Boolean = false;
private function parseURL(event:Event):void {
parsing = true;
var o:Object = URLUtil.stringToObject(browserManager.fragment);
if (o.view == undefined)
o.view = 0;
tn.selectedIndex = o.view;
browserManager.setTitle((tn.selectedIndex == 0) ? "Shipping" : "Receiving");
tn.validateNow();
var details:Boolean = o.details == true;
if (tn.selectedIndex == 0)
shipDetails.selected = details;
else
recvDetails.selected = details;
parsing = false;
}
private function updateURL():void {
if (!parsing)
callLater(actuallyUpdateURL);
}
private function actuallyUpdateURL():void {
var o:Object = {};
var t:String = "";
if (tn.selectedIndex == 1) {
t = "Receiving";
o.view = tn.selectedIndex;
if (recvDetails.selected)
o.details = true;
} else {
t = "Shipping";
o.view = tn.selectedIndex;
if (shipDetails.selected)
o.details = true;
}
var s:String = URLUtil.objectToString(o);
browserManager.setFragment(s);
browserManager.setTitle(t);
}
]]>
</fx:Script>
<mx:TabNavigator id="tn" change="updateURL()" width="300">
<mx:Panel label="Shipping">
<mx:CheckBox id="shipDetails" label="Show Details" change="updateURL()" />
</mx:Panel>
<mx:Panel label="Receiving">
<mx:CheckBox id="recvDetails" label="Show Details" change="updateURL()" />
</mx:Panel>
</mx:TabNavigator>
</s:Application>
This example has one major drawback: it does not “remember” the
state of the panel that is not in the current view. If you copy
the bookmark and open it in a new browser, the view that you were
last looking at, and the state of the CheckBox on that view, are
maintained. However, the CheckBox in the other view that was hidden
is reset to its original value (unchecked). There are several techniques
to solve this issue. For more information, see Using deep linking with navigator containers.