Flex How to change button state in actionscript? - actionscript-3

i can do this:
<s:Button id="Btn" enabled.State1="false" />
But the following code is giving me an error.
private function enableDisable():void{
Btn.enabled.State1="false"; //Error: Access of undefined property State1
}
how to code enabled.State1 in ActionScript?
Thanks

I know this is not what you want to hear, but here it goes anyway: why do you want to do that? The whole purpose of the states is that you wouldn't have to write tons of ActionScript to do the same thing.
Why you can't do it like that
By writing Btn.enabled.State1 in ActionScript you're essentially saying: give me the property called 'State1' of the Boolean instance called 'enabled'. Obviously that won't work because a Boolean doesn't have such a property. You're confusing the MXML dot (.) notation - used for assigning values to properties based on states - with the ActionScript dot notation - used for reading/writing properties.
A solution or as close as it gets
Since it's the very nature of this feature that you would use it in MXML, you can't do exactly what you're asking for in ActionScript. The next best thing would be to listen for StateChangeEvent en set the Button's 'enabled' property according to the new state name.
addEventListener(StateChangeEvent.CURRENT_STATE_CHANGE, onStateChange);
private function onStateChange(event:StateChangeEvent):void {
switch (event.newState) {
case "wrong": Btn.enabled = false; break;
case "correct": Btn.enabled = true; break;
}
}
(I'm using the same states as in James' answer)

I think you may be using states in the wrong context. For instance, you have component which contains a user input with a button next to it. The button is only enabled when the correct word is input. You would define two states for the component, perhaps correct and wrong.
<s:states>
<s:State name="wrong" />
<s:State name="correct" />
<s:states>
You would then, similar to what you've done above, set individual properties for the buttons depending on the state:
<s:Button id="Btn" enabled.wrong="false" enabled.correct="true" />
By default, the state of the component would be wrong. After handling user input and checking if the correct word is entered, the state of the component would be changed to correct.
Normally the state-specific properties of components are set at compile time and the state of the component itself changed at runtime.
Here is an overview of states in Flex 4.6

Related

Flex/Spark: How much logic in view? How to clear a TextField as a reaction to a user click or an event?

