2 Replies Latest reply on Nov 19, 2007 7:52 PM by cmarkiewicz

    ComboBox - override set data method - called for all rows in datagrid?

    cmarkiewicz
      Hello. I have a ComboBox column in my DataGrid. The ComboBox is populated with data i pull from a web service. I override the set data() so that it pre-populates, etc (code below). My issue is this - anytime I change the value of a ComboBox in any one of the rows of the DataGrid, the set data() method is called for all rows. This causes a problem because if I change one ComboBox and immediately click on the ComboBox in a different row, the ComboBox expands but then quickly retracts when the set data() method executes on that row.

      So my question is, how do I make it execute on just the affected row? My item renderer code is below. First the DataGridColumn, then the renderer (ProductCodeRenderer2).

      Thanks for your time.
      Chris

      <mx:DataGridColumn dataField="productCode" headerText="Product Code"
      headerWordWrap="true" editorDataField="valueSelected"
      width="80" itemRenderer="ProductCodeRenderer2" rendererIsEditor="true" />


      <?xml version="1.0" encoding="utf-8"?>
      <!-- mxmlcomponents/TypeComboBoxRenderer.mxml -->
      <mx:Canvas xmlns:mx=" http://www.adobe.com/2006/mxml"
      horizontalScrollPolicy="off" verticalScrollPolicy="off"
      >
      <mx:Script>
      <![CDATA[
      import mx.messaging.channels.StreamingAMFChannel;
      // Define a property for returning the new value to the cell.
      [Bindable]
      public var valueSelected:String;


      override public function set data(value:Object):void
      {
      if(value != null)
      {
      super.data = value;
      trace("set data...data.productCode:"+data.productCode);

      //show the comboBox
      if(value.nonPartFlag)
      {
      prodCodeChoices.visible=true;
      prodCodeLabel.visible=false;
      }
      //hide the comboBox and show the label
      else
      {
      prodCodeChoices.visible=false;
      prodCodeLabel.visible=true;
      }
      var pcArr:Array = data.productCodeArray;
      for (var j:int = 0; j < pcArr.length; j++)
      {
      var pctmp:String = pcArr[j];
      if (pctmp == data.productCode)
      {
      trace("PrevIndex/NewIndex:"+prodCodeChoices.selectedIndex+"/"+j);
      trace("PrevItem/NewItem:"+prodCodeChoices.selectedItem+"/"+data.productCode);
      trace("Match found!!!:"+j+"/"+pctmp);
      prodCodeChoices.selectedIndex = j;
      }
      }
      //prodCodeChoices.selectedItem=data.productCode;
      }
      }

      public function changeHandler(event:Event): void
      {
      trace("changeHandler...prodCodeChoices.selectedItem:"+prodCodeChoices.selectedItem);
      valueSelected = String(prodCodeChoices.selectedItem);
      }
      ]]>
      </mx:Script>

      <mx:ComboBox id="prodCodeChoices" dataProvider="{data.productCodeArray}" width="100%"
      change="changeHandler(event)"
      creationComplete="prodCodeChoices.selectedItem=data.productCode"
      />
      <mx:Label id="prodCodeLabel" text="{data.productCode}" />


      </mx:Canvas>

        • 1. Re: ComboBox - override set data method - called for all rows in datagrid?
          ntsiii Level 3
          That is the intended behavior: Any time you update the dataProvider from a renderer, all the renderers are updated. This is because the values in the othe renderers might depend on the changed value.

          I do not know if this will solve the problem, but best practice with renderers is to not actually do the work in set data(). Rather, store any values you need in instance variables, then call invalidateProperties. This tells the framework that when it is the optimum time, call the commitProperties() method on all renderers. Actually do your work in an overrides commitProperties() method. set data is called much more often than commitProperties.

          Tracy
          • 2. Re: ComboBox - override set data method - called for all rows in datagrid?
            cmarkiewicz Level 1
            Some more details on the same issue....

            Hello. I have a DataGrid with a column of ComboBoxes. The behavior I'm seeing is this:
            1) I click on a ComboBox - it expands
            2) I choose a value - it collapses
            3) I click on a ComboBox in a different column
            4) It expands - then immediately collapses

            I have determined why it is happening, but I'm not sure how to make it stop.

            I have a separate mxml file where I define the ComboBox and I override the set data() method. The set data() method sets the value in the ComboBox in each row. The issues is that after I change a ComboBox in one row, set data() is called on all rows - so as soon as I click on the second ComboBox, set data() is called (because I clicked away from the first ComboBox), the value is set in the second ComboBox - and it collapses.

            So, if I change the value in one ComboBox, click to some other cell, then click on the second ComboBox, it works fine (because set data() is called when i click to the other cell). So my questions is, how do I make this work? Can I force the call to set data() as soon as the first ComboBox collapses (my putting focus on another component temporarily?)? Or can I make it bypass the set data() call from ComboBoxes which weren't touched?

            Any help is greatly appreciated.

            Code is below, if it helps...

            Thanks
            Chris

            <?xml version="1.0" encoding="utf-8"?>
            <!-- mxmlcomponents/TypeComboBoxRenderer.mxml -->
            <mx:Canvas xmlns:mx=" http://www.adobe.com/2006/mxml"
            xmlns:lib="t3quote.*"
            horizontalScrollPolicy="off" verticalScrollPolicy="off"
            >
            <mx:Script>
            <![CDATA[
            import mx.messaging.channels.StreamingAMFChannel;
            // Define a property for returning the new value to the cell.
            [Bindable]
            public var valueSelected:String;



            override public function set data(value:Object):void
            {
            if(value != null)
            {
            super.data = value;
            trace("set data...data.productCode:"+data.productCode);

            //show the comboBox
            if(value.nonPartFlag)
            {
            prodCodeChoices.visible=true;
            prodCodeLabel.visible=false;
            }
            //hide the comboBox and show the label
            else
            {
            prodCodeChoices.visible=false;
            prodCodeLabel.visible=true;
            }

            var pcArr:Array = data.productCodeArray;
            for (var j:int = 0; j < pcArr.length; j++)
            {
            var pctmp:String = pcArr[j];
            if (pctmp == data.productCode)
            {
            trace("PrevIndex/NewIndex:"+prodCodeChoices.selectedIndex+"/"+j);
            trace("PrevItem/NewItem:"+prodCodeChoices.selectedItem+"/"+data.productCode);
            trace("Match found!!!:"+j+"/"+pctmp);
            prodCodeChoices.selectedIndex = j;
            }
            }


            }
            }


            public function changeHandler(event:Event): void
            {
            trace("changeHandler...prodCodeChoices.selectedItem:"+prodCodeChoices.selectedItem);
            valueSelected = String(prodCodeChoices.selectedItem);
            }
            ]]>
            </mx:Script>


            <mx:ComboBox id="prodCodeChoices" dataProvider="{data.productCodeArray}" width="100%"
            change="changeHandler(event)"
            creationComplete="prodCodeChoices.selectedItem=data.productCode"
            />
            <!--
            <lib:ComboBox id="prodCodeChoices" dataProvider="{data.productCodeArray}" width="100%"
            value="{data.productCode}"
            />
            -->
            <mx:Label id="prodCodeLabel" text="{data.productCode}" />


            </mx:Canvas>