2
votes

I would like to create an AdvancedDataGrid where one of the cells requires some layout work involving images and text. Here is the top level view of the problem that I am trying to solve

(My grid looks like this - Property "name" in the first column and Property "value" in the second)

<mx:AdvancedDataGrid showHeaders="false" defaultLeafIcon="{null}">  

    <mx:columns>
        <mx:AdvancedDataGridColumn  dataField="Property" headerText="Property" backgroundColor="#E5EFF5" width="0.4" wordWrap="true"/>
        <mx:AdvancedDataGridColumn  dataField="Value" headerText="Value" backgroundColor="white" width="0.6"/>
    </mx:columns> 


</mx:AdvancedDataGrid>   

(The dataProvider for the grid looks something like the following)

var retVal:ArrayCollection = new ArrayCollection([

{Property:'AA', Value:1},
{Property:'BB',  Value: <Object that requires custom formatting when displayed in the grid>},                                                          
{Property:'CC',  Value:"Simple string"}
                                                         ]);

Property BB alone has a more complex view involving laying out images and text in a particular layout. Every other property has a simple string or numeric value that does not require any special formatting.

Things like itemRenderer are proving to be too difficult to use for me given that not all my column entries for a given column are formatted in the same way when displayed inside the grid.

I am using an AdvancedDataGrid because it provides tree like navigation within the grid (using children) and that is something that I will eventually need.

An example would be helpful as I am new to flex.

Thank you.


I tried to create an example and it is not doing what I want

// GridExample.mxml

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>

<fx:Script>


    <![CDATA[
        import mx.collections.ArrayCollection;



        [Bindable]
        var data:ArrayCollection = new ArrayCollection([{Property:'AA', RowIdentifier: "SimpleType", Value:3},
                                                        {Property:'BB', RowIdentifier: "ArrayType", Value:["one", "two", "three"]}, 
                                                        {Property:'CC',  RowIdentifier: "SimpleType", Value:"My string"}
                                                        ]);

    ]]>
</fx:Script>

<mx:Box height="300" width="300">

    <mx:AdvancedDataGrid  
                         variableRowHeight="true"
                         width="100%"
                         showHeaders="false" 
                         defaultLeafIcon="{null}"
                         dataProvider="{data}">  


        <mx:columns>
            <mx:AdvancedDataGridColumn  dataField="Property" headerText="Property" backgroundColor="#E5EFF5" width="0.4" wordWrap="true"/>
            <mx:AdvancedDataGridColumn  dataField="Value" headerText="Value" backgroundColor="white" width="0.6" itemRenderer="ExampleRenderer"/>
            <mx:AdvancedDataGridColumn  dataField="RowIdentifier" visible="false"/>
        </mx:columns> 


    </mx:AdvancedDataGrid>      

</mx:Box>

</s:WindowedApplication>

//ExampleRenderer.mxml

<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" textAlign="center"    creationComplete="renderNow()" >
<mx:Script>
    <![CDATA[

        import mx.containers.HBox;
        import mx.containers.VBox;
        import mx.controls.Alert;
        import mx.controls.Image;
        import mx.controls.Label;
        import mx.resources.ResourceManager;

        private var dataObject:Object;



        private function renderNow():void {

            var rowId:String = dataObject["RowIdentifier"];
            if (rowId == "ArrayType"){
                var valueObj:Array = dataObject["Value"];
                var vBox:VBox = new VBox();
                vBox.percentHeight = 100;
                vBox.percentWidth = 100;


                for (var i:uint=0; i<valueObj.length;i++){
                    //Create the hBoxes that will wrap the host icon and the host Ip                    
                    var hBox:HBox = new HBox();

                    //Add host icon to the box
                    var imageIcon:Image = new Image();
                    imageIcon.source = "@Embed(source='adobe.png')";
                    hBox.addChild(imageIcon);


                    //Appears to the right
                    var label2:Label = new Label();
                    label2.text = valueObj[i];
                    label2.percentHeight = 100;
                    label2.percentWidth = 70;
                    hBox.addChild(label2);

                    //Add the hBox to the vBox
                    vBox.addChild(hBox);                    
                }
                this.addChild(vBox);
            }
            else{
                var iLabel:Label = new Label();
                iLabel.text = dataObject["Value"];
                iLabel.percentHeight = 100;
                iLabel.percentWidth = 100;
                this.addChild(iLabel);
            }
        }

        override public function set data(value:Object):void
        {
            dataObject = value;
        }
    ]]>
