Understanding State Life Cycles

One aspect of states that initially can be confusing is the life cycle of the components within a state. As you learned in Managing Object Creation Policies (Preloading Objects)” earlier in this chapter, by using states you can manage the creation policy for components within the state. By default, all the components in a state are not created until the state is first requested. You also learned that you can control the creation policy such that components are created when the application starts up regardless of whether they belong to the base state, or you can manually create the components in a state. That covers the possibilities for how and when components in states can get created. Next, we need to look at what happens to components once they have been created, because this point can cause a fair amount of confusion if misunderstood.

When a state is set to the current state one of two possible things can happen. If the components in the state have already been created they are immediately added to the display list; if the components haven’t yet been created they are first created and then added to the display list. On the other end of things, when a state is replaced as the current state only one thing can happen: the components that are part of that state are removed from the display list. Once the components in a state have been created, they are not destroyed. Replacing a state as the current state does not destroy the components it contains. This has subtle repercussions.

We’ll start by considering a relatively simple scenario to see the implications of how components are managed by states. In this scenario, we’ll create an application with two states: each is a simple form. We’ll assume that for business or legal reasons it is critical that if the user wants to return to one of the forms to change something, she must fill out the entire form again. To start, Example 12-19 shows the initial MXML code that creates the two forms, two states, and two buttons for switching between them.

Example 12-19. Creating two states, two forms, and two buttons

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:HBox>
        <mx:Button label="Form A" click="currentState='formA';" />
        <mx:Button label="Form B" click="currentState='formB';" />
    </mx:HBox>
    <mx:states>
        <mx:State name="formA">
            <mx:AddChild>
                <mx:VBox>
                    <mx:Label text="Select from the following list" />
                    <mx:CheckBox id="cars" label="Cars" />
                    <mx:CheckBox id="boats" label="Boats" />
                    <mx:CheckBox id="airplanes" label="Airplanes" />
                    <mx:CheckBox id="trains" label="Trains" />
                </mx:VBox>
            </mx:AddChild>
        </mx:State>
        <mx:State name="formB">
            <mx:AddChild>
                <mx:Form>
                    <mx:FormItem label="Name">
                        <mx:TextInput id="contactName" />
                    </mx:FormItem>
                    <mx:FormItem label="Email">
                        <mx:TextInput id="contactEmail" />
                    </mx:FormItem>
                </mx:Form>
            </mx:AddChild>
        </mx:State>
    </mx:states>
</mx:Application>

If you test this application, fill out the forms, and switch back and forth between them, you'll see that the form values are retained even as you switch states. In most cases, this is quite a good thing. However, in the scenario that we’ve created, we want to make sure the forms are always reset to the starting point when the user returns to them. Using the enterState event that we discussed in the preceding section, we can do just that. Use the enterState event to trigger ActionScript that resets the forms, as shown in Example 12-20.

Example 12-20. Resetting forms using the enterState event

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">

    <mx:Script>
         <![CDATA[

              private function resetFormA():void {
                   cars.selected = false;
                   boats.selected = false;
                   airplanes.selected = false;
                   trains.selected = false;
              }

              private function resetFormB():void {
                   contactName.text = "";
                   contactEmail.text = "";
              }

         ]]>
    </mx:Script>

    <mx:HBox>
         <mx:Button label="Form A" click="currentState='formA';" />
         <mx:Button label="Form B" click="currentState='formB';" />
    </mx:HBox>
    <mx:states>
         <mx:State name="formA" enterState="resetFormA();">
             <mx:AddChild>
                   <mx:VBox>
                        <mx:Label text="Select from the following list" />
                        <mx:CheckBox id="cars" label="Cars" />
                        <mx:CheckBox id="boats" label="Boats" />
                        <mx:CheckBox id="airplanes" label="Airplanes" />
                        <mx:CheckBox id="trains" label="Trains" />
                   </mx:VBox>
              </mx:AddChild>
          </mx:State>
          <mx:State name="formB" enterState="resetFormB();">
              <mx:AddChild>
                   <mx:Form>
                        <mx:FormItem label="Name">
                             <mx:TextInput id="contactName" />
                        </mx:FormItem>
                        <mx:FormItem label="Email">
                             <mx:TextInput id="contactEmail" />
                        </mx:FormItem>
                   </mx:Form>
              </mx:AddChild>
         </mx:State>
    </mx:states>
</mx:Application>

