Consider the following radio button example.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
private function getRb1():RadioButton {
trace(rb1 == null);
return rb1;
}
]]>
</mx:Script>
<mx:VBox>
<mx:RadioButtonGroup **id="rbg" selection="{getRb1()}**"/>
<mx:RadioButton id="rb1" label="Radio Button 1" />
<mx:RadioButton id="rb2" label="Radio Button 2" />
<mx:RadioButton id="rb3" label="Radio Button 3" />
</mx:VBox>
</mx:Application>
The problem is that I can not refer to rb1 while defining RadioButtonGroup, rb1 is null at that time, but i can use the selectedValue to set the initial selction.
I was just wondering is this some special case or its not safe to refer to components in mxml in general.
Thanks,
I'm not quite sure what you're asking, but hopefully this'll answer your question -- from the Flex docs:
RadioButtonGroup.selectionContains a reference to the currently
selected RadioButton control in the
group. You can access the property in
ActionScript only; it is not settable
in MXML. Setting this property to null
deselects the currently selected
RadioButton control.
In general, though, making component references in MXML is totally fine; that's how effects are often handled, among many other things. For example:
<mx:Glow id="g" />
<mx:Label showEffect="{g}" />
However in your case, assuming you're having trouble setting the selected item, it might be because you haven't specified the group attribute on the radio buttons; omitting that detaches the group component from the individual buttons. Once you add that, you can bind the group's selection property using a Bindable variable containing a reference to a component, like so:
<mx:Script>
<![CDATA[
[Bindable]
private var selectedRadioButton:RadioButton;
private function this_creationComplete(event:Event):void
{
selectedRadioButton = rb1;
}
private function btn_click(event:Event):void
{
selectedRadioButton = rb2;
}
]]>
</mx:Script>
<mx:VBox>
<mx:RadioButtonGroup id="rbg" selection="{selectedRadioButton}" />
<mx:RadioButton id="rb1" group="{rbg}" label="Radio Button 1" />
<mx:RadioButton id="rb2" group="{rbg}" label="Radio Button 2" />
<mx:RadioButton id="rb3" group="{rbg}" label="Radio Button 3" />
<mx:Button label="Choose a Different Button" click="btn_click(event)" />
</mx:VBox>
Does this make sense? Hopefully it's not completely off the mark; post back and let me know and I'll try to help out as best I can.
Generally: just because a control was declared in MXML does not mean it is available at runtime (it might be deleted from AS, not created yet, not added to stage, therefore some properties are not available yet). This indicates it is not safe to access components at runtime and depend on values.
Related
Objective: I would like to pass Skins to an itemRenderer (which is a Button) of a List, and be able to skin every button in that List.
This is what I have:
List:
<s:List itemRenderer="renderers.ItemRenderer" dataProvider="{collectionWorkspace}" />
ArrayCollection:
<s:ArrayCollection id="collectionWorkspace">
<comp:Layout1 />
<comp:Layout2 />
<comp:Layout3 />
<comp:Layout4 />
<comp:Layout5 />
</s:ArrayCollection>
The Layouts are Skin classes with HostComponent Button.
ItemRenderer:
<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/halo"
xmlns:s="library://ns.adobe.com/flex/spark">
<s:states>
<s:State name="normal" />
</s:states>
<s:Button skinClass="{data}"/>
</s:ItemRenderer>
I get an error (fixed for clarification):
Error: Skin for Application....Button1 cannot be found.
You are handing the skinClass property an instance of the skin class, not the actual class (which the button needs to create its own instance of the skin class).
If you can, the best thing to do would be to make collectionWorkspace be an array of Class objects, not of instances.
<s:ArrayCollection id="collectionWorkspace">
<fx:Class>yourPkg.Layout1</fx:Class>
<fx:Class>yourPkg.Layout2</fx:Class>
<fx:Class>yourPkg.Layout3</fx:Class>
<fx:Class>yourPkg.Layout4</fx:Class>
<fx:Class>yourPkg.Layout5</fx:Class>
</s:ArrayCollection>
If you can't do that, you should be able to pull out the class of the instance and pass it to the skinClass.
<s:Button skinClass="{Object(data).constructor}"/>
EDIT:
The binding by default won't work because data starts off as null before it gets initialized with the class. If you give it null, you will get the exception. To fix it, you will need to return the default for the time between null and value:
<s:Button skinClass="{data != null ? data as Class : spark.skins.spark.ButtonSkin}"/>
I tried doing this with an ArrayCollection using some button skins. It worked.
I have a login form with various textInputs and a submit button. If you submit proper login credentials the system unloads the login view and loads the app view. Pretty standard.
Unfortunately I've noticed this weird bug where if you hover over one of the textInput boxes with the mouse, then fill the form using only the keyboard (and leave the mouse parked on top of the textInput), and then tab to the submit button and press the space bar, i.e. login via keyboard, the mouse cursor will remain a caret in the new view, no matter what you do (move, click), until you find another textInput to undo the cursor state.
I've tried to do all sorts of stuff via CursorManager but nothing seems to do the trick. I've tried dispatching events ROLL_OUT or MOUSE_OUT events to the textInput but that doesn't do the trick either.
I've tried to reproduce this in a small example and have not been able to, which I realize makes helping me that much harder. Would still love to hear if anyone has dealt with something similar or hear of any pointers that may sound connected.
thank you!
f
I had the exactly the same problem. Here is my login screen view:
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
.textInput
{
showErrorTip : true;
showErrorSkin : true;
}
</fx:Style>
<fx:Declarations>
<mx:StringValidator id="usernameValidator" source="{username}" property="text"
trigger="{signinButton}" triggerEvent="click" required="true" />
<mx:StringValidator id="passwordValidator" source="{password}" property="text"
trigger="{signinButton}" triggerEvent="click" required="true"/>
</fx:Declarations>
<fx:Script>
<![CDATA[
import info.thwm.appx.model.vo.LoginVO;
import info.thwm.appx.view.events.ViewEvent;
import mx.validators.Validator;
public static const NAME:String = "LoginView";
[Bindable] public var loginVO:LoginVO = new LoginVO();
private function init():void{
focusManager.setFocus( username );
sendEvent( ViewEvent.VIEW_CREATED, NAME );
}
private function sendEvent( type:String, data:Object=null ):void{
dispatchEvent( new ViewEvent( type, data ) );
}
private function loginUser(event:MouseEvent = null):void{
var validators:Array = [usernameValidator, passwordValidator];
var errors:Array;
errors = Validator.validateAll(validators);
if (errors.length == 0){
sendEvent( ViewEvent.BTN_LOGIN_CLICK, loginVO );
}
}
]]>
</fx:Script>
<s:Panel width="320" height="230" title="Sign In">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:Form id="form1" styleName="formStyle" defaultButton="{signinButton}"> <s:layout>
<s:FormLayout paddingLeft="25" gap="-5"/>
</s:layout>
<s:FormItem label="Username" required="true" skinClass="info.thwm.appx.view.skins.FormItemSkin">
<s:TextInput id="username" text="#{loginVO.username}" styleName="textInput"/>
</s:FormItem>
<s:FormItem label="Password" required="true" skinClass="info.thwm.appx.view.skins.FormItemSkin">
<s:TextInput displayAsPassword="true" id="password" text="#{loginVO.password}" styleName="textInput"/>
</s:FormItem>
<s:FormItem>
<s:CheckBox label="Remember" id="remember" selected="#{loginVO.remember}"/>
</s:FormItem>
<s:FormItem>
<s:Button label="Sign In" id="signinButton" click="loginUser(event)"/>
</s:FormItem>
</s:Form>
<s:controlBarContent>
<s:HGroup width="100%" verticalAlign="middle">
<s:Button label="Register" id="registerButton" click="sendEvent( ViewEvent.BTN_REGISTER_CLICK );" />
<s:Label buttonMode="true" color="#57595A" text="Forgot your username or password?" click="sendEvent( ViewEvent.BTN_PSW_REMINDER_CLICK );"/>
</s:HGroup>
</s:controlBarContent>
</s:Panel>
Nothing special about that, but if i select username field with mouse and then only use keyboard for the rest, as soon as i get to next view mouse cursor becomes input caret. The only way around it was add this line "Mouse.cursor = MouseCursor.ARROW" in next view's onCreationComplete event function.
Try explicitly setting the focus to another object? See UIComponent.setFocus()
After stripping my app down to almost the bare bones I noticed that the text property of my textInputs was bound to a field of another variable. I'm not sure why this would create the issue described above but taking that binding out solved the problem. I wish I could do more research in the matter, but sadly this has already taken way too much time.
Am using Checkbox as ItemRenderer in tilelist. Am trying to setting
checkbox selected values through xml. I got the values perfectly.. but
checkbox could not bind the values(could not accept that). It's
automatically sets true for all checkboxes.
This is my xml
<PmhTreeAllow>
<PmhTreeAllowname id='1' label ='Allow Text' isField='false'/>
<PmhTreeAllowname id='2' label ='Document Link' isField='false'/>
<PmhTreeAllowname id='3' label ='Test Results Entry'isField='false'/>
<PmhTreeAllowname id='4' label ='Dummy' isField='false'/>
</PmhTreeAllow>
My Tilelist..
<mx:TileList id="tileList" width="160" height="100%" textAlign="left" horizontalScrollPolicy="off" verticalScrollPolicy="off" dataProvider="modelInstance.optionCollList}" columnCount="1" backgroundAlpha="0" borderStyle="none"itemRenderer="com.Frontend.views.treeStructure.myTileList" useRollOver="false" rowHeight="28" itemClick="tileItemClick(event)" columnWidth="150" selectedIndex="0" x="10" y="0">
Check box ItemRenderer..
<?xml version="1.0" encoding="utf-8"?>
<mx:CheckBox xmlns:mx="http://www.adobe.com/2006/mxml" label="{data.#label}" selected="data.#isField}"/>
Thanks in Advance
Ashok
http://www.switchonthecode.com/tutorials/flex-using-item-renderers
This will help u..
For performance reasons, it is considered a bad practice to use binding inside an itemRenderer. Instead listen to the FlexEvent.DATA_CHANGE and manually modify your values. I Bet doing so will solve your issue.
Try an itemRenderer like this:
<mx:CheckBox xmlns:mx="http://www.adobe.com/2006/mxml" label="{data.#label}" selected="data.#isField}" dataChange="onDataChange()">
<mx:Script><[[
public function onDataChange():void{
var dataAsXML = data as XML;
this.selected = data.#isField
this.label = data.#label
]]></mx:Script>
</mx:CheckBox>
I don't do a lot with XML, but I suspect that the XML properties will not bind because XML is not like an ActionScript object and therefore the "propertyChanged" Binding events do not exist on the XML object the same way they would be on an AS3 object.
How to validate the radio button is selected or not in flex 3?
if my question is wrong, please suggest me any thing regarding the validation of radio group.
Simply use a StringValidator:
<mx:StringValidator id="myRadioButtonGroupValidator"
source="{myRadioButtonGroup}"
property="selectedValue"
required="true"/>
For Spark groups and RadioButtons things work slightly different. See the example below.
Note: For a HGroup as the example shows: The warning-sight will appear for errors but there will be no red-colored border be visible. If you set a RadioButton itself as listener you might get an ugly result and if you set a FormItem as target you will see nothing happen.
<fx:Declarations>
<s:RadioButtonGroup id="myGroup" />
<mx:StringValidator id="vLevel"
required="true"
source="{myGroup}"
property="selectedValue"
minLength="1"
maxLength="80"
listener="{grpLevel}"
/>
</fx:Declarations>
<s:FormItem label="Level">
<s:HGroup id="grpLevel">
<s:RadioButton group="{myGroup}" label="A"/>
<s:RadioButton group="{myGroup}" label="B"/>
<s:RadioButton group="{myGroup}" label="C"/>
</s:HGroup>
</s:FormItem>
This is the way I solved the problem. If anything is wrong please leave a the comment.
<mx:NumberValidator id="radiogroupValidator" source="{radiogroup}" property="selectedValue" allowNegative="false" />
radio group source in mxml file
<mx:RadioButtonGroup id="radiogroup" itemClick="radiochangefunction(event)" selectedValue="-1" />
<mx:RadioButton id="radiobtn1" groupName="radiogroup" label="Send Password to existing EmailId" value="0"/>
<mx:RadioButton id="radiobtn2" groupName="radiogroup" label="Enter new EmailId" value="1"/>
The itemClick function
public function radiochangefunction(event):void
{
radiogroup.selectedValue=event.currentEvent.selectedValue.toString();
}
and finally in validation function
var isValidradiobutton:Boolean = (Validator.validateAll([radiogroupValidator]).length==0);
Listen to the itemClick event of the RadioButtonGroup. Within the handler, use selection or selectedValue property to know which RadioButton was clicked.
selection - returns a reference to the selected RadioButton instance
selectedValue - returns the value property of the selected RadioButton, if it is set. Otherwise, returns its label text.
Both of these properties return null if no RadioButton is selected.
A running example from livedocs
<?xml version="1.0"?>
<!-- Simple example to demonstrate RadioButtonGroup control. -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.ItemClickEvent;
// Event handler function to display the selected button
// in an Alert control.
private function handleCard(event:ItemClickEvent):void {
if (event.currentTarget.selectedValue == "AmEx") {
Alert.show("You selected American Express")
}
else {
if (event.currentTarget.selectedValue == "MC") {
Alert.show("You selected MasterCard")
}
else {
Alert.show("You selected Visa")
}
}
}
]]>
</mx:Script>
<mx:Panel title="RadioButtonGroup Control Example" height="75%" width="75%"
paddingTop="10" paddingLeft="10">
<mx:Label width="100%" color="blue"
text="Select a type of credit card."/>
<mx:RadioButtonGroup id="cardtype" itemClick="handleCard(event);"/>
<mx:RadioButton groupName="cardtype" id="americanExpress" value="AmEx"
label="American Express" width="150" />
<mx:RadioButton groupName="cardtype" id="masterCard" value="MC"
label="MasterCard" width="150" />
<mx:RadioButton groupName="cardtype" id="visa" value="Visa"
label="Visa" width="150" />
</mx:Panel>
</mx:Application>
I'm new to Flex and am using TileList bound to an ArrayCollection. The array collection is empty at load time, and then updates with the results from am HTTPService call. The problem is that the item renderers aren't being rendered as expected, I'm guessing because there was no data when they were first rendered at load time. Here's simplified example:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
public var myList1:ArrayCollection = new ArrayCollection();
[Bindable]
public var myList2:ArrayCollection = new ArrayCollection([{item:"foo"}, {item:"bar"}]);
public function updateMyList():void
{
myList1.source = [{item:"foo"}, {item:"bar"}];
}
]]>
</mx:Script>
<mx:Button id="myButton" label="Update My List"
click="updateMyList();"/>
<mx:TileList dataProvider="{myList1}"
direction="vertical"
width="800" >
<mx:itemRenderer>
<mx:Component >
<mx:Canvas backgroundColor="yellow" >
<mx:Label text="{data.item}" width="800" />
</mx:Canvas>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>
<!-- This one renders as expected -->
<mx:TileList dataProvider="{myList2}"
direction="vertical"
width="800" >
<mx:itemRenderer>
<mx:Component >
<mx:Canvas backgroundColor="yellow" >
<mx:Label text="{data.item}" width="800" />
</mx:Canvas>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>
</mx:Application>
You will notice that the second TileList whose bindings has data at load time renders as expected (800px wide), bit the first TileList is rendered is not the correct width and has scrollbars around it.
Could anyone explain why this is happening or even provide some work arounds to avoid this?
Regards,
Chris
It's likely that this section is causing the problems:
public function updateMyList():void
{
myList1.source = [{item:"foo"}, {item:"bar"}];
}
From here:
source of data in the ArrayCollection.
The ArrayCollection object does not
represent any changes that you make
directly to the source array. Always
use the ICollectionView or IList
methods to modify the collection.
This property can be used as the
source for data binding. When this
property is modified, it dispatches
the listChanged event.
So I'd probably change the line to:
myList1= new ArrayCollection([{item:"foo"}, {item:"bar"}]);
http://livedocs.adobe.com/flex/3/langref/mx/controls/TileList.html
Check the API.
Set the columnWidth and rowHeight properties like this,
<mx:TileList dataProvider="{myList1}"
direction="vertical"
width="800" columnWidth="800" rowHeight="25">
There is probably a more "proper" way to do it, but that should get you started.