Setting background colors on a DataGrid column in Flex

The following example shows how you can set alternating column background colors on a Flex DataGrid control by setting the backgroundColor style for each DataGridColumn object.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/09/24/setting-background-colors-on-a-datagrid-column-in-flex/ -->
<mx:Application name=""
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:XML id="xmlDP" source="data/dp.xml" />

    <mx:DataGrid id="dataGrid"
            dataProvider="{xmlDP.children()}"
            verticalScrollPolicy="on">
        <mx:columns>
            <mx:DataGridColumn dataField="@c1"
                    backgroundColor="haloSilver" />
            <mx:DataGridColumn dataField="@c2"
                    backgroundColor="white" />
            <mx:DataGridColumn dataField="@c3"
                    backgroundColor="haloSilver" />
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

View source is enabled in the following example.

Due to popular demand, here is the “same” example in a more ActionScript friendly format:

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/09/24/setting-background-colors-on-a-datagrid-column-in-flex/ -->
<mx:Application name=""
        xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white"
        initialize="init();">

    <mx:Script>
        <![CDATA[
            import mx.core.ScrollPolicy;
            import mx.controls.dataGridClasses.DataGridColumn;
            import mx.controls.DataGrid;

            private var xmlDP:XML;
            private var xmlLoader:URLLoader;
            private var dataGrid:DataGrid;
            private var dgc1:DataGridColumn;
            private var dgc2:DataGridColumn;
            private var dgc3:DataGridColumn;

            private function init():void {
                dgc1 = new DataGridColumn("@c1");
                dgc1.setStyle("backgroundColor", "haloSilver");

                dgc2 = new DataGridColumn("@c2");
                dgc2.setStyle("backgroundColor", "white");

                dgc3 = new DataGridColumn("@c3");
                dgc3.setStyle("backgroundColor", "haloSilver");

                dataGrid = new DataGrid();
                dataGrid.verticalScrollPolicy = ScrollPolicy.ON;
                dataGrid.columns = [dgc1, dgc2, dgc3];
                addChild(dataGrid);

                xmlLoader = new URLLoader();
                xmlLoader.dataFormat = URLLoaderDataFormat.TEXT;
                xmlLoader.addEventListener(Event.COMPLETE,
                            xmlLoader_complete);
                xmlLoader.load(new URLRequest("data/dp.xml"));
            }

            private function xmlLoader_complete(evt:Event):void {
                var xmlObj:XML = new XML(evt.currentTarget.data);
                dataGrid.dataProvider = xmlObj.children();
            }
        ]]>
    </mx:Script>

</mx:Application>

