Well, since I did a post on the Nested DataGrid last week, I figured that it was time to address another frustrating issue with the DataGrid. If you try to set a percentage width on a DataGridColumn, the MXML compiler throws an error because that functionality is not built into the DataGrid or the DataGridColumn.

Like many others who have tried to solve this problem, I have looked around for a workaround to solve the problem and after being frustrated I decided to build my own component to manage this. The most common alternative solution that I have found is based off of an Adobe TechNote which basically tells you to use the function below which should be run in the “creationComplete” event of the DataGrid:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
function setRelativeColWidths()
{
    dg.getColumnAt(0).width = dg1.width*.10;
    dg.getColumnAt(1).width = dg1.width*.15;
    dg.getColumnAt(2).width = dg1.width*.50;
    dg.getColumnAt(3).width = dg1.width*.10;
    dg.getColumnAt(4).width = dg1.width*.15;
}

I don’t like this solution for a couple of reasons.  First off, if I remove a column from the DataGrid, the method above throws an RTE, so I have to remember to remove it from above.  Second, I don’t like it because it is too much work and seems unnecessary. Third, I don’t like it because it doesn’t seem to work in all cases.  There are times when it will work in the “creationComplete” handler, and then sometimes it doesn’t, but it will work in the “addedToStage” handler, and then sometimes neither of them will work!

So I created a custom component called ScalableDataGrid. It contains a property called columnWidths which allows you to pass in the percentage widths or explicit widths for each of the columns. For example, if we have a dataProvider that looks like this:

?View Code ACTIONSCRIPT
1
2
3
4
5
6
[Bindable]
private var dp:ArrayCollection = new ArrayCollection([
    {col1: "C1 R1", col2: "C2 R1", col3: "C3 R1", col4: "C4 R1"},
    {col1: "C1 R2", col2: "C2 R2", col3: "C3 R2", col4: "C4 R2"},
    {col1: "C1 R3", col2: "C2 R3", col3: "C3 R3", col4: "C4 R3"}
]);

and I want to give col1 a 40% width, col2 a 60% width, col3 an explicit width of 200 pixels, and col4 an explicit width of 300 pixels, I would do the following:

1
2
3
4
5
6
7
8
<nross:ScalableDataGrid dataProvider="{dp}" width="100%" columnWidths="{['35%', '65%', '100', '100']}">
    <nross:columns>
        <mx:DataGridColumn dataField="col1" headerText="Column 1" textAlign="center"/>
        <mx:DataGridColumn dataField="col2" headerText="Column 2" textAlign="center" />
        <mx:DataGridColumn dataField="col3" headerText="Column 3" textAlign="center" />
        <mx:DataGridColumn dataField="col4" headerText="Column 4" textAlign="center" />
    </nross:columns>
</nross:ScalableDataGrid>

This would make it so that whenever the DataGrid’s 100% relative width is changed, the DataGridColumn widths specified in the columnWidths Array are persisted. The only case where this is not true is if the user manually resizes one of the columns. If this is the case, the columns width will default back to how the original DataGrid functions so that users won’t be frustrated when they resize a column and then find that when the DataGrid’s relative width is changed, it is snapped back to the width in the columnWidths Array.

While this is not the ideal solution (Adobe should just make it so that DataGridColumns can natively support percentage widths) I have found that it works perfectly for my needs, so I want to share it in the hopes that it can help someone else with similar issues.

See the demo and get the source here (Right click to View Source).

Also, feel free to combine ScalableDataGrid with last week’s NestedDataGrid custom component.  Just download both components and then make ScalableDataGrid extend NestedDataGrid or vice versa!

Tags: , , , , ,

