For Flex 2.0 Beginners - Use the mx:States and mx:ViewStack Tags To Change The Application's View

Introduction:

As a new Flex 2.0 developer coming from using HTML, JavaScript, CSS, DHTML, and ColdFusion, how to design a Flex application was confusing. HTML, even with AJAX, is primarily a page-oriented environment. If I needed to significantly change what the users sees, I would usually have the user go to a new web page. Most HTML-based applications are a series of connected web pages.

In Flex, there is not the concept of a page. Rather, Flex has several different ways for you change the "view" of your application. In this brief tutorial for beginners, I'll introduce two Flex controls: mx:States and mx:ViewStack. These two controls can be used together to change what your users see on screen in your Flex application.

Though, the Flex 2.0 Developer's Guide contains several examples of how to use mx:States and mx:ViewStack, there are not many examples of how to use the two controls together. I think in a more complex Flex application, you're likely to use both controls.

Please note, I'm a Flex 2.0 beginner also. I've built some Flex 2.0 applications and have a good understanding of how to use most of the Flex controls and how to connect a Flex application to a ColdFusion backend. But much of my Flex 2.0 knowledge comes either from reading the documentation or discovery learning through trial-and-error. If you have a better way to use these controls, please post a comment with a link to some good examples. My primary goal in my blog is to help myself and others learn how to use Flex and ColdFusion.

References:

Flex 2.0 Developer's Guide, Chapter 27, Using View States

Flex 2.0 Developer's Guide, Using Transitions

Flex 2.0 Developer's Guide, Chapter 16, ViewStack Navigator Container

Flex 2.0 Developer's Guide, Using Behaviors

Flex 2.0 Language Reference, SetEventHandler

You can view my example application here (right click to read the source code). I've commented the source code, so between the comments and the explanations below you should be able to follow what I did.

Changing the State

My application starts with a simple login form. However, if the user is not already registered, I need a way for him to register and then login. Since the information on the registration form includes what is on the login form, I just need to make some minor changes and additions to the login form to change its "state" to a registration form.

The mx:States tag can be used to add or remove controls from a "base" state. You can also change the properties of a control. In my example, the base state is shown when the user first launches the application. The base state is a simple login form. The user can enter his username and password, press the login button, and the program will log him in. However, if the user needs to register, I've provided a Need to Register link button. When the user clicks on that button, I change the "state" of the panel that is holding the login form.


<!-- The Application class states property defines the view states. -->
    <mx:states>
    
     <!--define what needs to be added/removed when showing the register
     state-->

        <mx:State name="register" id="register">
        
         <!--change the height of the panel-->
         <mx:SetProperty target="{loginPanel}" name="height" value="300" />
        
         <!-- add some additional form elements to the login form-->
             <mx:AddChild relativeTo="{loginForm}" position="firstChild" creationPolicy="all">
             
             <mx:FormItem id="lastName" label="Last Name:">
                    <mx:TextInput/>
                </mx:FormItem>
             
         </mx:AddChild>
            
            

The click event of the registerLink linkButton calls function changeState. In function changeState, I tell the application to set the currentState equal to register. Under the mx:States tag I've created an mx:State with an id of register. Inside this mx:state tag, I change the height of the loginPanel to 300 by using the mx:SetProperty tag. I then add some additional controls using the mx:AddChild tag. I also change the label property of the loginButton to have the value of Register and also change the loginButton's click event handler to be a different function (see mx:SetEventHandler). All of these changes will be made to the base state (the base state is the view of my application that appears when the program is first launched).

So when the user clicks on the Need to Register link, all the commands defined by the tags in my register state will be executed. In addition to defining this new state, I've defined an effect to occur when the application transitions to the register state. Using the mx:transition tag, I defined the Wipe Down effect to occur whenever the state of my application changes from the base state to the register state.


<mx:transitions>
    <!-- Define a transition for changing from the base state to the register state.-->
        <mx:Transition id="toRegisterState" fromState="*" toState="register">
    
         
     <mx:WipeDown target="{loginForm}" duration="1000" />


        
     </mx:Transition>

