10 Replies Latest reply on Aug 12, 2009 8:39 AM by Paul Reilly

    Data binding, set variable after RadioButtonGroup has been populated

    tobi3

      Hi

       

      I have a RadioButtonGroup:

       

      <mx:RadioButtonGroup id="lineSelector"/>

       

      I get some XML from the server, then the radio buttons are laid out:

       

      <mx:Repeater dataProvider="{itemsXmlItems}"
          id="lineRepeater">
          <mx:RadioButton
              groupName="lineSelector"
              label="Line {lineRepeater.currentItem.id}: {lineRepeater.currentItem.string}"
              value="{lineRepeater.currentItem.id}"
              selected="{lineRepeater.currentItem.ischecked}"
              width="660"
              click="handleLineSelection(event)"/>
      </mx:Repeater>

       

      After that happened, I need to set a global variable (as source for a data binding).

       

      The variable should be set to a value depending on lineSelector.selectedValue (even after the page has loaded and nothing has been clicked). Thus it can only be set after the whole RadioButtonGroup with all RadioButtons have been laid out. How to set up an event handler so that it will be called at that point in time?

       

      Tobi

        • 1. Re: Data binding, set variable after RadioButtonGroup has been populated
          Gregory Lafrance Level 6

          You could use the repeatEnd event of the repeater, or the creationComplete event of the application or component.

           

          If this post answers your question or helps, please mark it as such.

          1 person found this helpful
          • 2. Re: Data binding, set variable after RadioButtonGroup has been populated
            tobi3 Level 1

            To Greg: Thanks for your reply! If I remember correctly, neither of the suggestions was a fit for my problem. I probably should've posted the whole file, then it would have been easier for you (etc) to find the right solution.

             

            To everyone: Below is the current example file. Please read the script / XML comments in that file, especially "Line 1" -> "Question".

             

            <?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/halo"
                minWidth="
            1024" minHeight="768"
                creationComplete="
            getLines()" viewSourceURL="srcview/index.html">
                <s:layout>
                    <s:VerticalLayout
                        paddingLeft="
            20" paddingRight="20"
                        paddingTop="
            20" paddingBottom="20"/>
                </s:layout>
                <fx:Script><![CDATA[

            import mx.controls.Alert;
            import mx.rpc.http.HTTPService;
            import mx.rpc.events.ResultEvent;
            import mx.rpc.events.FaultEvent;
            import mx.collections.XMLListCollection;

            Bindable] 
            public var itemsXml:XML;

            Bindable] 
            public var itemsXmlItems:XMLListCollection;

            Bindable] 
            public var currentLine:String;

            public function getLines():void {
                var service:HTTPService = new HTTPService();
                service.url = 'http://www.rubynaut.com/dummy_data/lines.xml';
                service.resultFormat = "e4x";
                service.addEventListener("fault", fault);
                service.addEventListener("result", getLinesResult);
                service.send();
            }

            public function fault(event:FaultEvent):void {
                var faultString:String = event.fault.faultString;
                Alert.show(faultString);
            }

            public function getLinesResult(event:ResultEvent):void {
                itemsXml= event.result as XML;
                itemsXmlItems = new XMLListCollection(itemsXml.line);
                // Doesn't work here:
                // setLine();
            }

            public function handleLineSelection(evt:MouseEvent):void {
                setLine();
            }

            public function setLine():void {
                var currentLineId:String = lineSelector.selectedValue.toString();
                currentLine = itemsXml.line.(id == currentLineId).string;
            }

            public function getLine():String {
                var result:String = itemsXml.line.(id == lineSelector.selectedValue.toString()).string;
                return result;
            }

            public function idToLine(idArg:String):String {
                return itemsXml.line.(id == idArg).string;
            }

                ]]></fx:Script>
                <fx:Declarations>
                    <mx:RadioButtonGroup id="lineSelector"/>
                </fx:Declarations>
                <s:HGroup>
                    <s:Panel title="Lines" width="400" horizontalCenter="0">
                        <s:layout>
                            <s:VerticalLayout
                                paddingLeft="
            20" paddingRight="20"
                                paddingTop="
            20" paddingBottom="20"/>
                        </s:layout>
                        <s:VGroup>
                            <s:SimpleText>Select current line:</s:SimpleText>
                            <mx:VBox>
                                <mx:Repeater dataProvider="{itemsXmlItems}"
                                    id="
            lineRepeater">
                                    <!-- Doesn't work here:
                                     repeatEnd="setLine()"
            -->
                                    <mx:RadioButton
                                        width="
            660"
                                        groupName="
            lineSelector"
                                        label="
            Line {lineRepeater.currentItem.id}"
                                        value="
            {lineRepeater.currentItem.id}"
                                        selected="
            {lineRepeater.currentItem.ischecked}"
                                        click="
            handleLineSelection(event)"/>
                                        <!-- With Solution 4 (Line 4 ) the above line can be deleted. -->
                                </mx:Repeater>
                            </mx:VBox>
                        </s:VGroup>
                    </s:Panel>
                    <s:Panel title="Current Line" width="500">
                        <s:layout>
                            <s:VerticalLayout
                                paddingLeft="
            20" paddingRight="20"
                                paddingTop="
            20" paddingBottom="20"/>
                        </s:layout>
                        <!-- Line 1
                        This line works: There's text when a radio button is clicked.
                        But: Right after page load (or reload), the text is not set.
                        Question: Where could I call setLine()? It should be called after
                        the RadioButtonGroup has been populated.
                        <s:SimpleText text="{currentLine}"/>
                       
            -->
                        <!-- Line 2
                        This line works: There's text when a radio button is clicked.
                        And: Right after page load (or reload), the text is set.
                        <s:SimpleText text="{itemsXml.line.(id == lineSelector.selectedValue.toString()).string}"/>
                       
            -->
                        <!--
                        But the above line is long.
                       
            -->
                        <!-- Line 3
                        Wrapping the long expression in a function doesn't work,
                        the text is not set at all.
                        <s:SimpleText text="{getLine()}"/>
                       
            -->
                        <!--
                        It seems that binding expressions inside curly braces must always
                        contain the source property.
                        http://livedocs.adobe.com/flex/gumbo/html/ -> "Data Binding"
                        "Using ActionScript expressions in curly braces":
                        "you can use the curly braces syntax for the following types of binding":
                        "Calculations on a bindable property inside curly braces", etc.
                       
            -->
                        <!-- Line 4
                        Here's a line that's shorter than line 2 and works:
                        There's text when a radio button is clicked.
                        And: Right after page load (or reload), the text is set.
                       
            -->
                        <s:SimpleText text="{idToLine(lineSelector.selectedValue.toString())}"/>
                    </s:Panel>
                </s:HGroup>
            </s:Application>
            • 3. Re: Data binding, set variable after RadioButtonGroup has been populated
              Paul Reilly Level 1

              I tried your "line 1" option and it seems to be working just fine as long as setLine() checks for a null lineSelector.selectedValue before calling toString() on it.  I suspect that if your xml had "ischecked" set to true, then lineSelector.selectedValue would not be null initially.

              • 4. Re: Data binding, set variable after RadioButtonGroup has been populated
                tobi3 Level 1

                BTW, in the code listing above, the three lines lines starting with "Bindable]" should start with with "[Bindable]".

                • 5. Re: Data binding, set variable after RadioButtonGroup has been populated
                  tobi3 Level 1

                  Hi Paul,

                   

                  Thanks for your reply.

                   

                  > I tried your "line 1" option and it seems to be working just fine

                   

                  Like I said in the comment in the file:

                   

                  Line 1: This line works: There's text when a radio button is clicked.
                  But: Right after page load (or reload), the text is not set.

                   

                  > I suspect that if your xml had "ischecked" set to true, then lineSelector.selectedValue would not be null initially.

                   

                  I wouldn't want to change the data in order to fix the UI

                   

                  So the question remains: Where could I call setLine()? (It should be called after the RadioButtonGroup has been populated.)

                   

                  Solution "Line 4" works perfectly - I'm just curious how to implement the setLine() / SimpleText text="{currentLine}" approach.

                   

                  Tobi

                  • 6. Re: Data binding, set variable after RadioButtonGroup has been populated
                    Paul Reilly Level 1

                    > Line 1: This line works: There's text when a radio button is clicked.
                    > But: Right after page load (or reload), the text is not set.

                     

                    This is because none of the radio buttons are selected.

                     

                    > I wouldn't want to change the data in order to fix the UI

                     

                    If this is the case, then you shouldn't have the following line:

                     

                      selected="{lineRepeater.currentItem.ischecked}"

                     

                    > So the question remains: Where could I call setLine()? (It should be called after the 

                    > RadioButtonGroup has been populated.)

                     

                    The repeatEnd event handler.

                     

                    > Solution "Line 4" works perfectly - I'm just curious how to implement the setLine() /

                    > SimpleText text="{currentLine}" approach.

                     

                    It doesn't work perfectly.  You are relying on some framework side effect that selects a RadioButton if none of them are selected.  For me, that's line 11, which seems arbitrary. I tried looking through the framework source code to track this down, but it didn't jump out at me.  Regardless, you are much better off explicitly setting the selection if there isn't one and setLine() looks like a good place to do that.

                    1 person found this helpful
                    • 7. Re: Data binding, set variable after RadioButtonGroup has been populated
                      Gregory Lafrance Level 6

                      If this post answered your question or helped, please mark it as such.

                       

                      This code from another post I replied to may not fit your requirements, but it might help, and if not at least it will contribute to your knowledge of repeaters and radio buttons therein:

                       

                      <?xml version="1.0" encoding="utf-8"?>
                      <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
                        <mx:Script>
                         <![CDATA[
                            import mx.collections.ArrayCollection;
                            import mx.events.ItemClickEvent;
                         
                            [Bindable] private var ac:ArrayCollection = new ArrayCollection([
                              {img: "test1", vals: [10, 20, 30, 40]},
                              {img: "test2", vals: [15, 20, 100]},
                              {img: "test3", vals: [100, 200, 300, 400, 500]}
                            ]);
                          ]]>
                        </mx:Script>
                        <mx:DataGrid dataProvider="{ac}" width="680" height="480"
                          variableRowHeight="true" alternatingItemColors="[0xff0000, 0x0000ff]">
                          <mx:columns>
                            <mx:DataGridColumn dataField="img"/>
                            <mx:DataGridColumn dataField="vals">
                              <mx:itemRenderer>
                                <mx:Component>
                                  <mx:VBox>
                                    <mx:Text id="txt" fontSize="20"/>
                                    <mx:RadioButtonGroup id="grp" itemClick="txt.text = RadioButton(event.relatedObject).label;"/>
                                    <mx:Repeater id="rp" dataProvider="{data.vals}">
                                      <mx:RadioButton label="{rp.currentItem}" groupName="grp"/>
                                    </mx:Repeater>
                                  </mx:VBox>
                                </mx:Component>
                              </mx:itemRenderer>
                            </mx:DataGridColumn>
                          </mx:columns>
                        </mx:DataGrid>
                      </mx:Application>

                      • 8. Re: Data binding, set variable after RadioButtonGroup has been populated
                        tobi3 Level 1

                        Hi Paul,

                         

                        Thanks for your post!

                         

                        > It doesn't work perfectly.

                         

                        It fulfilled 100% of the requirements I listed.

                         

                        > You are relying on some framework side effect that selects a RadioButton

                        > if none of them are selected.  For me, that's line 11, which seems

                        > arbitrary. I tried looking through the framework source code to track this

                        > down, but it didn't jump out at me.  Regardless, you are much better

                        > off explicitly setting the selection if there isn't one

                         

                        I agree, explicitly setting a specific button is better. Thanks for the suggestion!

                         

                        > and setLine() looks like a good place to do that.

                         

                        I did it by using this attribute on RadioButton:

                         

                            selected="{lineRepeater.currentIndex == 0}"

                         

                        Below are two alternative implementations.

                         

                        To everyone (and Paul ): Please see "Question:" in the code below.

                         

                        <?xml version="1.0" encoding="utf-8"?>
                        <!--
                        If you run this from within Flash Builder and run the
                        app in Firefox: If you get "Security error accessing url",
                        you might have to turn the Network Monitor off:
                        Right-click on the project folder, Properties ->
                        Flex Compiler -> uncheck Enable network monitor.
                        -->
                        <!--
                        This implementation tries to use the setLine() function.
                        -->
                        <!--
                        The first radio button is selected. But in setLine(),
                        lineSelector.selectedValue is null.

                        Question:
                        How could I change this example so that the Current Line is
                        set after page load?
                        -->
                        <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/halo"
                            minWidth="
                        1024" minHeight="768"
                            creationComplete="
                        downloadLines()" viewSourceURL="srcview/index.html">
                            <s:layout>
                                <s:VerticalLayout
                                    paddingLeft="
                        20" paddingRight="20"
                                    paddingTop="
                        20" paddingBottom="20"/>
                            </s:layout>
                            <fx:Script><![CDATA[

                        import mx.controls.Alert;
                        import mx.rpc.http.HTTPService;
                        import mx.rpc.events.ResultEvent;
                        import mx.rpc.events.FaultEvent;
                        import mx.collections.XMLListCollection;

                        public var itemsXml:XML;

                        Bindable] 
                        public var itemsXmlItems:XMLListCollection;

                        Bindable] 
                        public var currentLine:String;

                        public function downloadLines():void {
                            var service:HTTPService = new HTTPService();
                            service.url = 'http://www.rubynaut.com/dummy_data/lines.xml';
                            // Or
                            // service.url = 'http://www.rubynaut.com/dummy_data/zero_lines.xml';
                            service.resultFormat = "e4x";
                            service.addEventListener("fault", fault);
                            service.addEventListener("result", downloadLinesResult);
                            service.send();
                        }

                        public function fault(event:FaultEvent):void {
                            var faultString:String = event.fault.faultString;
                            Alert.show(faultString);
                        }

                        public function downloadLinesResult(event:ResultEvent):void {
                            itemsXml= event.result as XML;
                            itemsXmlItems = new XMLListCollection(itemsXml.line);
                        }

                        public function setLine():void {
                            // This line shouldn't be necessary? There should be one
                            // selected radio button because of this line:
                            // selected="{lineRepeater.currentIndex == 0}"
                            if (lineSelector.selectedValue) {
                                var currentLineId:String = lineSelector.selectedValue.toString();
                                currentLine = itemsXml.line.(id == currentLineId).string;
                            }
                        }

                            ]]></fx:Script>
                            <fx:Declarations>
                                <mx:RadioButtonGroup id="lineSelector"/>
                            </fx:Declarations>
                            <s:HGroup>
                                <s:Panel title="Lines" width="400" horizontalCenter="0">
                                    <s:layout>
                                        <s:VerticalLayout
                                            paddingLeft="
                        20" paddingRight="20"
                                            paddingTop="
                        20" paddingBottom="20"/>
                                    </s:layout>
                                    <s:VGroup>
                                        <s:SimpleText>Select current line:</s:SimpleText>
                                        <mx:VBox>
                                            <mx:Repeater id="lineRepeater"
                                                dataProvider="
                        {itemsXmlItems}"
                                                repeatEnd="
                        setLine()">
                                                <mx:RadioButton id="lineSelectorButtons"
                                                    groupName="
                        lineSelector"
                                                    label="
                        Line {lineRepeater.currentItem.id}"
                                                    value="
                        {lineRepeater.currentItem.id}"
                                                    click="
                        setLine()"
                                                    selected="
                        {lineRepeater.currentIndex == 0}"
                                                    width="
                        660"/>
                                            </mx:Repeater>
                                        </mx:VBox>
                                    </s:VGroup>
                                </s:Panel>
                                <s:Panel title="Current Line" width="500">
                                    <s:layout>
                                        <s:VerticalLayout
                                            paddingLeft="
                        20" paddingRight="20"
                                            paddingTop="
                        20" paddingBottom="20"/>
                                    </s:layout>
                                    <s:SimpleText text="{currentLine}"/>
                                </s:Panel>
                            </s:HGroup>
                        </s:Application>

                         

                        The other implementation:

                         

                        <?xml version="1.0" encoding="utf-8"?>
                        <!--
                        If you run this from within Flash Builder and run the
                        app in Firefox: If you get "Security error accessing url",
                        you might have to turn the Network Monitor off:
                        Right-click on the project folder, Properties ->
                        Flex Compiler -> uncheck Enable network monitor.
                        -->
                        <!--
                        The first radio button is selected.
                        In this implementation, there's no setLine() function.
                        Right after page load, the Current Line text is set,
                        and it gets adjusted when a radio button is clicked.
                        -->

                        <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/halo"
                            minWidth="
                        1024" minHeight="768"
                            creationComplete="
                        downloadLines()" viewSourceURL="srcview/index.html">
                            <s:layout>
                                <s:VerticalLayout
                                    paddingLeft="
                        20" paddingRight="20"
                                    paddingTop="
                        20" paddingBottom="20"/>
                            </s:layout>
                            <fx:Script><![CDATA[

                        import mx.controls.Alert;
                        import mx.rpc.http.HTTPService;
                        import mx.rpc.events.ResultEvent;
                        import mx.rpc.events.FaultEvent;
                        import mx.collections.XMLListCollection;

                        public var itemsXml:XML;

                        Bindable] 
                        public var itemsXmlItems:XMLListCollection;

                        public function downloadLines():void {
                            var service:HTTPService = new HTTPService();
                            service.url = 'http://www.rubynaut.com/dummy_data/lines.xml';
                            // Or
                            // service.url = 'http://www.rubynaut.com/dummy_data/zero_lines.xml';
                            service.resultFormat = "e4x";
                            service.addEventListener("fault", fault);
                            service.addEventListener("result", downloadLinesResult);
                            service.send();
                        }

                        public function fault(event:FaultEvent):void {
                            var faultString:String = event.fault.faultString;
                            Alert.show(faultString);
                        }

                        public function downloadLinesResult(event:ResultEvent):void {
                            itemsXml= event.result as XML;
                            itemsXmlItems = new XMLListCollection(itemsXml.line);
                        }

                        public function idToLine(idArg:String):String {
                            return itemsXml.line.(id == idArg).string;
                        }

                            ]]></fx:Script>
                            <fx:Declarations>
                                <mx:RadioButtonGroup id="lineSelector"/>
                            </fx:Declarations>
                            <s:HGroup>
                                <s:Panel title="Lines" width="400" horizontalCenter="0">
                                    <s:layout>
                                        <s:VerticalLayout
                                            paddingLeft="
                        20" paddingRight="20"
                                            paddingTop="
                        20" paddingBottom="20"/>
                                    </s:layout>
                                    <s:VGroup>
                                        <s:SimpleText>Select current line:</s:SimpleText>
                                        <mx:VBox>
                                            <mx:Repeater id="lineRepeater"
                                                dataProvider="
                        {itemsXmlItems}">
                                                <mx:RadioButton id="lineSelectorButtons"
                                                    groupName="
                        lineSelector"
                                                    label="
                        Line {lineRepeater.currentItem.id}"
                                                    value="
                        {lineRepeater.currentItem.id}"
                                                    selected="
                        {lineRepeater.currentIndex == 0}"
                                                    width="
                        660"/>
                                            </mx:Repeater>
                                        </mx:VBox>
                                    </s:VGroup>
                                </s:Panel>
                                <s:Panel title="Current Line" width="500">
                                    <s:layout>
                                        <s:VerticalLayout
                                            paddingLeft="
                        20" paddingRight="20"
                                            paddingTop="
                        20" paddingBottom="20"/>
                                    </s:layout>
                                    <s:SimpleText
                                        text="
                        {idToLine(lineSelector.selectedValue.toString())}"/>
                                </s:Panel>
                            </s:HGroup>
                        </s:Application>

                         

                        Tobi

                        • 9. Re: Data binding, set variable after RadioButtonGroup has been populated
                          tobi3 Level 1

                          Hi

                           

                          I'd still be interested in an answer to the question in the first of

                          the two listings above.


                          How could I change this example so that the Current Line [variable
                          currentLine

                          is set after page load?

                           

                          Where / when could I call setLine(), so that lineSelector.selectedValue is

                          not null when it's called?

                          So that this line works:

                          currentLine = itemsXml.line.(id == currentLineId).string;

                           

                          Tobi

                          • 10. Re: Data binding, set variable after RadioButtonGroup has been populated
                            Paul Reilly Level 1

                            To solve your problem, I would check if a value is selected in setLine() and if not, set one.  To fully answer your question, you'll have to dig into the framework and figure out how the implicit selectedValue selection works.  One way to do that is to set a breakpoint in the selectedValue setter and look at the stack to see how it gets there.