6 Replies Latest reply on May 19, 2011 3:15 AM by mumcs01

    Cascading s:dropDownLists with changing values / dataprovidor problems

    mumcs01 Level 1

      So I've been pulling my hair out on this, should be simple topic for over a week now, and I"m just stumped. I've tried everything I can think of. Here's the story. I have an XML file I"m reading that is being turned into an object, then an array collection on the load of the application. All is good. Its a definition file to determine what 4 dropDownLists will offer. When a user changes dropdown #1, it can change the options of #2, and consiquently #3 and so on. When they then select #2, it can change the options offered on #3. I also need to set defaults of each based on the XML file. Anyway. Below is the Flex for these.

       

      <mx:Form x="17" y="80" width="351" height="137" >
      <s:DropDownList id="dModuleType" dataProvider="{validSelections}" labelField="name" width="70" x="276" y="47" fontSize="8" height="12" requireSelection="true" visible="{ Globals.SHOW_DEBUG_FIELDS }" open="dModuleType_openHandler(event)"/>
      <mx:FormItem id="lFiringMode" label="Firing Mode">
        <s:DropDownList id="dFiringMode" dataProvider="{ dModuleType.selectedItem.firingmode }" labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dFiringMode')"/>
      </mx:FormItem>
      <mx:FormItem id="lControlMode" label="Control Mode">
        <s:DropDownList id="dControlMode" dataProvider="{ dFiringMode.selectedItem.control } " labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dControlMode')"/>
      </mx:FormItem>
      <mx:FormItem id="lCurve" label="Curve">
        <s:DropDownList id="dCurve" dataProvider="{ dControlMode.selectedItem.curve }" labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dCurve')"/>
      </mx:FormItem>

      </mx:Form>

       

      This all works... until I change the The second dropdown box (or the 3rd or 4). Below is the event handler:

       

      protected function buildValidSelection(event:IndexChangeEvent = null, _function:String = null):void
      {
        if (_function == 'dFiringMode') { currentRecord.firingMode = dFiringMode.selectedItem.value; }
        if (_function == 'dControlMode') { currentRecord.controlMode = dControlMode.selectedItem.value; }
        if (_function == 'dCurve') { currentRecord.curve = dCurve.selectedItem.value; }
        validSelections.removeAll();
        var moduleNumber:int = findModule(moduleDb, currentRecord.moduleType);
        validSelections.addItem(( moduleDb[moduleNumber] );
        dFiringMode.selectedIndex = findIndex(validSelections[0].firingmode, currentRecord.firingMode);
        dControlMode.selectedIndex = findIndex(validSelections[0].firingmode[dFiringMode.selectedIndex].control, currentRecord.controlMode);
        dCurve.selectedIndex = findIndex(validSelections[0].firingmode[dFiringMode.selectedIndex].control[dControlMode.s electedIndex].curve, currentRecord.curve);
      }

      The valid selections is the arraycollection of current values for each dropdownlist, and it is rebuilt with the correct values when a change is made. This seems to work as i run this on init and it shows the correct values. again, the problem only occurs after a change is made to field 2,3, or 4, and all the dropdown choices vanish. According to debug the values are gettting changed in valudSelections, but the dropdownlists are not accepting the new dataprovider changes at the addItem command.....

       

      Any ideas? I'm running out of hair

        • 1. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
          Level 2

          Can u provide a zip with xml included

          • 2. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
            mumcs01 Level 1

            I've done one better. I wrote a small app to regentate the problem. Below is the application and the associated XML file (you can't upload files to the forum? Or maybe I'm missing something). Any help would be great!!!!!!

             

            Notice all the fields populate. Change the dropdownlist labeled 'Firing Mode'. Notice, everything goes away? Weird?

            --------------------------------

             

            <?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"
                  width="386" height="304" preinitialize="preinitializeHandler(event)" >

            <fx:Declarations>
              <mx:HTTPService id="getXmlModuleList" url="data/modules.xml" method="GET" resultFormat="object"/>
              <s:CallResponder id="getModuleListResponse" result="buildModuleDatabase(event)" />
            </fx:Declarations>

            <fx:Script>
              <![CDATA[
               import mx.binding.utils.BindingUtils;
               import mx.collections.ArrayCollection;
               import mx.collections.ArrayList;
               import mx.collections.CursorBookmark;
               import mx.collections.IViewCursor;
               import mx.collections.Sort;
               import mx.collections.SortField;
               import mx.collections.XMLListCollection;
               import mx.events.FlexEvent;
               import mx.messaging.management.Attribute;
               import mx.rpc.events.ResultEvent;
               import mx.utils.ArrayUtil;
              
               import spark.events.DropDownEvent;
               import spark.events.IndexChangeEvent;
              
               protected var cursor:IViewCursor;
               protected var searchObject:Object;  // Used globally as a search object comtainer.
               protected var dimmerUDNSort:Sort = new Sort();
              
               [Bindable] public var _target:int=0;

               public var dimmers:ArrayCollection= new ArrayCollection;
              
               [Bindable] public var moduleDb:ArrayCollection;
               [Bindable] public var validSelections:ArrayCollection = new ArrayCollection;
              
               protected function preinitializeHandler(event:FlexEvent):void
               {
                getModuleListResponse.token = getXmlModuleList.send();
               }
              
               protected function buildModuleDatabase(event:ResultEvent): void
               {
                moduleDb = event.result.moduletable.module as ArrayCollection;
                buildValidSelection();
               }
              
               protected function buildValidSelection(event:IndexChangeEvent = null, _function:String = null):void
               {
                validSelections.removeAll();
                var moduleNumber:int = findModule(moduleDb, "Generic");
                validSelections.addItem( moduleDb[moduleNumber] );
               }
               
               private function findModule(whichArray:ArrayCollection, whichItem:String):int
               {
                var ret_value:int = -1;
                for(var i:int = 0; i < whichArray.length; i++)
                {
                 if(String(whichArray[i].name)==whichItem) {
                  ret_value = i;
                  break;
                 }
                }
                if (whichArray.length == i) { ret_value = 0; } 
                return ret_value;
               }
              
               private function findIndex(whichArray:ArrayCollection, whichItem:String):int
               {
                var ret_value:int = -1;
                for(var i:int = 0; i < whichArray.length; i++)
                {
                 if(String(whichArray[i].value)==whichItem) {
                  ret_value = i;
                  break;
                 }
                }
                return ret_value;
               }

              ]]>
            </fx:Script>

            <s:DropDownList id="dModuleType" dataProvider="{validSelections}" labelField="name" width="70" x="276" y="47" fontSize="8" height="12" requireSelection="true" />
            <mx:Form x="17" y="80" width="351" height="137" >
              <mx:FormItem id="lFiringMode" label="Firing Mode">
               <s:DropDownList id="dFiringMode" dataProvider="{ dModuleType.selectedItem.firingmode }" labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dFiringMode')"/>
              </mx:FormItem>
              <mx:FormItem id="lControlMode" label="Control Mode">
               <s:DropDownList id="dControlMode" dataProvider="{ dFiringMode.selectedItem.control } " labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dControlMode')"/>
              </mx:FormItem>
              <mx:FormItem id="lCurve" label="Curve">
               <s:DropDownList id="dCurve" dataProvider="{ dControlMode.selectedItem.curve }" labelField="label" width="150" requireSelection="true" change="buildValidSelection(event,'dCurve')"/>
              </mx:FormItem>
             
            </mx:Form>
            <s:Button x="304" y="225" label="Apply" id="bApply"/>
            </s:Application>

             

             

            ---- and the XML file ---

             

            <?xml version="1.0" encoding="utf-8"?>
            <moduletable>
            <module name="Generic">
              <firingmode label="Normal" value="Normal">
               <control label="Dimmable" value="Dimmable" threshold="1" default="true" >
                <curve label="Modified Square" value="ModSquare" default="true" />
                <curve label="Linear" value="Linear" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="Off" value="Off" />
               <control label="Switched" value="Switched" threshold="50" >
                <curve label="Circle" value="Circle" />
                <curve label="Square" value="Square" default="true" />
                <curve label="REctangle" value="rectange" />
                <curve label="Pizza" value="pizza" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="Always-On" value="AlwaysOn" />
               <control label="Latch-lock" value="LatchLock">
                <curve label="Weird" value="wierdish" />
                <curve label="Shape" value="shape" default="true" />
                <curve label="thing" value="thing" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
              </firingmode>     
              <firingmode label="Dimmer Double" value="DimDbl">
               <control label="Dimmable" value="Dimmable" threshold="1" default="true" >
                <curve label="Modified Square" value="ModSquare" default="true" />
                <curve label="Linear" value="Linear" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="TestOff" value="TEstOff" />
               <control label="Switched" value="Switched" threshold="50" >
                <curve label="Modified Square" value="ModSquare" />
                <curve label="Linear" value="Linear" default="true" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="Always-On" value="AlwaysOn" />
               <control label="Latch-lock" value="LatchLock">
                <curve label="Modified Square" value="ModSquare" />
                <curve label="Linear" value="Linear" default="true" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
              </firingmode>
              <firingmode label="Fluorescent" value="Fluorescent">
               <control label="Dimmable" value="Dimmable" threshold="1" default="true" >
                <curve label="Modified Square" value="ModSquare" />
                <curve label="Linear" value="Linear" default="true" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="Off" value="Off" />
               <control label="Switched" value="Switched" threshold="50">
                <curve label="Modified Square" value="ModSquare" />
                <curve label="Linear" value="Linear"  default="true" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
               <control label="Always-On" value="AlwaysOn" />
               <control label="Latch-lock" value="LatchLock">
                <curve label="Modified Square" value="ModSquare" />
                <curve label="Linear" value="Linear" default="true" />
                <curve label="Modified Linear" value="ModLinear" />
                <curve label="Sensor 2.0" value="Sensor2.0" />
                <curve label="Custom 1" value="Custom1" />
                <curve label="Custom 2" value="Custom2" />
                <curve label="Custom 3" value="Custom3" />
                <curve label="Custom 4" value="Custom4" />
                <curve label="Custom 5" value="Custom5" />
               </control>
              </firingmode>
            </module>
            </moduletable>

            • 3. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
              Level 2

              i guess just a picture maybe with the camera icon. i will get back to ya

               

              unless you have a zip:   drewpierce@live.com

              • 4. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
                Level 2

                ok i have to fumble. i can get 2 to be in sync but it seems that the 3rd is a sweet spot i can't hit.

                it is based entirely on this:

                http://blog.flexexamples.com/2007/08/04/creating-two-related-comboboxes/

                 

                even tho you have more xml tags so it uses the '@' sign.

                 

                it seems peculiar that even Peter Deehan in his article above has a 3 dimensional xml structure like you but he only displays 2. he had country/Prov/City but did not display city in a drop down perhaps because propogation died ????

                 

                gurus what am i doing wrong ? how do you sync up the 3rd combo box ?? do you have to hand code event listeners for 3rd and below ?

                 

                btw your xml needed some massaging to work here so i had to overhaul it.

                 

                good luck and sorry i could not solve it but look forward to hearing the solution !

                 

                in action:

                http://trumpboston.com/helpothers/example03547/

                 

                source code:

                http://trumpboston.com/helpothers/example03547/skurla.zip

                • 5. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
                  Level 2

                  if you continue to run out of hair on this i have a solution but it is not with bindings and i want to hear about n-tier solutions here.

                   

                  -drew

                  • 6. Re: Cascading s:dropDownLists with changing values / dataprovidor problems
                    mumcs01 Level 1

                    Hey Drew! Thanks for taking a look at it, and I think actally your ideas have sent me in the right direction. I did a little playing around yesterday, and I guess this problem forced me to go back and undersstand the fundamentals of binding at the actionscript level.

                     

                    So here is what I figured out, and i have roughly working, using my original XML file.

                     

                    It seems there is something fundamentally wrong with binding the dataprovidor of one list object to the selecteditem of another in Flex 4 spark. (I went back to flex 3 and seemed to be able to do this without a problem using mx: components. I even found an old post at flexexamples that was doing exactly what I was doing and it worked! However they built the examples on Flex 3). Saying that, it is only when you are binding in Flex in 4 that this problems shows up.

                     

                    The work around:

                     

                    In my init() function I am now setting up bindsetters, and have made functions triggered off of the bindsetter for the first and second dropdownlists to alter the data providor of the next dropdown. Example, Dropdown#1 has a bindsetter to tigger a function when its data providor changes to alter dropdown #2's data providor, and dropdown #2 has a bindsetter to alter dataprovidor #3. With this methodology I only need to assign the data providor once to the first dropdownlist, and the rest is an automatic chain reaction... Most importantly, it all works and there is very little code!

                     

                    I will post an example when I finish it as it seems to be something people would want to do and should be easy.. (and is rather not intuitive. Hopefully it will save someone else the week I lost on this .

                     

                    Again, thanks Drew! you steered me the right way, (and forced me to go back to the fundamentals of binding). Though it seems there is something wrong in the spark dropdownlist component. I can't imagine this is intentional.