Question

(EDIT: See my answer provided below as a possible solution)

I have a datagrid where each datagridcolumn is using different itemrenderers. One of these renderers in one of the columns is a List component full of values. The text shown in the list component are labels of it's dataprovider.

What I would like to do is make the List component column itemrenderer an itemeditor. This means that the user clicks on the cell in the column and a list of values shows up (NOT a drop down). They can then choose multiple values from the list component. When they click out of the List component, the column shows the values chosen.

When they SAVE their choices (via a save button outside of the datagrid in question), I would like to reference that data to determine what choice they have made - HOWEVER - instead of the label, I would like to get the number associated to that label. I do this with XML:

<colors>
<color label="Green" value="1"/>
<color label="Yellow" value="2"/>
<color label="Red" value="3"/>
</colors>

Now, the itemeditor part is great as it works fine for visually seeing your choices after you have clicked outside of the cell. However, I would like to identify the value of the chosen color ("3") and do this for each value chosen in this list.

This should be identified naturally by the following datagridcolumn (CheckList is simply a List that allows multiple selection without holding the CTRL key down) using the given dataprovider for this column:

<colorData chosenColors=''/>

Here is the sample code:

<mx:DataGridColumn dataField="@chosenColors" editorDataField="colors" headerText="Colors" width="200" wordWrap="true">
                    <mx:itemEditor>
                        <fx:Component>
                            <s:MXDataGridItemRenderer focusEnabled="true" height="22" >
                                <fx:Script>
                                    <![CDATA[
                                        public function get colors():String {
                                            var str:String = new String;
                                            for(var i:int=0;i < colorList.selectedItems.length; i++){
                                                if(i > 0){
                                                    str += ",\n";
                                                }
                                                str += colorList.selectedItems[i].@label;

                                            }
                                            return str;
                                        }
                                    ]]>
                                </fx:Script>
                                <r:CheckList id="colorList"
                                                    dataProvider="{parentApplication.colors}"
                                                    labelField="@label" width="100%" height="150"/>
                            </s:MXDataGridItemRenderer>
                        </fx:Component>
                    </mx:itemEditor>
                </mx:DataGridColumn>

However, this simply replaces the XML with the following if, say, Green and Red were chosen:

<colorData chosenColors=' Green, Red'/>

Instead, I would like the resulting XML to be:

<colorData chosenColors=' 1, 3'/>

Please let me know how I can accomplish this - inline renderer or not, other implementation, etc. Thanks for your help!

Was it helpful?

Solution

Try this will help you.

Instead of getting label text from selectedItems get value attribute value like @value. So now become <colorData chosenColors='1, 3'/>.

public function get colors():String {

    var values:Array = [];
    
    for(var i:int=0;i < colorList.selectedItems.length; i++){       
        values.push(colorList.selectedItems[i].@value.toString()); //Note here
    }
    
    return values.toString();
}

1, 3 also display in grid as well. I 'm not sure what you expect at UI level. Still if you want display Color like Green, Red in UI level but at the same time you need to store value their respective node. In case create one more attribute in XML like

<colorData chosenColors='Green, Red' chosenValueColors='1,3' />. 

Here chosenColors for display purpose and chosenValueColors for might database or do for other things. Now you can expected value from attribute chosenValueColors from XML.

Based on comments

To acheive you requirement you need to override data getter/setter method in itemRenderer or you can use dataChange Event.

override public function get data():Object
{
    return super.data;
}

override public function set data(value:Object):void
{
    super.data = value;
    
    if(!value)
        return;
    
    var selectedValues:Array = value.@chosenColors.toString().split(","); //get selected value in array
    var selectedIndices:Vector.<int> = new Vector.<int>();
    
    for (var i:int = 0, len:int = colorList.dataProvider.length; i < len; i++) 
    {
        var color:XML = colorList.dataProvider[i] as XML;
        
        if(selectedValues.indexOf(color.@value.toString()) > -1)
            selectedIndices.push(i); //Store index of selected items
    }
    
    trace(selectedIndices.toString());
    
    colorList.selectedIndices = selectedIndices;
}

