6 Replies Latest reply on Sep 16, 2009 6:52 PM by PeakDigital

    Three ComboBoxes Dependent on Each Other - Please Help

    Gregory Lafrance Level 6

      I am trying to figure out how to make the data displayed in three ComboBoxes dependent on each other while not hard-coding business rules in "if" constructs, but instead use an ArrayCollection of invalid combinations.

       

      After compiling the following code and launching, the "$100.00" item in the Tariff ComboBox will be grayed out and inactive
      because its "valid" field is "false".
           
      QUESTION: what should be added to this application to support the following use cases of the ComboBoxes:
                        
      1) If the user selects clothes and China in the Product and Source ComboBoxes, the "valid" field for the "$100.00" item in the "tariff" ArrayCollection changes to "true", so the "$100.00" item is black and active. Also, the "valid" field for the "none" item in the "tariff" ArrayCollection changes to "false", so the "none" item is gray and inactive.

       

      2) If after performing 1) above, the user selects Mexico Source ComboBox, the "valid" field for the "$100.00" item in the "tariff" ArrayCollection changes to "false", so the "$100.00" item is gray and inactive. Also, the "valid" field for the "none" item in the "tariff" ArrayCollection changes to "true", so the "none" item is black and active
                  
      I do not want to hard-code these business rules using if() constructs in ComboBox change handlers. Instead, I want to use the "invalid" ArrayCollection below to enforce whatever invalid combinations are in that AC. This will enable a flexible system.

       

      I've been wracking my brain on this one so please help.

      <?xml version="1.0"?>
      <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        creationComplete="init();">
        <mx:Script>
          <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            
            /* The items in these ComboBoxes will be grayed out and inactive 
               if their "valid" field is "false". 
            
               After launching the application, open the "Tariff" ComboBox
               and notice the $100.00 item is grayed out and cannot be selected.
               
               QUESTION: what should be added to this application to support
                         the following use cases of the ComboBoxes:
                         
               1) If the user selects clothes and China in the Product and 
                   Source ComboBoxes, the "valid" field for the "$100.00" item
                   in the "tariff" ArrayCollection changes to "true", so the
                   "$100.00" item is black and active. Also, the "valid" field 
                   for the "none" item in the "tariff" ArrayCollection changes 
                   to "false", so the "none" item is gray and inactive
               2) If after performing 1) above, the user selects Mexico Source 
                   ComboBox, the "valid" field for the "$100.00" item in the 
                   "tariff" ArrayCollection changes to "false", so the "$100.00" 
                   item is gray and inactive. Also, the "valid" field for the 
                   "none" item in the "tariff" ArrayCollection changes to "true", 
                   so the "none" item is black and active
                   
               I do not want to hard-code these business rules using if() constructs
               in ComboBox change handlers. Instead, I want to use the "invalid"
               ArrayCollection below to enforce whatever invalid combinations
               are in that AC. This will enable a flexible system.
            */
            
            [Bindable] private var product:ArrayCollection = new ArrayCollection([
              {label: "cars", valid: true},
              {label: "clothes", valid: true}
            ]);
            [Bindable] private var source:ArrayCollection = new ArrayCollection([
              {label: "China", valid: true},
              {label: "Mexico", valid: true}
            ]);
            [Bindable] private var tariff:ArrayCollection = new ArrayCollection([
              {label: "none", valid: true},
              {label: "$100.00", valid: false}
            ]);
            
            [Bindable] private var invalid:ArrayCollection = new ArrayCollection([
              ["cars"],["China"],["$100.00"],
              ["clothes"],["China"],["none"],
              ["clothes"],["Mexico"],["$100.00"]
            ]);
            
            [Bindable] private var currProduct:Object = new Object();
            [Bindable] private var currSource:Object = new Object();
            [Bindable] private var currTariff:Object = new Object();
            
            private function init():void{
              systemManager.addEventListener(FlexEvent.VALUE_COMMIT, sysMgrHandler, true);
            }
            
            private function sysMgrHandler(evt:FlexEvent):void{
              if(evt.target is ComboBox){
                var tgt:ComboBox = evt.target as ComboBox;
                switch(tgt){
                  case cbxOne:
                    if(tgt.selectedItem.valid == false){
                      tgt.selectedItem = currProduct;
                    }
                    break;
                  case cbxTwo:
                    if(tgt.selectedItem.valid == false){
                      tgt.selectedItem = currSource;
                    }
                    break;
                  case cbxThree:
                    if(tgt.selectedItem.valid == false){
                      tgt.selectedItem = currTariff;
                    }
                    break;
                }
              }
            }
          ]]>
        </mx:Script>
        <mx:Label text="Tariff Calculator"/>
        <mx:Canvas width="{hb.width}">
          <mx:Label text="Product:" x="{cbxOne.x}"/>
          <mx:Label text="Source:" x="{cbxTwo.x}"/>
          <mx:Label text="Tariff:" x="{cbxThree.x}"/>
        </mx:Canvas>
        <mx:HBox id="hb">
          <mx:ComboBox id="cbxOne" dataProvider="{product}" open="currProduct=cbxOne.selectedItem;">
            <mx:itemRenderer>
              <mx:Component>
                <mx:Label text="{data.label}" color="{uint(data.valid==true?0x000000:0xCCCCCC)}"/>          
              </mx:Component>
            </mx:itemRenderer>
          </mx:ComboBox>
          <mx:ComboBox id="cbxTwo" dataProvider="{source}" open="currSource=cbxTwo.selectedItem;">
            <mx:itemRenderer>
              <mx:Component>
                <mx:Label text="{data.label}" color="{uint(data.valid==true?0x000000:0xCCCCCC)}"/>          
              </mx:Component>
            </mx:itemRenderer>
          </mx:ComboBox>
          <mx:ComboBox id="cbxThree" dataProvider="{tariff}" open="currTariff=cbxThree.selectedItem;">
            <mx:itemRenderer>
              <mx:Component>
                <mx:Label text="{data.label}" color="{uint(data.valid==true?0x000000:0xCCCCCC)}"/>          
              </mx:Component>
            </mx:itemRenderer>
          </mx:ComboBox>
        </mx:HBox>
      </mx:Application>
      
      
        • 1. Re: Three ComboBoxes Dependent on Each Other - Please Help
          Gregory Lafrance Level 6

          Just wondering if anyone can offer some advice on how to approach this problem.

          • 2. Re: Three ComboBoxes Dependent on Each Other - Please Help
            babo_ya Level 3

            Here is my thought and i know you are not gonna like this

             

            I think your requirement is a certainly business rule and you are trying to solve this issue without implementing business rule. I think the important thing is WHERE you capture this business rule obviously you do not want to put it on the "View" elements (If you are using MVC approach). I could be wrong and I'm sure other people has their ways to implement this. But, I would create a control class that accepts, source, tariff data and add the business rule and the return the result back to the view (the last comboBox).  And if a client B wants a different business rule you just need to create a new control class that implements client B's business rule.

             

             

            Just my thought, i'm sure alot pple will disagree with my approach.

             

            Hope this helps,

             

            BaBo,

            • 3. Re: Three ComboBoxes Dependent on Each Other - Please Help
              Gregory Lafrance Level 6

              Thanks for your ideas, but I guess I was thinking more in terms of specifics.

               

              Having the business rules in a separate control file or not is another topic. I am more interested in possible mechanics of using the "invalid" ArrayCollection in order to loop through the three ComboBox dataProvider AC to appropriately set their items' "valid" fields.

               

              Sometimes I think I am close to getting this conceptually, but then I realize it doesn't work as I need it to.

              • 4. Re: Three ComboBoxes Dependent on Each Other - Please Help
                msakrejda Level 4

                It seems like you may want another layer of indirection here. Not necessarily another class (that's probably needed, but orthogonal), but it seems awkward that your "valid/invalid" flags are sitting there directly in the combobox data provider ACs.The items themselves aren't really valid or invalid: it's whether they are selectable in the comboboxes based on the state of the entire application. Instead of storing plain Objects in those ACs, I'd suggest something like

                 

                class Validator {

                 

                  public var selectedSource:String;

                  public var selectedProduct:String;

                  public var selectedTarriff:String;

                 

                  public var invalid:ArrayList

                 

                  public function isValid(type:String,item:String):Boolean {

                    // loop over invalid to determine whether this particular item is valid, given the

                    // currernt combination of selected items

                  }

                 

                }

                 

                class ValidatedItem {

                  public var name:String;

                  public var type:String;

                  public var validator:Validator;

                  public function get valid():Boolean {

                    return validator.isValid(type, name);

                  }

                }

                 

                Then fill your combobox dataproviders with ValidatedItems instead of Objects. You'll need to instantiate the Validator once for the app and inject it into each item (a Dependency Injection infrastructure like Mate or SmartyPants can make this easier). You can use a Singleton instead if that's more your thing (I'm trying to de-Singleton my life).

                 

                I think that you'll need to wire some extra binding to Validator since otherwise ValidatedItem won't update the valid property when the selected items on Validator change, but that's straigthforward.

                 

                Is this the sort of approach you were thinking of?

                 

                --

                Maciek Sakrejda

                Truviso, Inc.

                www.truviso.com

                Truviso is hiring: http://www.truviso.com/company-careers.php?i=87

                1 person found this helpful
                • 5. Re: Three ComboBoxes Dependent on Each Other - Please Help
                  Gregory Lafrance Level 6

                  I appreciate your input. I'll mull over your suggestion, but I think at this point I'm just looking for something simple, some way of parsing the dataproviders and the invalid AC to set the "valid" fields.

                   

                  Anyone have suggestions along these lines?

                  • 6. Re: Three ComboBoxes Dependent on Each Other - Please Help
                    PeakDigital Level 1

                    Greg,

                     

                    Not sure if I can help on this or not, but since you have assisted me in the past I need to try...

                     

                    If I am reading your use case descriptions correctly, it seems the Tariff ComboBox is the only one reacting to user input? What if the user works right to left, starting by choosing "none" for the Tariff amount?

                     

                    Am I interpreting correctly that your ArrayCollection named "invalid"  is intended to contain all possible permutations of the members of the ComboBoxes?

                     

                    I have an idea in mind, but if I'm on the wrong track it probably wouldn't work.

                     

                    Paul