How to check the state of a Radio Button in Flex 3

2019-08-23 14:52发布

问题:

I'm working on a template for dynamic questionnaires in Flex. More detailed description in my previous thread HERE

To create the questionnaire, I use nested repeaters - one for the questions and one for the answers (as their amount may vary).

<mx:Repeater id="r" dataProvider="{questions}">
   <mx:Label text="{r.currentItem.question}" width="200"/>
      <mx:Repeater id="r2" dataProvider="{r.currentItem.answers}">
         <mx:RadioButton label="{r2.currentItem.text}" width="200"                                          
          click="answerHandler(event, event.currentTarget.getRepeaterItem())"/>
      </mx:Repeater>
</mx:Repeater>

To understand my data providers, it's probably best to check the answer for my previous thread - easier than if I try to explain it here.

The question here is... As you can see, I created click event handler for each radio button and my plan was to do playerScore++ every time the user chose correctly (which can be achieved by checking the Boolean property "correct" of sent RepeaterItem).

However, I see now that even if the button is selected already, I can still click on it more times, and even though it's not changing anything in the view, it increments the score every time.. I would also have to handle situation in which the user changes his mind (I could give + points for each good answer and - points for wrong, but this would mean, that if the user chose more wrong answers, my score will be negative and I don't want it).

So it would be way way easier to just have a Submit button and check the states of all my buttons and if they are correct only after the user clicks "submit". Is it possible?

回答1:

I recommend you to refer to the following sample and add RadioButtonGroup to your repeater groups and listen to change events instead of click. You can listen change event right in RadioButtonGroup and check if (radioGroup.selectedValue.correct) for correctness of new selection. See corresponding documentation.

To have possibility to assign radiogroups unique name you have to extract inner repeater with answers into separate component. Breaking your application into smaller components can make your application more clear and readable. You can treat every MXML file as a class (as in OOP) but in declarative form. And to tell the true every MXML component is a class which inherited from root-node-class.

Lets look at the code.

First, our inner component which serves answers:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Metadata>
        [Event(name="rightAnswerEvent", type="AnswerEvent")]
    </mx:Metadata>
    <mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        public var answers:ArrayCollection;

        protected function answerGroup_changeHandler(event:Event):void
        {
            if (answerGroup.selectedValue.correct)
                dispatchEvent(new AnswerEvent(AnswerEvent.RIGHT_ANSWER_EVENT));
        }
    ]]>
    </mx:Script>

    <mx:RadioButtonGroup change="answerGroup_changeHandler(event)" id="answerGroup" />
    <mx:Repeater dataProvider="{answers}" id="answersRepeater">
        <mx:RadioButton group="{answerGroup}" label="{answersRepeater.currentItem.text}"
            value="{answersRepeater.currentItem}" />
    </mx:Repeater>
</mx:VBox>

It gets answers collection as input and fires our custom event to inform some components about right answer (see Metadata tag).

Our custom event is pretty simple an looks like the following:

package
{
import flash.events.Event;

public class AnswerEvent extends Event
{
    public static const RIGHT_ANSWER_EVENT:String = "rightAnswerEvent";

    public function AnswerEvent(type:String)
    {
        super(type);
    }
}
}

So now our top level component:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="vertical" xmlns:local="*"
    xmlns:mx="http://www.adobe.com/2006/mxml">
    <mx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        private var questions:ArrayCollection = new ArrayCollection();

        [Bindable]
        private var scoreCounter:int;
    ]]>
    </mx:Script>
    <mx:Label text="{'Score ' + scoreCounter}" />
    <mx:Repeater dataProvider="{questions}" id="questionRepeater">
        <mx:Label text="{questionRepeater.currentItem.question}" />
        <local:AnswerGroup answers="{questionRepeater.currentItem.answers}" rightAnswerEvent="scoreCounter++" />
    </mx:Repeater>
</mx:Application>

I omitted initialization code to populate our Question and Answer domain objects with data from XML (see previous thread).

So now we have compact modularized code where every part solves its own task.

Hope this helps!