I used the mx:states tag to make relatively minor changes to the application's appearance. If I need to make a major change, for example, all new controls, then I've found it easier to use the ViewStack tag. In my example, when the user logs in, I need to make a complete change to the view.

Changing The View

After the user successfully logs in, I want to show the user a completely new view of my application. This view would have new controls, layout, etc and would be completely different from the login form that is my base state. Though I could use a new mx:state tag to achieve this new look, using the ViewStack container is simpler.

mx:ViewStack is a navigator container. Views of your application can be "stacked" on top of each other and the user can only see and interact with the top view on the stack. After you specify an mx:ViewStack tag, a view will be created for each child container. In my example, I have defined three mx:panel tags: loginPanel, mainApplication, and secondaryApplication. So my mx:ViewStack has three child containers. The default child displayed will be the first one, loginPanel, which is also the view for my base state.


<mx:ViewStack id="appViews" width="100%" height="100%">
    
    <!--since this panel is the first child of the ViewStack it will be the default base
    state and will be what appears when the user starts the application-->

    
    <mx:Panel title="Login" id="loginPanel" horizontalScrollPolicy="off"
        verticalScrollPolicy="off" layout="absolute" width="300" height="175">

        
    </mx:Panel>
    
    <!--The application will switch to this ViewStack child after the user logs in-->
    <mx:Panel title="Main Application View" width="100%" height="100%" id="mainApplication"
    showEffect="mainApplicationWipeLeft" hideEffect="mainApplicationWipeRight">

    
    </mx:Panel>
    
    <!--The application will switch to this ViewStack child if the user clicks on the button in the
    mainApplication panel-->

    <mx:Panel title="Secondary Application View" width="100%" height="100%" id="secondaryApplication"
    showEffect="secondaryApplicationFadeIn">

    
    </mx:Panel>
    
    

You can determine when to change the view that is on the top. In my example, after the user successfully logs in, I want a completely new view. So in function login, I specify that the ViewStack control (named appViews) should make the selected child named mainApplication visible (move it to the top of the stack). On the mainApplication panel, I would have all my new controls. In my example, I use buttons to give the user the ability to change the view to the secondaryApplication panel or to logout and return to the loginPanel.

I've also defined some effects (behaviors) to play when these panels become visible or hidden. You can specify an effect to occur by using the showEffect and hideEffect attributes of the mx:panel.

Summary:

Using a combination of mx:States and mx:ViewStack can provide you with powerful tools to change the "view" of your application. My example is simple, but by studying the references above you can use these two Flex controls together to create complex Flex applications. I hope this brief tutorial and my example will help you understand better how to make the transition from designing an HTML page-based application to designing a Flex 2.0 application.

 

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Thanks for this article. I'm a developer just getting into Flex and have the basics of connecting to a cf backend and some of the Flex controls figured out. I have to say the States and ViewStack concept stumped a little at first.

You are right there is documentation around, i still think people coming from a traditional web based layout though ( new content = new page ) struggle a little with how to move through their application and which options are appropriate.

This shows clearly how to / advantages without worrying about the other bits and peices .. clear and concise :-)
# Posted By Mark | 3/11/07 4:29 AM
Hi Bruce.

You stuff is really informative. Been using your site as a learning tool for Flex. I was wondering if you had any ideas to change a viewstate via a combobox? Just curiuous. Any help/feedback is welcomed. Thanks again. Keep up the good work!
# Posted By Edwin Leung | 3/19/07 5:18 AM
Was also curious about controlling a viewstack via a combo box. Most of the other controls allow you to specify a view stack as the dataProvider. This doesn't appear to work with combo boxes. Any thoughts/suggestion you might have would be greatly appreciated.