When using Flex with Spark, I have a simple chat window with a TextInput to enter your message and a send Button.
TextInput
Starts out as ""
Should be set to "" last in the function that handles the message sending
Should also be set to "" as a response for event="myOtherEvent"
Button
Should only be enabled when the TextInput's text.length > 0
At first I thought it was pretty clean to skip binding the text being entered into the TextInput to anything in my model and let that logic for button enabling/disabling stay in the view.
I still feel that it's a pretty nice approach except for the fact that it isn't a complete solution as it does not clear the TextInput.text as a response to receiving event="myOtherEvent".
The MXML for that partial solutions is:
<s:TextInput id="chatText" width="100%" height="32" />
<s:Button
label="Send"
enabled="{chatText.text.length > 0}"
click='{model.send(chatText.text); chatText.text=""}'
/>
If it wasn't for my event response requirement, how do you feel about that solution?
There is some logic in the Button, but just basic setting and checking. I know that it's a good idea to separate logic and presentation, but I thought this was a nice balance.
A complete solution I can think of would be to:
Have a two way binding of chatText.text and a property in my model
And in the set method for that property, I would dispatchEvent(new Event("updateButton")
A function in the same model class would bind to that event. That function would also be read in enabled="{model.thatFunction()}" of the Button. The function would return chatTextStringPropertyInModel.length > 0 and thus (by jumping through some hoops) would see to that the send-Button is enabled when there is text available for sending.
The model.send(chatText.text) can set chatTextStringPropertyInModel="" after sending and as that property is two-way bound with chatText.text the change would be reflected in the UI too.
My questions:
How much logic is all right to have in the view?
How should I solve this? What is most elegant and maintainable?
Maybe I'm confused but I don't see an issue in your solution. You just need to add an event handler for your other event
<fx:Script>
<![CDATA[
//clear text and disable button on other event
private function onMyOtherEvent(event:Event):void
{
chatText.text = "";
}
]]>
</fx:Script>
<s:TextInput id="chatText" width="100%" height="32" />
<s:Button
label="Send"
enabled="{chatText.text.length > 0}"
click='{model.send(chatText.text); chatText.text=""}'/>
Also I don't think there's anything wrong with a view component handling it's own view logic...

How can you make a Datagrid's Image-based itemRenderer either visible or not, depending on the value of its row and column in the datagrid?

The description is basically the same as the title. This is a related post I made a little while ago: Why would an Image-based itemRenderer always be visible? Basically the dataField that's being used for the itemRenderer's column in this case is "ongoing", and I want to set the itemRenderer and/or its image to true or false, depending on the value of ongoing in that row. If the itemRenderer is Label-based, I'm able to set the text to different values, depending on that. Certain specific properties, like visible, are problematic though. Documentation I've found so far on using states is very difficult to follow, and I'm not even sure those apply here. How do I do this? The current code, by the way is as follows:
<mx:DataGridColumn dataField="ongoing" id="ongoing" headerText="">
<mx:itemRenderer>
<mx:Component>
<mx:Image source="logo.jpg">
<mx:Script>
<![CDATA[
override public function set data(value:Object):void {
super.data = value;
super.visible = (value.ongoing != 'False');
}
]]>
</mx:Script>
</mx:Image>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
I've also tried working with the set visible override. Thanks!
That doesn't make any sense, especially in a Datagrid. If you don't want to display data, filter for it using a collection's filter function. Otherwise you're having empty cells.
Also, you're working against the component live cycle:
Setting visible in data will be called before the component is actually rendered - so there is no effect. If you're using vanilla objects and no classes, changes of the property's value will not have any effects as well.
On a site note: Boolean should be Booleans, no Strings and inline renderers can lead to some scoping issues, that's why i'd recommend using a separate component definition (aka .as or .mxml file).
The answer can loosely be found here by gokiさん:
http://www.fxug.net/modules/xhnewbb/viewtopic.php?topic_id=2229
At the moment at least, I'm having to actually set the source to either the image or a blank string to get this to work (looked like he was trying to do something slightly different), but it works.
EDIT: These two lines of code replaced where he was messing with the visible property:
var property0:SetProperty = new SetProperty(this, "source", "");
var property1:SetProperty = new SetProperty(this, "source", "dot.png");

Setting a skinState of a button in AS3

I want to set (manually) the skinState (for example 'disabled') of a button (that I skinned) in ActionScript.
For example:
I have a button skin with hostComponent: components.backend.btnMenuBakComp
The button skin has the default button states (up, over, down, ...), but I want to set one of this skinStates in ActionScript.
For example:
subMenu.btnDashboard.currentState = "disabled";
This doesn't work because the state "disabled" is not known in the component (it is only known in the skinState of btnDashboard).
How can I fix this?
Is there another solution then load a new skinClass?
Thanks
Quick and dirty
You can access the skin of any component and just set its state directly:
subMenu.btnDashboard.skin.currentState = "disabled";
That is however not a very clean way to do it. You are telling a Skin class directly what to do and completely bypassing the host component. Hence the host component has no idea of the changes that were made to its skin.
The proper way
A cleaner way to approach this is to expose a property on the host component and then tell the skin to adjust itself to possible changes by overriding the getCurrentSkinState() method.
You could for instance create a property 'enabled' and then tell the skin to update its state by calling invalidateSkinState() whenever 'enabled' is being set.
public function set enabled(value:Boolean):void {
_enabled = value;
invalidateSkinState();
}
Calling invalidateSkinState() will make the skin call getCurrentSkinState() in the next render cycle. This method will then look something like this:
override protected function getCurrentSkinState():String {
return _enabled ? "normal" : "disabled";
}
Do note that since you are skinning a Button (or a subclass of it) all that I've written here is already baked into that component. So the answer to your question might be as simple as : "just set the 'enabled' property to true.
subMenu.btnDashboard.enabled = true;

Best way to show and hide MXML components

I am working on an application where I need to basically have 2 separate screens and I need to be able to switch between them. I am a total noob to Flex & Flash and I have not found anything on how to do this in my 2 days of Googling. It really shouldn't be this hard to do! :)
Here is what I have tried. I created a Flex Project and added 2 MXML Component files called Test1 & Test2 and each simply have a button in them which have a label of Button1 & Button2 so I can see if the correct component is showing. Below is the button code in the Test1 MXML Component file:
<s:Button id="btn1" label="Button1" click="currentState = 'State2'">
In the MXML Application file I have 2 States called State1 & State2. I have added the following to this file as well:
<local:Test1 includeIn="State1" x="0" y="0"></local:Test1>
<local:Test2 includeIn="State2" x="0" y="200"></local:Test2>
I have also added the states to all 3 files:
<s:states>
<s:State name="State1"/>
<s:State name="State2"/>
</s:states>
When I run the application, I see Test1 as I would expect since State1 is the first state listed. When I click the button in Test1 (labeled Button1), I would expect it to now show the Test2 MXML component (since I am changing the currentState to 'State2', but it does not. Test1 is still displayed with Button1 showing.
Can someone shed some light as to what I am doing wrong? Or propose a better (or proper) way of doing this?
Thanks in advance!
Sounds like the states in your Application are not connected to the states in your components. Just giving them the same name doesn't connect them in any way. Anyway, if you're just trying to hide/switch components in your main Application you really only need the states in there.
One option would be to just access the Application's currentState property directly from within the components:
<s:Button id="btn1" label="Button1" click="FlexGlobals.topLevelApplication.currentState = 'State2'"/>
That works, but it's not recommended because it strongly couples the component with the parent Application and in a large project will lead to a mess if you have to refactor (or work with other people).
Another option, is to have each component dispatch an event to let the parent know it should change:
<fx:Metadata>
[Event(name="changeParentState", type="flash.events.Event")]
</fx:Metadata>
<s:Button id="btn1" label="Button1" click="dispatchEvent(new Event('changeParentState'));"/>
Then, the parent would decide which state it should switch to:
<local:Test1 includeIn="State1" changeParentState="currentState='State2'" />
<local:Test2 includeIn="State2" changeParentState="currentState='State1'" />
This way is more generic and just better OOP. However, if you'd want your components to be able to trigger more than just a single state, you might have to do something more complex. This should give you a sense of where to go at least.

In flex4 & as3 how do you change the button label dynamically?

Is there any way to change Spark button label dynamically? When i click on it, i want the label to change. I bind the String to label and gives value for the first time, but even flashBuilder shows me that Data binding will not be able to detect assignments.
Here is my button:
<s:Button name="button" label="{butt}" x="5" y="3" useHandCursor="true"
click="start()" buttonMode="true" cornerRadius="5"
skinClass="skins.CustomButtom"/>
And here is assigment:
public var butt:String = "Start";
Update
Both answers work.
Make the variable Bindable like this:
[Bindable]
public var butt:String = "Start";
It is not advisable to have buttons with changing labels.
Even if you must, it is preferable to change the label property directly instead of introducing a binding because Flash Player needs to instantiate extra listeners for bound variables.
In this case, a binding is required only if you are going to be changing the label frequently.
Without the bindable, you might have noticed that Flash will assign the value "Start" to the label of the button (generally, the value of the bound variable at the time of creation of the button).