Flex: Changing property of inactive state

I have a decision tree wizard where the first states in the workflow determine what is shown in the last states.  

I ran into a bug where if I change the enabled state of an element in a state which has not yet been viewed - I get the following error:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
      at stateChangeExample/check2Handler()[/.../src/stateChangeExample.mxml:25]
      at stateChangeExample/___stateChangeExample_CheckBox2_click()[/.../src/stateChangeExample.mxml:49]

I have included code for an example.  You'll notice that if you select the checkbox on the right before you hit the change state button, you'll get the error.  If you then change the state and then change it back you will no longer get the error.

I have a couple workarounds... namely run through all the states onLoad or buffer all the changes until the state is set to currentState... but I prefer to figure this out.  Maybe there is a way I need to activate the state without showing it?

HELP!!!
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
	<mx:states>
		<mx:State name="state2">
			<mx:AddChild position="lastChild">
				<mx:TextInput id="input2" x="203" y="41"/>
			</mx:AddChild>
		</mx:State>
	</mx:states>
	<mx:Script>
		<![CDATA[
			public function check1Handler():void
			{
				if(input1.enabled == true)
				{
					input1.enabled = false;
				} 
				else
				{
					input1.enabled = true;	
				} 	
			}
			public function check2Handler():void
			{
				if(input2.enabled == true)
				{
					input2.enabled = false;
				} 
				else
				{
					input2.enabled = true;	
				} 					
			}
			public function changeState():void
			{
				if(currentState == "state2")
				{
					currentState = "";
				} 
				else
				{
					currentState = "state2";	
				} 	
			}
		]]>
	</mx:Script>
	<mx:CheckBox click="check1Handler()" x="10" y="11" label="disable/enable in base state"/>
	<mx:TextInput id="input1" x="10" y="41"/>
	<mx:CheckBox click="check2Handler()" x="203" y="11" label="disable/enable in state2"/>
	
	<mx:Button click="changeState()" x="10" y="71" label="Change State"/>
	
	
	
</mx:Application>

Open in new window

bittermonkAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
hockeyragazzoConnect With a Mentor Commented:
This has likely got something to do with the fact that input2 hasn't yet been instantiated in the display. I often run into problems like these when I have a custom component with a bunch of textinputs and I want to insert data into those inputs directly (input2.text = "Blah blah") before they've been added to the display. The solution I use in this case is to bind variables to the text inputs and simply set the variables. Absent other solutions that help you better understand the nature of the accessibility of display objects when they're not in the stage, how about this:

Set the enabled property equal to some Boolean variable called Input2EnabledBool which starts at whatever state you like (true or false). This way you can set the value of Input2EnabledBool = false when you want to disable the TextInput and = true when you want to enable it. As far as I know, this will solve your problem.

Be sure to put a [Bindable] tag before your variable:

[Bindable] private var Input2EnabledBool = true;

and then:



<mx:State name="state2">
                        <mx:AddChild position="lastChild">
                                <mx:TextInput id="input2" x="203" y="41" enabled={Input2EnabledBool}/>
                        </mx:AddChild>
                </mx:State>

Open in new window

0
 
hockeyragazzoCommented:
An alternative, yet more bloated (especially if you have many TextInputs on which you want to perform these operations), option is to put your input2 with visible=false in the main portion of the Application instead of creating it in the new state. Then, instead of adding a TextInput in your new state, simply set the visible property = true. This will ensure that it exists at every point after creationComplete and all you will be changing when you go into a new state is the visibility of input2.

I personally like the variable binding option better because states are an extremely efficient way to add components in a way that doesn't add much to the size of the Application/component you're building.
0
 
bittermonkAuthor Commented:
hockeyragazzo: Your answer is better than what I went with...

So to be clear... if I change the currentState and then change it back...

the element in state2 is not on the stage until state2 is set to currentState
and
when I return to the base state the element in state2 remains on the stage although it is no longer visible.

Is there a way to add all the states to the stage onLoad without making them visible?
0
Easily Design & Build Your Next Website

Squarespace’s all-in-one platform gives you everything you need to express yourself creatively online, whether it is with a domain, website, or online store. Get started with your free trial today, and when ready, take 10% off your first purchase with offer code 'EXPERTS'.

 
bittermonkAuthor Commented:
I definitely like the binding option better than removing the states...
0
 
hockeyragazzoCommented:
According to my understanding, that is correct. You can test this out by entering some text into your TextInput and switching states back and forth. If the text remains in the box after going to the base state and back to state2, then I think that is a correct interpretation.

As far as I know, adding all the states to the stage, i.e. adding all the components in a state to the stage, would defeat the purpose of having states. The only way to accomplish this would be to set a creationComplete function to just run through all the states you want to load and then back to your base state. I suspect that in a larger application, and possibly even in smaller ones like yours, this would start looking pretty clunky to the user. The same effect can be achieved by adding your component in the main part of the Application (as if it were in the base state), but setting the visibility = false, then using states to manipulate the visible property. This does come at a cost as every component in the main portion of the Application adds to the size of the .swf you produce on export, while adding components with states is a low-cost alternative to this.

But considering this is the only scenario I can really think of where states kind of screw with what the programmer expects to occur, binding variables to your state-added components is probably the best solution.

Lemme know what you end up going with and how it works out for you....or if you need any more clarification :-)
0
 
bittermonkAuthor Commented:
Thanks for the clarification... I'll go with this :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.