Thanks.
# Posted By Joe | 3/19/07 8:43 AM
Joe and Edwin:
I've not done this but try using ApplicationControlBar that contains a combo box. On the combo box change event, have the function select a new child for the view stack that matches the label of the combo box.
# Posted By Bruce | 3/19/07 4:50 PM
I've tried exactly what you've suggested but for some reason the focus doesn't switch to the any of the children. I'll give it another shot once I have a few more hours of sleep logged. I'll let you know what I come up with.
# Posted By Joe | 3/19/07 6:02 PM
Thanks Bruce..it was a great help.
# Posted By Edwin | 3/27/07 5:02 PM
Hi there,
I also use your site often to learn more about flex. So to start off a big thank-you!

how about changing the view of a stack from within a view?
# Posted By Al | 3/29/07 9:16 AM
Al - I'm not sure I understand your question. In my example for this blog entry I do change the selectedChild of the ViewStack which changes which "view" appears to the user.
# Posted By Bruce | 3/30/07 8:04 AM
Thanks for the helpful info, coming from ASP programming, it is really exciting to know what you can do with these things! BTW, do you know any other place I could get info on Flex + ASP??? I have grasped at the concept of outputting XML via ASP, but need some more reading. Thanks!
# Posted By Herick Paiva | 3/31/07 6:27 PM
Herick - I'm not an ASP programmer so I don't know of any specific Flex - ASP references. Try asking your question on the FlexCoders group on Yahoo.
# Posted By Bruce | 4/1/07 6:12 AM
Hi Bruce, to back up what i think Al is saying above - each of my views in the viewstack is a component. Can i control the viewstack from within this component?
# Posted By Martz | 5/16/07 7:53 AM
Martz - I would think that what you want to do is feasible. I'll have to research how you can dynamically get a reference to the outer container (in this case the ViewStack) so you can change the ViewStacks selectedChild property from within your component.

One way to solve your issue would be to pass a reference to the ViewStack to your custom component. Then our custom component could use that reference to change the ViewStack's selected child. See my blog entry on exposing properties for child components.

But I bet there is an easier way to get a reference to the ViewStack. I'll research this more and post what I can find. Again, you may also want to post your question on the Yahoo! FlexCoders group as they have much more expertise then I.
# Posted By Bruce | 5/16/07 5:50 PM
hi bruce! thanks for all your documentation it really helps those of us newbies understand better how to build flex apps. one problem im running into is that when i try to save using flex builder and refer to form variables ie. lastname.text that are not in the base state, it errors saying that its a bad reference. For example say your registerUser(): funtion actually needed to process the data and refer to the form item fields, for example firstName.text. How do i get it to not error when writing the function that refers to that field? any assistance would be greatly appreciated!!! :) best, stephen
# Posted By stephen | 5/22/07 3:00 PM
Stephen -

Take a look at:

http://www.brucephillips.name/blog/index.cfm/2007/...

where I actually register the user. You'll see that the ActionScript functions just refer to the form fields by the id value (eg, email.text) even if those form fields are added in a state change.

I suspect you're not refering to the id value correctly. Anyway take a look at the above example's code.
# Posted By Bruce | 5/22/07 5:16 PM
Is it possible to execute transitions on two components simultaneously? I'd like one panel to slide off the screen while the other comes up beneath it... instead of having a blank screen for a bit.

<mx:Sequence id="slideUpOut">
<mx:Move yBy="-400" duration="1000"/>
</mx:Sequence>
<mx:Sequence id="slideUpIn">
<mx:Move yFrom="500" yTo="0" duration="1000"/>
</mx:Sequence>
   <mx:ViewStack id="appViewStack" left="0" right="0" top="0" bottom="0">
      <vw:Login id="appLogin" formSubmitted="enterApp()" name="appLogin" hideEffect="{slideUpOut}" />
      <vw:Home id="appHome" showEffect="{slideUpIn}" />
   </mx:ViewStack>
# Posted By Erik Madsen | 8/10/07 10:36 AM
# Posted By Bruce | 8/10/07 11:58 AM
Hi,
I've followed this tutorial and it works great thanks, but i'm stuck when it comes to practice. Most my 'pages' are components in a viewstack as well as the login page. and as there are usually a login and signup button -how would the user click from one component in a viewstack to another component's state (ie. your register state?) and further change the state back to base when u click onwards and come back to that compenent's view?
# Posted By Xav_B | 8/13/07 2:13 AM
Xav - check out the code that handles the user clicking on the logout button in the example. That code changes the state back to the login form.
# Posted By Bruce | 8/14/07 7:04 AM
Bruce,