public function get colors():String {
    
    var values:Array = [];
    
    for(var i:int=0;i < colorList.selectedItems.length; i++){
        
        values.push(colorList.selectedItems[i].@value.toString());
    }
    
    return values.toString();
}

public function colorList_changeHandler(event:IndexChangeEvent):void
{
    data.@value = colors; //IMPORT Commit the selected value to dataProvider.
}

Note here we listen change event for commit value into dataprovider like change="colorList_changeHandler(event)"

 <r:CheckList id="colorList" change="colorList_changeHandler(event)"
            dataProvider="{parentApplication.colors}"
            labelField="@label" width="100%" height="150"/>

OTHER TIPS

(EDIT: This implementation has issues with Flex 4.11 where the dataprovider will sometimes be altered if using addItem - this may be fixed in Flex 4.12, but I have not tested. See below comments for resolution.)

I actually implemented this slightly different than Raja Jaganathan, however, I do believe his answer will help as well. Here's how I implemented this fix.

Again, the desire was to have the XML dataProvider updated with XML and not just text after the itemEditor was complete. The way I implemented this was to follow Adobe's example at this URL (Flex 4.6 guide): Examples using MX item editors with the list-based controls

I used an inline itemEditor for my list that resembled my original question. The difference was that I instead implemented an override for the data function (similar to what Raja did). In the data function (called when itemEdit begins), I set my data, but also set the selectedItems of the list control based upon what colors were listed in my XML. This ensured the list control showed the colors that were already selected before user interaction.

Next, at the end of itemEdit, I modified my colors function to set a temporary attribute on the XML that contained the ID's that were selected in the list. This ensured the user's choices (if different from the original) were captured.

Now, here is where I struggled and where Raja's answer may work better. In the colors function, I merely added the selected XML in the list control to the dataProvider XML. This turned out to be very problematic as Flex wouldn't store XML to the dataProvider without first escaping it, leaving a mess of ampersands and HTML encoded XML (i.e. junk). To get around this, I created a listener on the datagrid for the itemEditEnd event. This listener called a function - similar to the Adobe example - that read the chosen color ids and replace the encoded XML junk that Flex gave me with real XML. The most important thing in this XML was to call preventDefault() right away to prevent overriding what I did to the dataprovider.

Doing these things provided me with the ability to provide a list to the user to choose from, then to show the user their current choices once they moved to a different cell in the datagrid. It also allowed me to store these choices for later retrieval when the user chose to save the change to the table permanently.

EDIT: Below this point is a deeper explanation of how to implement differently than Adobe's example.

The Adobe link above has some issues when modifying the editedItemEditor.data. Instead, I added a itemEditEnd event handler function in the data grid like so:

<mx:DataGrid id="dataGridSvcTypeReasons" height="100%" width="100%" dataProvider="{dataProvider}" editable="true" itemEditEnd="dataGrid_itemEditEndHandler(event)">

In the handler function, I manipulated the original data - NOT the editedItemRenderer.data per Adobe's example:

protected function dataGrid_itemEditEndHandler(event:DataGridEvent):void{

    if (event.reason == DataGridEventReason.CANCELLED){
        // Do not update cell.
        return;
    }

    event.preventDefault();

    var data:Object = dataProvider.getItemAt(event.rowIndex);

    // look to see if my list exists (if not, then this edit does not pertain to my list)
    if(event.currentTarget.itemEditorInstance.hasOwnProperty("myList")){
        var selectedItems:Vector.<Object>;

        selectedItems = event.currentTarget.itemEditorInstance.myList.selectedItems;

        delete data.colors;
        data.appendChild(<colors/>);

        if(selectedItems){
            for each(var item:XML in selectedItems){
                for(var i:int = 0; i < myList.dataProvider.length; i++){
                    if(myList.dataProvider[i].@value == item.@value){
                        data.colors.appendChild(new XML(myList.dataProvider[i]));
                        break;
                    }
                }
            }
        }
    }
}

This method will avoid GUI issues that result from destroying the editedItemRenderer found in Adobe's example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top