It’s likely that you’ll frequently use states to add and remove custom application components. For example, if you were to write an application such as the one shown in Example 12-19 and Example 12-20, you’d probably convert the forms to components. If you were to do that, the basic strategy for resetting the form values would be similar, but there would be slight changes. To better understand this we’ll first look at the code for the componentized version of the application. Example 12-21 and Example 12-22 show the MXML components for the two forms.

Example 12-21. FormA.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Label text="Select from the following list" />
    <mx:CheckBox id="cars" label="Cars" />
    <mx:CheckBox id="boats" label="Boats" />
    <mx:CheckBox id="airplanes" label="Airplanes" />
    <mx:CheckBox id="trains" label="Trains" />
</mx:VBox>

Example 12-22. FormB.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Form xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:FormItem label="Name">
         <mx:TextInput id="contactName" />
    </mx:FormItem>
    <mx:FormItem label="Email">
         <mx:TextInput id="contactEmail" />
    </mx:FormItem>
</mx:Form>

Next, in Example 12-23, you can see what the revised application MXML looks like. We’ve removed the Script block from this code because it is no longer relevant.

Example 12-23. Using custom application components for the forms

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="vertical" xmlns:local="*">
    <mx:HBox>
         <mx:Button label="Form A" click="currentState='formA';" />
         <mx:Button label="Form B" click="currentState='formB';" />
    </mx:HBox>
    <mx:states>
         <mx:State name="formA">
              <mx:AddChild>
                   <local:FormA id="formA" />
              </mx:AddChild>
         </mx:State>
         <mx:State name="formB">
              <mx:AddChild>
                   <local:FormB id="formB" />
              </mx:AddChild>
         </mx:State>
    </mx:states>
</mx:Application>

At this point, we’re back to where we were when we started because the forms still don’t clear out when the user returns to them. We had to remove the ActionScript code we used before because it was trying to reference components that don’t exist now that we’ve converted the forms to components. We’ll use the same basic strategy we used before, but now we’ll encapsulate it. Example 12-24 and Example 12-25 show what the MXML components look like when we add reset() methods to them. Notice that the reset() methods are merely the old resetFormA() and resetFormB() methods.

Example 12-24. FormA.mxml with the reset() method

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
         <![CDATA[

              public function reset():void {
                   cars.selected = false;
                   boats.selected = false;
                   airplanes.selected = false;
                   trains.selected = false;
              }

         ]]>
    </mx:Script>

    <mx:Label text="Select from the following list" />
    <mx:CheckBox id="cars" label="Cars" />
    <mx:CheckBox id="boats" label="Boats" />
    <mx:CheckBox id="airplanes" label="Airplanes" />
    <mx:CheckBox id="trains" label="Trains" />
</mx:VBox>

Example 12-25. FormB.mxml with the reset() method

<?xml version="1.0" encoding="utf-8"?>
<mx:Form xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
         <![CDATA[

              public function reset():void {
                   contactName.text = "";
                   contactEmail.text = "";
              }

         ]]>
    </mx:Script>

    <mx:FormItem label="Name">
         <mx:TextInput id="contactName" />
    </mx:FormItem>
    <mx:FormItem label="Email">
         <mx:TextInput id="contactEmail" />
    </mx:FormItem>
</mx:Form>

Now all we need to do is call the reset() method of the corresponding component on the enterState event handlers within the application code, as shown in Example 12-26.

Example 12-26. The application using the enterState event to trigger calls to the reset() method

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
xmlns:local="*">
    <mx:HBox>
         <mx:Button label="Form A" click="currentState='formA';" />
         <mx:Button label="Form B" click="currentState='formB';" />
    </mx:HBox>
    <mx:states>
         <mx:State name="formA" enterState="formA.reset();">
              <mx:AddChild>
                   <local:FormA id="formA" />
              </mx:AddChild>
         </mx:State>
         <mx:State name="formB" enterState="formB.reset();">
              <mx:AddChild>
                   <local:FormB id="formB" />
              </mx:AddChild>
         </mx:State>
    </mx:states>
</mx:Application>

Note

It's easy enough to become accustomed to using creationComplete and/or initialize event handlers to control actions that you want to occur when a custom MXML component appears on the display list, because in many cases all of these events coincide. However, when a component is added and removed from the display list using states, the creationComplete and initialize events will occur only the first time the state with the component is set to the current state (assuming that the creation policy is set to auto). Do not rely on these events for things that need to occur each time the component is added again as a result of a state change. See Chapter 19 for more information about component phases.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset