In my Flex 4.6 web application I use mainly spark components, but there is also an mx-component - a PopUpButton extended by me (the source code is below).
Users report problems with that button, but I can't reproduce any - since weeks.
I've tried replacing mx:Menu attached to it by a s:List but it hasn't changed anything. I suspect there is a "null pointer exception" or some other failure, that I don't hit when testing myself...
My question is: why does Flash Builder reports warning about my custom button as if its methods would be private or not present?
Can anybody please spot the reason?
My main App.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:comps="*">
<fx:Script>
<![CDATA[
_auxBtn.update(obj.aux);
......
_auxBtn.disable();
]]>
</fx:Script>
<comps:AuxButton id="_auxBtn" enabled.normal="false" enabled.ingame="false" aux="handleAux(event)" />
My custom button AuxButton.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:PopUpButton
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
popUp="{_list}"
initialize="init(event)">
<fx:Metadata>
[Event(name="aux", type="PrefEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import mx.utils.ObjectUtil;
import spark.components.List;
private const EXACT:String = 'Своя игра';
private const REVEAL:String = 'Показать';
private var _str:String;
[Bindable]
private var _data:ArrayCollection = new ArrayCollection();
[Bindable]
private var _list:List = new List();
private function init(event:FlexEvent):void {
_list.dataProvider = _data;
_list.addEventListener('click', handleList);
addEventListener('click', handleClick);
}
public function update(aux:Array):void {
var found:Boolean;
// nothing has changed
if (ObjectUtil.compare(_data.source, aux, 0) == 0)
return;
if (aux == null || aux.length == 0) {
disable();
return;
}
_data.removeAll();
for each (var obj:Object in aux) {
_data.addItem(obj);
if (!_str) {
if (EXACT == obj['label']) {
_str = obj['event'];
label = obj['label'];
found = true;
} else if (REVEAL == obj['label']) {
_str = obj['event'];
label = obj['label'];
found = true;
}
} else if (_str == obj['event']) {
found = true;
}
}
if (!found) {
_str = _data[0].event;
label = _data[0].label;
}
enabled = true;
}
private function handleList(event:MouseEvent):void {
var index:int = _list.selectedIndex;
if (index >= 0 && index < _data.length) {
_str = _data[index].event;
label = _data[index].label;
}
close();
}
private function handleClick(event:MouseEvent):void {
dispatchEvent(new PrefEvent(PrefEvent.AUX, _str));
disable();
}
public function disable():void {
_data.removeAll();
enabled = false;
_str = null;
label = '';
}
]]>
</fx:Script>
</mx:PopUpButton>
Don't worry about Flash Builder warnings, sometimes it has difficulties analyzing custom mx extended code (even spark sometimes!).
If it runs it's okay, warnings will eventually go away after a clean or a FB restart.
You can also try to reproduce same feature using a mix of spark component, depending on a feature, it is maybe the best thing to do.
Stay assured, I pasted your code in my Flash Builder (and removed the PrefEvent), there are no warnings at all on my computer :)
For the error you users are reporting, you should give us more detail so we can try to help.
Cheers
Related
I have a Flex Mobile Project that I am working on. I am trying to pass parameters from one view to another. The only problem is that I cannot use navigator.pushView to push the View and the parameter as the view I am pushing to was the previous view. So this wipes out using the addHandler() and the returnObjectsCreated() as I cannot use pushView. I am having to use popView because it is my previous view that I have to pass parameters too. Any help would be appreciated.
That class that has the parameters I need to pass is below. It is a view that shows a list. So I need to pass list.selectedItem to the popview or previous view...
<?xml version="1.0" encoding="utf-8"?>
<amec:BaseBrowseView xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:amec="com.amec.Components.*"
title="Select an item">
<fx:Script>
<![CDATA[
import com.amec.BaseSql;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.events.IndexChangeEvent;
[Bindable]private var resultArr:ArrayCollection = new ArrayCollection();
protected function myList_changeHandler(event:IndexChangeEvent):void
{
navigator.popView();
//Either send a ref to the last view or override createReturn
}
[Bindable(event="myDataChanged")]
private function get myData():ArrayCollection
{
}
]]>
</fx:Script>
<s:List id="list"
height="100%" width="100%"
dataProvider="{myData}"
labelField="DMV_VALUE_1"
change="myList_changeHandler(event);">
</s:List>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
Now below is the previous view that I want to popView to that I need to pass parameters to so I can populate the TextInput with.
<?xml version="1.0" encoding="utf-8"?>
<amec:BaseControl xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:amec="com.amec.Components.*"
horizontalCenter="true">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Bindable]
protected var textValue:String;
protected function control_creationCompleteHandler(event:FlexEvent):void
{
// todo: get control data from view.data
}
protected function control_clickHandler(event:MouseEvent):void
{
parentView.navigator.pushView(TextListView);
}
]]>
</fx:Script>
<s:Label text="Robert says something meaningful goes here" />
<s:TextInput id="ns" text="{textValue}" editable="false" click="control_clickHandler(event)"/>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
Again I cannot use pushView as the view is already on the stack.
In case you want to do it the right way, on the previous view (the one you want the result going to, add an eventListener for 'add'.
protected function addHandler(event:FlexEvent) : void {
if (navigator.poppedViewReturnedObject != null) {
var returnedObject : Array = navigator.poppedViewReturnedObject.object as Array;
if(!returnedObject) return;
yourData= new ArrayCollection(returnedObject);
}
}
On the view that you are going to pass the object from:
override public function createReturnObject():Object {
var returnedObject : Object = new Object();
returnedObject = dataYouWantToSendBack;
return returnedObject;
}
I looked at using static variables but that was a little messy, I also looked at using Dependency Injection but spending a few hours to set up the framework and get it running is to costly when all I am doing is passing parameters on a popView, so what I came up with is the similar approach I have used when doing Native Android Apps with the Android SDK. A Singleton with getters and setters.
Basically the way I have been able to do this is with the use of a Singleton sharedInstance. See code below:
package com.controls.Text
{
import flash.utils.Dictionary;
[Bindable]
public class ParameterManager
{
private static var instance:ParameterManager = new ParameterManager();
private var dictionary:Dictionary=new Dictionary();
public function ParameterManager( )
{
if (instance != null) { throw new Error('Must use ParameterManager.getInstance().') }
}
public static function getInstance(): ParameterManager {
return instance;
}
public function setParameter(key:*, value:*):void
{
dictionary[key]=value;
}
public function getParameter(key:*):*
{
return dictionary[key];
}
}
}
The method setting the value of the parameter:
protected function myList_changeHandler(event:IndexChangeEvent):void
{
var listViewReturnObject:String = new String();
listViewReturnObject = list.selectedItem.DMV_VALUE_1;
ParameterManager.getInstance().setParameter("selectedItem", listViewReturnObject);
navigator.popView();
}
The method getting the value:
protected function control_creationCompleteHandler(event:FlexEvent):void
{
var listViewReturnObject:Object = new Object();
listViewReturnObject= ParameterManager.getInstance().getParameter("selectedItem");
if (listViewReturnObject != null)
{
dataTxt.text= String(listViewReturnObject);
ParameterManager.getInstance().setParameter("", null); //Make sure objects are cleared when done.
}
}
I have a Flex application that behaves as described below
I want to fix two things
I want to make clear to the user that more info can be shown. Current "Profundidad" is only a label.
The element that is being shown below is not aligned to the one above it, since this is actually another component that is being shown when the state changes
I have tried using Accordion, but when you have a Accordion with a single element, that element is always visible so it can not be collapsed and expanded
What i want is the final result to look as close as posible to this
You can easily achieve this using states. First define two states: 'normal' and 'expanded'
<s:states>
<s:State name="normal"/>
<s:State name="expanded"/>
</s:states>
Then use includeIn or excludeFrom to display components as needed:
<!-- always visible components -->
<s:Label text="FPBAF20F"/>
<s:Label text="N/A"/>
<s:Button label="Profundidad"
click="currentState = currentState == 'expanded' ? 'normal' : 'expanded'"/>
<!-- the compra/venta grid only shown in 'expanded' state -->
<s:DataGrid includeIn="expanded" />
The click handler isn't very pretty, but you get the idea: when you click the Button, the state is toggled from 'normal' to 'expanded' and back when you click again.
That's really all there is to it.
If you prefer an out-of-the-box solution, you're free to use the CollapsiblePanel component I created: https://github.com/RIAstar/CollapsiblePanelFx ;)
Maybe this code will be useful:
MXML file
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:classes="com.classes.*">
<classes:CollapsiblePanel id="cp" title="Profundidad (Click me)" open="false">
<mx:DataGrid>
<mx:ArrayList>
<fx:Object Cantidad="" Precio=""/>
</mx:ArrayList>
</mx:DataGrid>
</classes:CollapsiblePanel>
</s:Application>
CollapsiblePanel.as. Note that in my case, this class is in com.classes package, you can put this in the place as you want.
package com.classes {
import flash.events.*;
import mx.effects.AnimateProperty;
import mx.events.*;
import mx.containers.Panel;
import mx.core.ScrollPolicy;
[Style(name="closedIcon", property="closedIcon", type="Object")]
[Style(name="openIcon", property="openIcon", type="Object")]
public class CollapsiblePanel extends Panel {
private var _creationComplete:Boolean = false;
private var _open:Boolean = true;
private var _openAnim:AnimateProperty;
public function CollapsiblePanel(aOpen:Boolean = true):void
{
super();
open = aOpen;
this.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
}
private function creationCompleteHandler(event:FlexEvent):void
{
this.horizontalScrollPolicy = ScrollPolicy.OFF;
this.verticalScrollPolicy = ScrollPolicy.OFF;
_openAnim = new AnimateProperty(this);
_openAnim.duration = 300;
_openAnim.property = "height";
titleBar.addEventListener(MouseEvent.CLICK, headerClickHandler);
_creationComplete = true;
}
private function headerClickHandler(event:MouseEvent):void { toggleOpen(); }
private function callUpdateOpenOnCreationComplete(event:FlexEvent):void { updateOpen(); }
private function updateOpen():void
{
if (!_open) height = closedHeight;
else height = openHeight;
setTitleIcon();
}
private function get openHeight():Number {
return measuredHeight;
}
private function get closedHeight():Number {
var hh:Number = getStyle("headerHeight");
if (hh <= 0 || isNaN(hh)) hh = titleBar.height;
return hh;
}
private function setTitleIcon():void
{
if (!_open) this.titleIcon = getStyle("closedIcon");
else this.titleIcon = getStyle("openIcon");
}
public function toggleOpen():void
{
if (_creationComplete && !_openAnim.isPlaying) {
_openAnim.fromValue = _openAnim.target.height;
if (!_open) {
_openAnim.toValue = openHeight;
_open = true;
dispatchEvent(new Event(Event.OPEN));
}else{
_openAnim.toValue = _openAnim.target.closedHeight;
_open = false;
dispatchEvent(new Event(Event.CLOSE));
}
setTitleIcon();
_openAnim.play();
}
}
public function get open():Boolean {
return _open;
}
public function set open(aValue:Boolean):void {
_open = aValue;
if (_creationComplete) updateOpen();
else this.addEventListener(FlexEvent.CREATION_COMPLETE, callUpdateOpenOnCreationComplete, false, 0, true);
}
override public function invalidateSize():void {
super.invalidateSize();
if (_creationComplete)
if (_open && !_openAnim.isPlaying) this.height = openHeight;
}
}
}
Yon can see this SWF in action here.
The source code of this collapsible panel is here.
I hope this will be help you.
After changing my OS's decimal separator as explained here:
( http://blogmines.com/blog/2010/03/11/how-to-change-the-decimal-separator-in-excel-2010/ ), I want to display a number in Flex that uses a comma for both the thousands separator and the decimal separator. Sounds simple enough, right?
I tried using three different NumberFormatters offered by Flex. Along the way, I learned that two of them didn't play well with others in the same class, even if using fully qualified class paths when declaring the variables, so I had to split them up into three classes, like so:
NF1 - spark.formatters.NumberFormatter
package dstrube
{
import flash.globalization.NumberParseResult;
import spark.formatters.NumberFormatter;
public class NF1
{
public static function get(value:String):String{
var nf1:NumberFormatter = new NumberFormatter();
var result:NumberParseResult = nf1.parse(value);
return nf1.format(result.value);
}
}
}
NF2 - flash.globalization.NumberFormatter
package dstrube
{
import flash.globalization.NumberParseResult;
import flash.globalization.NumberFormatter;
public class NF2
{
public static function get(value:String):String{
var nf2:NumberFormatter = new NumberFormatter("");// LocaleID.DEFAULT = same outcome as without
nf2.fractionalDigits = 2; //= same outcome as without
nf2.trailingZeros = true;
var result:NumberParseResult = nf2.parse(value);
//nf2.parseNumber(value); = NaN
return nf2.formatNumber(result.value)
}
}
}
NF3 - mx.formatters.NumberFormatter (deprecated)
package dstrube
{
//import mx.formatters.NumberBaseRoundType;
import mx.formatters.NumberFormatter;
public class NF3
{
public static function get(value:String):String{
var nf3:NumberFormatter = new NumberFormatter();
//nf3.rounding = NumberBaseRoundType.NEAREST; //no effect in this case
return nf3.format(value);
}
}
}
and finally, the main
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
creationComplete="init()"
>
<fx:Script>
<![CDATA[
import dstrube.NF1;
import dstrube.NF2;
import dstrube.NF3;
[Bindable]
public var s:String = "";
protected function init():void{
var value:String = "5558049.90360013";
s = "spark.formatters.NumberFormatter = " + NF1.get(value); //5,558,049.90
s += "\n flash.globalization.NumberFormatter = " + NF2.get(value);//5,558,049,00
s += "\n mx.formatters.NumberFormatter = " + NF3.get(value); //5,558,049.90360013
}
]]>
</fx:Script>
<s:TextArea id="textArea" text="{s}" width="100%" height="100%" />
</s:Application>
The smartest of the three NumberFormatters is flash.globalization.NumberFormatter for recognizing decimal separator, but it rounds incorrectly, showing 5,558,049,00 instead of 5,558,049,90
Any ideas?
You can either:
Explicitly setting the formatter's properties will give you the
output you require.
Set the formatter to use the default locale.
[Bindable] protected var formatted:String;
protected function init(event:FlexEvent):void
{
var formatter:NumberFormatter = new NumberFormatter();
// Option 1 set explicitly
formatter.decimalSeparator = ",";
formatter.fractionalDigits = 2;
formatter.trailingZeros = true;
// Option 2 set default locale to be the locale
formatter.setStyle("locale", LocaleID.DEFAULT);
formatted = formatter.format("5558049.90360013");
}
]]>
</fx:Script>
<s:Label text="{formatted}" />
The output is "5,558,049,90".
This way will display whatever the decimal separator is set to be in the OS's settings.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
initialize="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import spark.formatters.NumberFormatter;
import flash.globalization.NumberFormatter;
[Bindable] protected var formatted:String;
protected function init(event:FlexEvent):void
{
var formatter:spark.formatters.NumberFormatter = new spark.formatters.NumberFormatter();
var nf2:flash.globalization.NumberFormatter = new flash.globalization.NumberFormatter("");
formatter.decimalSeparator = nf2.decimalSeparator;
formatter.fractionalDigits = 2;
formatter.trailingZeros = true;
formatted = formatter.format("5558049.90360013");
}
]]>
</fx:Script>
<s:Label text="{formatted}" />
</s:Application>
I'd be extremely grateful if somebody could help me, or point me in the right direction.
I've been trying to get an adobe air application start in system tray, so far I've used this snippet: http://www.swamicharan.com/blog/air/minimizing-an-air-app-to-systemtray/ which works as described, however no matter what I do I can't seem to make it start, minimized, in the system tray. This is the code I have so far:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="300" height="100" creationComplete="initApp()" layout="horizontal">
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
private var trayIcon:BitmapData;
public function initApp():void{
loadTrayIcon();
this.addEventListener(Event.CLOSING, minToTray);
}
public function loadTrayIcon():void{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, readyToTray);
loader.load(new URLRequest("assets/icon.PNG"));
}
private function minToTray(event:Event):void{
event.preventDefault();
dock();
}
public function readyToTray(event:Event):void{
trayIcon = event.target.content.bitmapData;
var myMenu:NativeMenu = new NativeMenu();
var openItem:NativeMenuItem = new NativeMenuItem("Options");
var closeItem:NativeMenuItem = new NativeMenuItem("Close");
openItem.addEventListener(Event.SELECT, unDock);
closeItem.addEventListener(Event.SELECT, closeApp);
myMenu.addItem(openItem);
myMenu.addItem(new NativeMenuItem("", true));
myMenu.addItem(closeItem);
if(NativeApplication.supportsSystemTrayIcon){
SystemTrayIcon(NativeApplication.nativeApplication.icon).tooltip = "Notifier";
SystemTrayIcon(NativeApplication.nativeApplication.icon).
addEventListener(MouseEvent.CLICK, unDock);
stage.nativeWindow.addEventListener(
NativeWindowDisplayStateEvent.DISPLAY_STATE_CHANGING, winMinimized);
SystemTrayIcon(NativeApplication.nativeApplication.icon).menu = myMenu;
}
}
private function winMinimized(displayStateEvent:NativeWindowDisplayStateEvent):void{
if(displayStateEvent.afterDisplayState == NativeWindowDisplayState.MINIMIZED){
displayStateEvent.preventDefault();
dock();
}
}
public function dock():void{
stage.nativeWindow.visible = false;
NativeApplication.nativeApplication.icon.bitmaps = [trayIcon];
}
public function unDock(event:Event):void{
stage.nativeWindow.visible = true;
stage.nativeWindow.orderToFront();
NativeApplication.nativeApplication.icon.bitmaps = [];
}
private function closeApp(event:Event):void{
stage.nativeWindow.close();
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
s|WindowedApplication
{
skinClass:ClassReference("spark.skins.spark.SparkChromeWindowedApplicationSkin");
background-color:#999999;
background-alpha:"0.7";
}
</fx:Style>
<s:Label text="Hello AIR"/>
</mx:WindowedApplication>
Many Thanks.
I think you'll manage by calling dock() at the end of readyToTray(event:Event).
To make sure your initialWindow is invisible when it launches you can set it's visible property to false in the application descriptor file.
The following is my codes. This is still work in progress; so, you will see some functions with empty contents. Plus, this is my first Flex application; please bear with me.
This is a quiz application that gets the questions and answers to each questions from a ColdFusion web service. There are three types of questions, True or False, Multiple Choice with single selection, and Multiple Choice with multiple selections. So, based upon the question type, the application would dynamically generate the appropriate amount of radio buttons or check boxes for the users to select. I got these working. The problem that I am having is, I am not sure how to check what the users have actually selected. In some other forums and posts on other web site, it said that I can use event.currentTarget.selectedValue to get the user selection. But when I actually do it, I got a run-time error saying, "Property selectedValue not found on mx.controls.FormItem and there is no default value." My question is, what do I need to do to capture the user selections?
Thanks in advance,
Monte
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="initVars()">
<fx:Declarations>
<s:RemoteObject id="CFCertService" destination="ColdFusion" source="CFCertExam.cfquiz">
<s:method name="returnQuestions" result="resultHandler(event)"/>
<s:method name="returnAnswers" result="answerHandler(event)"/>
</s:RemoteObject>
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.containers.FormItem;
import mx.controls.Alert;
import mx.controls.CheckBox;
import mx.controls.RadioButton;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;
[Bindable]
private var questionArray:ArrayCollection;
private var questionType:String;
private var answerItem:FormItem;
[Bindable]
private var currentQuestionCounter:int;
[Bindable]
private var answerArray:ArrayCollection;
private var myOptionButton:RadioButton = new RadioButton();
private var myOptionButton2:RadioButton = new RadioButton();
private function initVars():void {
currentQuestionCounter = 0;
btnPrev.enabled = false;
btnNext.enabled = false;
}
private function answerHandler(event:ResultEvent):void {
answerArray = event.result as ArrayCollection;
var i:int;
answerForm.removeAllChildren();
answerItem = new FormItem();
answerForm.addChild(answerItem);
switch (questionType) {
case "True or False":
{
myOptionButton.label = "True";
if (answerArray.getItemAt(0).Answer_Choice == "True") {
myOptionButton.value = 1;
} else {
myOptionButton.value = 0;
}
answerItem.addChild(myOptionButton);
myOptionButton2.label = "False";
if (answerArray.getItemAt(0).Answer_Choice == "False") {
myOptionButton2.value = 1;
} else {
myOptionButton2.value = 0;
}
answerItem.addChild(myOptionButton2);
answerItem.addEventListener(MouseEvent.CLICK, selectionHandler);
break;
}
case "Multiple Choice (Single Selection)":
{
for (i=0; i<answerArray.length; i++) {
var myOptionButton1:RadioButton = new RadioButton();
myOptionButton1.label = answerArray.getItemAt(i).Answer_Choice;
if (answerArray.getItemAt(i).Corect_Flag == "1") {
myOptionButton1.value = 1;
} else {
myOptionButton1.value = 0;
}
answerItem.addChild(myOptionButton1);
}
break;
}
case "Multiple Choice (Multiple Selection)":
{
for (i=0; i<answerArray.length; i++) {
var myCheckBox:CheckBox = new CheckBox();
myCheckBox.label = answerArray.getItemAt(i).Answer_Choice;
answerItem.addChild(myCheckBox);
}
break;
}
}
answerForm.x = 380;
answerForm.y = 200;
}
private function selectionHandler(event:MouseEvent):void {
Alert.show(event.currentTarget.toString());
}
private function resultHandler(event:ResultEvent):void {
questionArray = event.result as ArrayCollection;
txt1Questions.htmlText = questionArray.getItemAt(currentQuestionCounter).Question_Text;
questionType = questionArray.getItemAt(currentQuestionCounter).Question_Type;
btnNext.enabled = true;
CFCertService.returnAnswers(questionArray.getItemAt(currentQuestionCounter).Question_ID);
}
private function buttonEventHandler():void {
CFCertService.returnQuestions();
btnStartExam.enabled = false;
}
private function btnPrevEventHandler():void {
currentQuestionCounter--;
if (currentQuestionCounter == 0) {
btnPrev.enabled = false;
}
if (currentQuestionCounter < questionArray.length) {
btnNext.enabled = true;
}
txt1Questions.htmlText = questionArray.getItemAt(currentQuestionCounter).Question_Text;
questionType = questionArray.getItemAt(currentQuestionCounter).Question_Type;
CFCertService.returnAnswers(questionArray.getItemAt(currentQuestionCounter).Question_ID);
}
private function answerReturnHandler(questionIndex:int):void {
}
private function btnNextEventHandler():void {
currentQuestionCounter++;
if (currentQuestionCounter > 0) {
btnPrev.enabled = true;
}
if (currentQuestionCounter >= (questionArray.length - 1)) {
btnNext.enabled = false;
}
txt1Questions.htmlText = questionArray.getItemAt(currentQuestionCounter).Question_Text;
questionType = questionArray.getItemAt(currentQuestionCounter).Question_Type;
CFCertService.returnAnswers(questionArray.getItemAt(currentQuestionCounter).Question_ID);
}
]]>
</fx:Script>
<mx:Text id="txt1Questions" x="129" y="124"/>
<s:Button id="btnStartExam" label="Start Exam" click="buttonEventHandler()" x="370" y="54"/>
<mx:Form id="answerForm"/>
<s:Button x="129" y="436" label="Previous" id="btnPrev" click="btnPrevEventHandler()" enabled="false"/>
<s:Button x="642" y="436" label="Next" id="btnNext" click="btnNextEventHandler()" enabled="false"/>
</s:Application>
The problem in your code is that currentTarget references the UIComponent that you add the event listener to, which you added to the FormItem and not the RadioButtons.
Two Options
If you want to continue to add the event listener to the FormItem, you should use target instead of currentTarget to obtain the reference to the actual item clicked, rather than the UIComponent with the listener on it. However, you should be aware that if you add anything else to the FormItem (e.g., Labels, RichText, etc), those items will also trigger the event listener when clicked.
The other option is to add event listeners (they can all use selectionHandler) to each of the RadioButtons and then currentTarget will work fine.
Also, you might want to use a RadioButtonGroup for those questions which only allow a single selection. Then you would only need to use the Event.CHANGE on the RadioButtonGroup to trigger your selectionHandler.
Additional Resource
Check out the video on event bubbling from the Flex in a Week series.