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:
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:
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!
take a look here: http://www.daveoncode.com/2009/03/18/set-datagridcolumns-width-in-percentage-with-ease/
@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?
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.
There doesn’t seem to be a view source option when I right click on the demo. Is the source still available?
Thanks.
Sorry about that Jonny.
“View Source” has been enabled when you right click on the app.
Thanks for the reply Nate. This should be really helpful.
But this is Flex 2, isn’t it? It won’t work in Flex 3 or Gumbo.
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.
@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.
Its really helpful
nice work nate, saved me a heap of work, thanks
Brilliant!!
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.
Worked perfectly for me. Thanks for saving me time…
Great job! It was very helpful. Thanks!
not work for flex4
This does not work if there is a horizontal scroll. Anyone have a solution for this:
Great solution! It´s been a great help for my project.
Thanks a lot
@Joel,
This is expected. If you are using a horizontal scrollbar on your grid, you shouldn’t have need for this class.
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
@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!
Thanks much Nate for this elegant solution!
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;
}