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!