Page Stack - Navigate by Page Name
Building a navigation system in Flex is harder than it should be. Trying to figure out how to decouple your navigation model from the view is unintuitive. ViewStack is the obvious choice for it, but it leaves you with only two options, neither of which is good.
-
Use
selectedIndex- You can throw your pages/containers in aViewStackand store the currently selected page index in a model. This works great, except that your model is coupled to the order of the pages in theViewStack. You can store the indices in constants, but if someone adds a new page in there, it will throw off all the indices. -
Use
selectedChild- You can mitigate the index problem by storing theselectedChildproperty on your model, but then your model has a reference to a view. Yuck.
The solution - Page Stack
This simple component allows you to store the name of the selected page. You can set the page. You can then store a string on your model that you bind to the selectedPage property of PageStack. If you set the name on each child of the PageStack, they’ll match up.
MyView.mxml
<components:PageStack selectedPage="{navigation.selectedPage}">
<mx:Canvas name="{Navigation.FIRST}"/>
<mx:Canvas name="{Navigation.SECOND}"/>
<mx:Canvas name="{Navigation.THIRD}"/>
</components:PageStack>
<mx:Button label="Go to Page 3" click="navigation.selectedPage = Navigation.THIRD"/>
Navigation.as
public class Navigation
{
public static const FIRST:String = "first";
public static const SECOND:String = "second";
public static const THIRD:String = "third";
[Bindable]
public var selectedPage:String = FIRST;
}
And here’s the source!
package net.seanhess.components
{
import flash.display.DisplayObject;
import mx.containers.ViewStack;
import mx.core.Container;
public class PageStack extends ViewStack
{
protected var pages:Object = {};
protected var newChildren:Boolean = false;
override public function addChildAt(child:DisplayObject, index:int) : DisplayObject
{
newChildren = true;
invalidateProperties();
return super.addChildAt(child, index);
}
override protected function commitProperties() : void
{
super.commitProperties();
if (newChildren)
{
newChildren = false;
pages = {};
for each (var child:DisplayObject in getChildren())
{
var name:String = child.name;
pages[name] = child;
}
}
}
public function set selectedPage(value:String):void
{
var child:Container = pages[value] as Container;
if (!child)
throw new Error("Could not find page: " + value);
selectedChild = child;
}
public function get selectedPage():String
{
return selectedChild.name;
}
}
}