Always a pleasure to be on your site. I am facing an issue with a ViewStack's children showEffect and hideEffect behaviors when using certain effects (namely Zoom and Blur) - Does anyone notice that when applying certain effects to a ViewStack's children on hide and show that the final state of the newly selected child blinks on screen for a moment before the effect plays?

So if I blur out Child A and then blur in Child B, Child B flickers for a moment in its "in focus" display state before the blur effect happens.

Seems to be an ongoing issue.
# Posted By Kenny | 12/5/07 9:47 AM
Hi Does anyone know how i use a downloaded flex example. I mean how do I open the example? There is no open project in the file menu?

Sorry to be so thick
# Posted By Paul | 12/7/07 2:38 AM
Paul - When you view my example you can right click on it and select the choice of View Source. In the lower left is a link named Download Source (Zip).

Download that zip file and then open it up. In this example there is one .mxml file since all the code is contained in that one file.

If you want to run this file in your own Flex project: Create a new Flex project in Flex Builder (you can name it statesTest to match the single mxml file name or you can use your own name).

Copy the statesText.mxml file into your project's root folder. Now you can run that file in Flex Builder.

You may want to check out the 30 days of Free Flex Training being offered by Total Training. See: http://www.totaltraining.com/Store/online_adobe_lo...

You'll get lots of practice on creating Flex projects using saved code files (there are several different ways to do this).
# Posted By Bruce | 12/7/07 5:18 AM
i am having two component inside a screen i put a button in one component when i click it the second component should change which is in viewstack
pls give me a good solution...........
thanks in advance
# Posted By krisna | 5/14/08 2:39 AM
Thanks a million for taking such a great effort in putting out these examples. Wanted to know, if both the states need to be inside a contianer for the state change to take place. Can we define two states, inside an application and expect the transitions to take place and the child containers in the second state to render. for e.g in my application as shown bleow the addchild "levels" gets called in the transtions phase, but none of the child components of the "levels" state get rendered.
Should the levels state be inside a panel or some other contianer.
====================================================
<mx:WipeRight duration="1000" id="wipeIn" />
<mx:states>
<mx:State name="{ModelLocator.INIT}">
<mx:AddChild>
<view:SignInPanel id="signInPanel" horizontalAlign="center" verticalAlign="middle" />
</mx:AddChild>
</mx:State>

<mx:State name="{ModelLocator.PLAY}">
<mx:RemoveChild id="removeSignInPanel" target="{signInPanel}" />
<mx:AddChild>
<view:Levels id="levels" width="100%" height="100%" />
</mx:AddChild>
</mx:State>
   
<mx:transitions>
<mx:Transition id="fadeSignInOut" fromState="{ModelLocator.INIT}" toState="{ModelLocator.PLAY}">
<mx:Sequence>
<mx:Move target="{signInPanel}" xTo="5000" duration="2000" />
<mx:RemoveChildAction target="{signInPanel}" />
<mx:AddChildAction target="{levels}" />
</mx:Sequence>
</mx:Transition>
</mx:transitions>
====================================================
# Posted By ashok | 5/27/08 4:14 PM
Hi Bruce,

Good Tutorial indeed ...

But if I add a ButtonBar by providing "ViewStack's" id as a datasource .. it displays all the components viz Login,MainApplication and SecondaryApplication in the whole browser.

How to avoid that by displaying first the login component and then rest of the two after successful login with the help of ButtonBar or any Nav. Control.

Thanks
-jai
# Posted By Jai | 8/24/09 2:09 PM
Good One !!

How can we navigate from one flex page to another based on the input.

Thanks,
Laskan
# Posted By laskan | 9/22/09 6:22 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1.002. Contact Blog Owner