22 Responses


  1. Nate on 22 Apr 2009

    @daveoncode,

    Your solution only works for percentages, but not a combination of the two. What if I want the first column to be 70%, the second to be 30%, and the last to be 50 pixels?

    1
    2
    3
    4
    5
    6
    7
    
    <mx:DataGrid dataProvider="{dummyData}" width="100%" height="300">
      <mx:columns>
        <mx:DataGridColumn dataField="label" width="0.7"/>
        <mx:DataGridColumn dataField="data" width="0.3"/>
        <mx:DataGridColumn dataField="extra" width="50"/>
      </mx:columns>
    </mx:DataGrid>

    The result is that the last column is gigantic whereas the other two are tiny. The reason is because the DataGrid takes the total of all the widths and then uses the total width of the DataGrid to allocate a percentage to each. For purely percentage-based columns, this works, but not for a combination.

  2. Jonny on 10 Jul 2009

    There doesn’t seem to be a view source option when I right click on the demo. Is the source still available?

    Thanks.

  3. Nate on 10 Jul 2009

    Sorry about that Jonny.

    “View Source” has been enabled when you right click on the app.

  4. Jonny on 16 Jul 2009

    Thanks for the reply Nate. This should be really helpful.

  5. Karl on 31 Aug 2009

    But this is Flex 2, isn’t it? It won’t work in Flex 3 or Gumbo.

  6. HexTheKiwi on 17 Sep 2009

    This is brilliant – exactly the solution what I was looking for.

    What licence do you have on the code for this blog entry? Is it placed in the public domain?

    Thanks.

  7. Nate on 17 Sep 2009

    @Hex,

    Glad to hear ScalableDataGrid helps you. All code on my site is free to use for any purpose unless explicitly stated otherwise. You may use ScalableDataGrid in any manner you would like. Thank you for taking the time to double-check though.

  8. Fatima on 30 Dec 2009

    Its really helpful

  9. richard willis on 05 Jan 2010

    nice work nate, saved me a heap of work, thanks :)

  10. Josh Bell on 11 Mar 2010

    Brilliant!!

  11. Green on 14 Jul 2010

    Thank you for sharing this solution – it is very nice. Had to adapt it for a case of hidden/shown again columns, but the extending was very easy.

  12. Andrew on 23 Aug 2010

    Worked perfectly for me. Thanks for saving me time…

  13. Zinovii Dmytriv on 07 Oct 2010

    Great job! It was very helpful. Thanks!

  14. cheng on 15 Nov 2010

    not work for flex4

  15. Joel on 16 Nov 2010

    This does not work if there is a horizontal scroll. Anyone have a solution for this:

  16. xleon on 23 Nov 2010

    Great solution! It´s been a great help for my project.
    Thanks a lot

  17. Nate on 23 Nov 2010

    @Joel,

    This is expected. If you are using a horizontal scrollbar on your grid, you shouldn’t have need for this class.

  18. mihai on 22 Feb 2011

    looks cool, but for me crashes at

    columns[i].setWidth(w);
    columns[i].explicitWidth = w;
    columns[i].preferredWidth = w;

    and I really don’t understand this part of code… I don’t have that setWidth() method anywhere

  19. Jason Fry on 05 Mar 2011

    @mihai yeah I had that problem too. I think it’s something to do with Flex 3/4. I fixed it by changing the lines:

    columns[i].setWidth(w);
    columns[i].explicitWidth = w;
    columns[i].preferredWidth = w;

    to:

    columns[i].width = w;

    in the ScalableDataGrid.as class.

    Other than that, great little component! I’ve spent far too long trying to get something like this working. Cheers!

  20. Jonathan on 10 May 2011

    Thanks much Nate for this elegant solution!

  21. Jay on 09 Apr 2012

    Thanks for the excellent component, Nate!

    I used it with an AdvancedDataGrid in Flex 3.5 and found the space available for columns seemed to be 2 pixels less than the unscaledWidth of the table, so I changed the code to initialize leftoverWidth to:
    var leftoverWidth:Number = unscaledWidth – 2;

    I have a lot of rows in my tables, so I also added the following code to take the vertical scroll bar into account:

    if (verticalScrollBar != null && verticalScrollBar.visible)
    {
    leftoverWidth -= verticalScrollBar.width;
    }


Leave your comment


ray ban wayfarer ebay ray ban aviators
bag borrow or steal
Buy shoes online india
replica handbags