</mx:Script>

</mx:Box>

The output of running this gives me the wrong grid cells (Property values are completely off and they run around when I try to resize if my Box width and height are set in percentages)

Can you help me find what is wrong with what I am doing? Any help is appreciated.

Regards

1
Short answer: Create an itemRenderer. There isn't going to be an easier way to get different rows to display differently. You'll have to change formatting or layout based on the data. If you switch to a Spark DataGrid, the itemRendererFunction may help. - JeffryHouser
Hi Reboog711, I tried to create a simple example based on your previous comment and could not get that to work. Could you take a look at it and tell me what I am doing wrong? My first column is a property (string) and my second column is the value which could either be a simple string/number or an array of values that needs to be formatted. I am saving away the dataObject for the row and using that to render the view. I am pretty sure I am getting hooks wrong (especially the creationComplete thing) but Flex does not seem to have a simple hook for me to override. - user2789284

1 Answers

1
votes

Item renderers are recycled, which means you should expect that any one of your renderer instances can be assigned a data item from the list at random (EG. the data setter should drive any visual changes). Don't forget to reset the state from any previous rendering on a different data item.

<fx:Script>


    <![CDATA[
        import mx.collections.ArrayCollection;

        [Bindable]
        private var _data:ArrayCollection =
            new ArrayCollection([{Property: 'AA', RowIdentifier: "SimpleType", Value: 3},
            {Property: 'BB', RowIdentifier: "ArrayType", Value: ["one", "two", "three"]},
            {Property: 'CC', RowIdentifier: "SimpleType", Value: "My string"}]);
    ]]>
</fx:Script>

<mx:Box width="300" height="300">

    <mx:AdvancedDataGrid width="100%" dataProvider="{_data}" defaultLeafIcon="{null}" showHeaders="false"
                         variableRowHeight="true">
        <mx:columns>
            <mx:AdvancedDataGridColumn width="0.4" backgroundColor="#E5EFF5" dataField="Property"
                                       headerText="Property" wordWrap="true" />
            <mx:AdvancedDataGridColumn width="0.6" backgroundColor="white" dataField="Value" headerText="Value">
                <mx:itemRenderer>
                    <fx:Component>
                        <s:MXAdvancedDataGridItemRenderer>

                            <fx:Script>
                                <![CDATA[
                                    import mx.containers.HBox;
                                    import mx.containers.VBox;
                                    import mx.controls.Image;
                                    import mx.controls.Label;

                                    override public function set data(value:Object):void
                                    {
                                        super.data = value;

                                        renderNow(value);
                                    }

                                    private function renderNow(data:Object):void
                                    {

                                        //remove any components added from a different data item
                                        this.removeAllElements();

                                        var rowId:String = data["RowIdentifier"];

                                        if(rowId == "ArrayType")
                                        {
                                            var valueObj:Array = data["Value"];
                                            var vBox:VBox = new VBox();
                                            vBox.percentHeight = 100;
                                            vBox.percentWidth = 100;

                                            for(var i:uint = 0; i < valueObj.length; i++)
                                            {
                                                //Create the hBoxes that will wrap the host icon and the host Ip                    
                                                var hBox:HBox = new HBox();

                                                //Add host icon to the box
                                                var imageIcon:Image = new Image();
                                                imageIcon.source = "@Embed(source='adobe.png')";
                                                hBox.addChild(imageIcon);

                                                //Appears to the right
                                                var label2:Label = new Label();
                                                label2.text = valueObj[i];
                                                label2.percentHeight = 100;
                                                label2.percentWidth = 70;
                                                hBox.addChild(label2);

                                                //Add the hBox to the vBox
                                                vBox.addChild(hBox);
                                            }
                                            this.addElement(vBox);
                                        }
                                        else
                                        {
                                            var iLabel:Label = new Label();
                                            iLabel.text = data["Value"];
                                            iLabel.percentHeight = 100;
                                            iLabel.percentWidth = 100;
                                            this.addElement(iLabel);
                                        }
                                    }
                                ]]>
                            </fx:Script>

                        </s:MXAdvancedDataGridItemRenderer>
                    </fx:Component>
                </mx:itemRenderer>
            </mx:AdvancedDataGridColumn>
            <mx:AdvancedDataGridColumn dataField="RowIdentifier" visible="false" />
        </mx:columns>
    </mx:AdvancedDataGrid>

</mx:Box>