12 thoughts on “Setting background colors on a DataGrid column in Flex

  1. Hello,

    I found your exemple very interesting.
    I have a demand.

    Can your show an example, with arraycollection (A,B), in which you add :
    – a column that calculated the total of each row of the columns before.
    – a footer that calculated the total of each columms.

    |---- A -----|---- B -----|---- C -----|
    |------------|------------|---(A+B)----|
    |------------|------------|---(A+B)----|
    ..
    |------------|------------|---(A+B)----|
    |- TOTAL A --|- TOTAL B --|- TOTAL C---|
    

    Best Regards

  2. pierre,

    Fortunately, the first part of the problem is pretty easy. You simply need to create a DataGridColumn and specify a labelFunction which adds the values from Column A to Column B and return the sum. It gets marginally tricker since you may also have to specify a custom sortCompareFunction so the column sorts correctly if the user clicks on the header. Something like the following should get you started:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
        <mx:Script>
            <![CDATA[
                import mx.controls.Label;
                import mx.controls.dataGridClasses.DataGridColumn;
                import mx.utils.ObjectUtil;
    
                private function sum_labelFunc(item:Object, col:DataGridColumn):Number {
                    return Number(item.c1) + Number(item.c2);
                }
    
                private function sum_sortCompareFunc(a:Object, b:Object):int {
                    var sumA:Number = Number(sumCol.itemToLabel(a));
                    var sumB:Number = Number(sumCol.itemToLabel(b));
    
                    return ObjectUtil.numericCompare(sumA, sumB);
                }
            ]]>
        </mx:Script>
    
        <mx:ArrayCollection id="arrColl">
            <mx:source>
                <mx:Array>
                    <mx:Object label="Row 1" c1="1" c2="15" />
                    <mx:Object label="Row 2" c1="5" c2="28" />
                    <mx:Object label="Row 3" c1="5" c2="44" />
                    <mx:Object label="Row 4" c1="9" c2="73" />
                    <mx:Object label="Row 5" c1="3" c2="81" />
                    <mx:Object label="Row 6" c1="1" c2="4" />
                    <mx:Object label="Row 7" c1="6" c2="63" />
                    <mx:Object label="Row 8" c1="5" c2="12" />
                </mx:Array>
            </mx:source>
        </mx:ArrayCollection>
    
        <mx:DataGrid id="dataGrid" dataProvider="{arrColl}">
            <mx:columns>
                <mx:DataGridColumn dataField="label" />
                <mx:DataGridColumn dataField="c1" />
                <mx:DataGridColumn dataField="c2" />
                <mx:DataGridColumn id="sumCol"
                        headerText="sum"
                        labelFunction="sum_labelFunc"
                        sortCompareFunction="sum_sortCompareFunc" />
            </mx:columns>
        </mx:DataGrid>
    
    </mx:Application>
    

    As for the second part of the question, creating a footer that calculates the sum. There are probably a couple ways to do that. Unfortunately this isn’t something I’ve ever tried/investigated, so I can’t be of much help. You could probably loop through the items in the data provider and calculate the sum manually and display it in a Label control beneath the DataGrid. You’d probably want to listen for DataGridColumn resize events and resize/reposition your labels accordingly (so they line up). but that probably isn’t the solution you were looking for.
    Thankfully, Alex Harui has an example of custom DataGrid footers in his blog, so you may be able to view his source code and get the rest of the way there: “Flex 3 DataGrid Footers” and “DataGrid Footers”.

    Peter

  3. Hello Peter,

    I have two questions in the script below:
    – How round the result in each row of the sum column (2 decimales) , i tried toString but i have an error.
    – Is it possible, and how, to pass the total quantity and the total sum in an other datagrid in order to display the result.

    Thank for your help

    Regards

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="left" verticalAlign="top">
     <mx:Script>
      <![CDATA[
       import mx.controls.Label;
       import mx.controls.dataGridClasses.DataGridColumn;
       import mx.utils.ObjectUtil;
       import mx.events.CollectionEvent;
       import mx.collections.ArrayCollection;
       import mx.controls.Alert;
       import mx.events.DataGridEvent;
    
       private function resizeCols(event:Event=null) : void {
        if(dgS.rowCount > dgS.dataProvider.length)
          dgtot.width = dgS.width;
         else
          dgtot.width = dgS.width-16;
       }
    
       private function resizeCol(event : DataGridEvent) : void {
        DataGridColumn(dgtot.columns[event.columnIndex]).width = DataGridColumn(dgS.columns[event.columnIndex]).width;
       }
    
       private function sum_labelFunc(item:Object, col:DataGridColumn):Number {
        var sum:Number = Number(item.Price) * Number(item.Quantity);
        return sum;
       }
    
       private function sum_sortCompareFunc(a:Object, b:Object):int {
        var sumA:Number = Number(sumCol.itemToLabel(a));
        var sumB:Number = Number(sumCol.itemToLabel(b));
        return ObjectUtil.numericCompare(sumA, sumB);
       }
    
    
       [Bindable]
       public var dpADG:ArrayCollection = new ArrayCollection([
        {Artist:'Pavement',      Album:'Slanted and Enchanted',  Price:11.99, Quantity:10},
        {Artist:'Pavement',      Album:'Brighten the Corners',   Price:11.99, Quantity:-12},
        {Artist:'Saner',         Album:'A Child Once',           Price:11.99, Quantity:30},
        {Artist:'Saner',         Album:'Helium Wings',           Price:12.99, Quantity:45},
        {Artist:'The Doors',     Album:'The Doors',              Price:10.99, Quantity:60},
        {Artist:'The Doors',     Album:'Morrison Hotel',         Price:12.99, Quantity:45},
        {Artist:'Grateful Dead', Album:'American Beauty',        Price:11.99, Quantity:23},
        {Artist:'Grateful Dead', Album:'In the Dark',            Price:11.99, Quantity:36},
        {Artist:'Grateful Dead', Album:'Shakedown Street',       Price:11.99, Quantity:73},
        {Artist:'The Doors',     Album:'Strange Days',           Price:12.99, Quantity:11},
        {Artist:'The Doors',     Album:'The Best of the Doors',  Price:10.99, Quantity:19},
        {Artist:'The Doors2',    Album:'The Best of the Doors2', Price:10.99, Quantity:21}
       ]);
    
       private var dpADG2:ArrayCollection = new ArrayCollection([
        {Artist:'Pavement',      Album:'Slanted and Enchanted', Price:11.99, Quantity:12},
        {Artist:'Pavement',      Album:'Brighten the Corners',  Price:11.99, Quantity:76},
        {Artist:'Saner',         Album:'A Child Once',          Price:11.99, Quantity:98},
        {Artist:'Saner',         Album:'Helium Wings',          Price:12.99, Quantity:54},
        {Artist:'The Doors',     Album:'The Doors',             Price:10.99, Quantity:79},
        {Artist:'The Doors',     Album:'Morrison Hotel',        Price:12.99, Quantity:28},
        {Artist:'Grateful Dead', Album:'American Beauty',       Price:11.99, Quantity:39},
        {Artist:'Grateful Dead', Album:'In the Dark',           Price:11.99, Quantity:30},
        {Artist:'Grateful Dead', Album:'Shakedown Street',      Price:11.99, Quantity:38}
       ]);
    
       [Bindable]
       private var dpADGTotal:ArrayCollection = new ArrayCollection([
        {Artist:'', Album:'Total', Quantity:'XXX.XX'}
       ]);
    
      ]]>
     </mx:Script>
     <mx:Style>
      .title {
       text-align:center;
       font-weight:bold;
      }
      .body {
       text-align:right;
       padding-right:10;
      }
     </mx:Style>
    
    
     <mx:NumberFormatter id="numberFormatter"/>
    
    
     <mx:Button label="{'Switch to Dataprovider '+ (dgS.dataProvider == dpADG ? 'without' : 'with') +'  scroll'}" click="{dgS.dataProvider = (dgS.dataProvider == dpADG ? dpADG2 : dpADG)}"/>
    
    
     <mx:VBox width="100%" height="100%" verticalGap="0">
      <mx:DataGrid id="dgS"
                   dataProvider="{dpADG}"
                   height="40%" width="40%"
                   resize="{resizeCols()}"
                   columnStretch="{resizeCol(event)}"
                   creationComplete="{dgS.addEventListener(CollectionEvent.COLLECTION_CHANGE, resizeCols, false, 0, true)}"
                   editable="true"
                   textAlign="right">
       <mx:columns>
        <mx:DataGridColumn dataField="Artist"   id="dcArt" textAlign="left"  headerStyleName="title"/>
        <mx:DataGridColumn dataField="Album"               textAlign="left"  headerStyleName="title"/>
        <mx:DataGridColumn dataField="Quantity"            textAlign="right" headerStyleName="title" paddingRight="10"
                           editable="true" itemEditor="comps.MyNumericStepper" editorDataField="value"/>
        <mx:DataGridColumn dataField="Price"               textAlign="right" headerStyleName="title" paddingRight="10"/>
        <mx:DataGridColumn                      id="sumCol" textAlign="right" headerStyleName="title" paddingRight="10"
                           editable="false"
                           headerText="Sum"
                           labelFunction="sum_labelFunc"
                           sortCompareFunction="sum_sortCompareFunc" />
       </mx:columns>
      </mx:DataGrid>
      <mx:DataGrid id="dgtot"
                   width="40%"
                   dataProvider="{dpADGTotal}"
                   showHeaders="false"
                   rowCount="1"
                   height="{dgtot.rowHeight}"
                   creationComplete="{resizeCols()}"
                   fontWeight="bold">
       <mx:columns>
        <mx:DataGridColumn/>
        <mx:DataGridColumn dataField="Album"               textAlign="right" fontStyle="italic" paddingRight="10"/>
        <mx:DataGridColumn dataField="Quantity"            textAlign="right"                    paddingRight="10"/>
        <mx:DataGridColumn dataField="Price"/>
        <mx:DataGridColumn                    id="sumLign" textAlign="right"                 paddingRight="10"
                           labelFunction="sum_labelFunc"/>
       </mx:columns>
      </mx:DataGrid>
     </mx:VBox>
    
    </mx:Application>
    
  4. Pierre,

    To round to two decimals you can use <Number>.toFixed(2), or you can use a CurrencyFormatter or NumberFormatter.

    As for your other question, this should get you somewhat close, but there are still a few bugs in the code. Most notably:
    (a) Rearranging columns in the top DataGrid control causes the column order in the top and bottom data grid to get out of sync.
    (b) Changing data providers on the top DataGrid doesn’t correctly update the values in the bottom DataGrid. You’ll need to add additional logic/code.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            horizontalAlign="left"
            verticalAlign="top"
            initialize="init();">
    
     <mx:Script>
      <![CDATA[
       import mx.collections.ArrayCollection;
       import mx.controls.Alert;
       import mx.controls.Label;
       import mx.controls.dataGridClasses.DataGridColumn;
       import mx.events.CollectionEvent;
       import mx.events.DataGridEvent;
       import mx.utils.ObjectUtil;
    
       private function resizeCols(event:Event=null) : void {
        if(dgS.rowCount > dgS.dataProvider.length)
          dgtot.width = dgS.width;
         else
          dgtot.width = dgS.width-16;
       }
    
       private function resizeCol(event : DataGridEvent) : void {
        DataGridColumn(dgtot.columns[event.columnIndex]).width = DataGridColumn(dgS.columns[event.columnIndex]).width;
       }
    
       private function sum_labelFunc(item:Object, col:DataGridColumn):String {
        var sum:Number = Number(item.Price) * Number(item.Quantity);
        return currencyFormatter.format(sum);
       }
    
       private function currency_labelFunc(item:Object, col:DataGridColumn):String {
        return currencyFormatter.format(item[col.dataField]);
       }
    
       private function sum_sortCompareFunc(a:Object, b:Object):int {
        var sumA:Number = Number(sumCol.itemToLabel(a));
        var sumB:Number = Number(sumCol.itemToLabel(b));
        return ObjectUtil.numericCompare(sumA, sumB);
       }
    
       [Bindable]
       public var dpADG:ArrayCollection = new ArrayCollection([
        {Artist:'Pavement',      Album:'Slanted and Enchanted',  Price:11.99, Quantity:10},
        {Artist:'Pavement',      Album:'Brighten the Corners',   Price:11.99, Quantity:-12},
        {Artist:'Saner',         Album:'A Child Once',           Price:11.99, Quantity:30},
        {Artist:'Saner',         Album:'Helium Wings',           Price:12.99, Quantity:45},
        {Artist:'The Doors',     Album:'The Doors',              Price:10.99, Quantity:60},
        {Artist:'The Doors',     Album:'Morrison Hotel',         Price:12.99, Quantity:45},
        {Artist:'Grateful Dead', Album:'American Beauty',        Price:11.99, Quantity:23},
        {Artist:'Grateful Dead', Album:'In the Dark',            Price:11.99, Quantity:36},
        {Artist:'Grateful Dead', Album:'Shakedown Street',       Price:11.99, Quantity:73},
        {Artist:'The Doors',     Album:'Strange Days',           Price:12.99, Quantity:11},
        {Artist:'The Doors',     Album:'The Best of the Doors',  Price:10.99, Quantity:19},
        {Artist:'The Doors2',    Album:'The Best of the Doors2', Price:10.99, Quantity:21}
       ]);
    
       private var dpADG2:ArrayCollection = new ArrayCollection([
        {Artist:'Pavement',      Album:'Slanted and Enchanted', Price:11.99, Quantity:12},
        {Artist:'Pavement',      Album:'Brighten the Corners',  Price:11.99, Quantity:76},
        {Artist:'Saner',         Album:'A Child Once',          Price:11.99, Quantity:98},
        {Artist:'Saner',         Album:'Helium Wings',          Price:12.99, Quantity:54},
        {Artist:'The Doors',     Album:'The Doors',             Price:10.99, Quantity:79},
        {Artist:'The Doors',     Album:'Morrison Hotel',        Price:12.99, Quantity:28},
        {Artist:'Grateful Dead', Album:'American Beauty',       Price:11.99, Quantity:39},
        {Artist:'Grateful Dead', Album:'In the Dark',           Price:11.99, Quantity:30},
        {Artist:'Grateful Dead', Album:'Shakedown Street',      Price:11.99, Quantity:38}
       ]);
    
        private function init():void {
            dpADG.addEventListener(CollectionEvent.COLLECTION_CHANGE, dpADG_collectionChange);
            dpADG.refresh();
        }
    
        private var quantityTotal:Number;
        private var sumTotal:Number;
    
        private function dpADG_collectionChange(evt:CollectionEvent):void {
            quantityTotal = 0;
            sumTotal = 0;
            dpADG.source.forEach(quantitySum);
            var it:Object = dpADGTotal.getItemAt(0);
            it.Quantity = quantityTotal;
            it.Sum = sumTotal;
            dpADGTotal.setItemAt(it, 0);
        }
    
        private function quantitySum(item:*, index:int, array:Array):void {
            quantityTotal += item.Quantity;
            var sum:Number = Number(item.Price) * Number(item.Quantity);
            sumTotal += sum;
        }
    
    
       [Bindable]
       private var dpADGTotal:ArrayCollection = new ArrayCollection([
        {Artist:'', Album:'Total', Quantity:'', Sum:''}
       ]);
    
      ]]>
     </mx:Script>
     <mx:Style>
      .title {
       text-align: center;
       font-weight: bold;
      }
      .body {
       text-align: right;
       padding-right: 10;
      }
     </mx:Style>
    
     <mx:NumberFormatter id="numberFormatter"/>
     <mx:CurrencyFormatter id="currencyFormatter" precision="2" />
    
     <mx:Button label="{'Switch to Dataprovider '+ (dgS.dataProvider == dpADG ? 'without' : 'with') +'  scroll'}"
             click="dgS.dataProvider = (dgS.dataProvider == dpADG ? dpADG2 : dpADG);"/>
    
     <mx:VBox width="100%" height="100%" verticalGap="0">
      <mx:DataGrid id="dgS"
                   dataProvider="{dpADG}"
                   height="40%" width="100%"
                   resize="resizeCols();"
                   columnStretch="resizeCol(event);"
                   creationComplete="dgS.addEventListener(CollectionEvent.COLLECTION_CHANGE, resizeCols, false, 0, true);"
                   editable="true"
                   textAlign="right">
       <mx:columns>
        <mx:DataGridColumn id="dcArt"
                dataField="Artist"
                textAlign="left"
                headerStyleName="title" />
        <mx:DataGridColumn dataField="Album"
                textAlign="left"
                headerStyleName="title" />
        <mx:DataGridColumn dataField="Quantity"
                textAlign="right"
                headerStyleName="title"
                paddingRight="10"
                editable="true"
                itemEditor="mx.controls.NumericStepper"
                editorDataField="value" />
        <mx:DataGridColumn dataField="Price"
                textAlign="right"
                headerStyleName="title"
                paddingRight="10"
                labelFunction="currency_labelFunc" />
        <mx:DataGridColumn id="sumCol"
                textAlign="right"
                headerStyleName="title"
                paddingRight="10"
                editable="false"
                headerText="Sum"
                labelFunction="sum_labelFunc"
                sortCompareFunction="sum_sortCompareFunc" />
       </mx:columns>
      </mx:DataGrid>
      <mx:DataGrid id="dgtot"
                   width="40%"
                   dataProvider="{dpADGTotal}"
                   showHeaders="false"
                   rowCount="1"
                   height="{dgtot.rowHeight}"
                   creationComplete="{resizeCols()}"
                   fontWeight="bold">
       <mx:columns>
        <mx:DataGridColumn/>
        <mx:DataGridColumn dataField="Album"
                textAlign="right"
                fontStyle="italic"
                paddingRight="10" />
        <mx:DataGridColumn dataField="Quantity"
                textAlign="right"
                paddingRight="10" />
        <mx:DataGridColumn dataField="Price" />
        <mx:DataGridColumn dataField="Sum"
                textAlign="right"
                paddingRight="10"
                labelFunction="currency_labelFunc" />
       </mx:columns>
      </mx:DataGrid>
     </mx:VBox>
    
    </mx:Application>
    

    Peter

  5. how can u retrive the arraycollection field name in actionscript. like
    arraycollection(col1:’a’,col2:’b’);
    in this i want to col1.

    If possible plase let me, how convert the colums as a rows?
    arraycollection(a:’col1′,b:’col2′)

  6. my requirement is
    mydatagrid contains two columns
    column1 columnn2
    true 12
    false 15
    true 16

    if the value in column1 is true then the backgroundcolor of column2 must be red or else if the value in column1 is false then the backgroundcolor of column 2 must be
    blue

  7. Can you please provide an example on how to dynamically color any row of datagrib based on some event on datagrid row ????
    thanks in advance :)

  8. I’m looking at the examples and I suppose I’m not sure how it knows what “haloSilver” is. In my project, I have a DataGrid with five columns, populated by a PHP script that retrieves data from mysql. The first column retrieves an image to display user rank while the next three columns display text. The last column is currently unused. One of the columns currently reads ”

    I want to be able to set the background of the second, third and forth columns to #555555 but as soon as I try, I get script errors.

    http://www.battletech-live.net/error1010.png

  9. Well, I found that my problem is an apparent bug. If showHeaders is false, the debug version of Flash Player 10 will throw an error. A workaround is to keep headers visible, set their height to 1 and set their color to match the background of the columns, or as closely as possible.

Comments are closed.