In the previous post I described a method to automatically resize columns for Infragistics grid control. It works (most of the times) for flat WebDataGrid, but if you try same approach with WebHierarchicalDataGrid – it will fail for child bands.
Lets review what we’re trying to accomplish. A grid column should automatically resize to whichever is wider: either size of widest data in a column cell, or size of column header’s caption.
First is accomplished by not setting column width explicitly and by setting white-space attribute of cell’s style to nowrap. It can be done by either opening grid CSS class file located at ~/ig_res/[Your Style Name]/ig_dataGrid.css, locate tbody.igg_[Your Style Name]Item>tr>td class and add one more line at the end: white-space:nowrap. Here is an example with Office 2007 Style:
tbody.igg_Office2007BlueItem>tr>td { background-color:White; border-right:solid 1px #D0D7E5; border-bottom:solid 1px #D0D7E5; padding:2px 5px 2px 5px; height: 18px; overflow: hidden; text-align:left; vertical-align:middle; white-space:nowrap; }
Or (if you don’t want to touch original style) same can be achieved by *CssClass properties exposed by the grid.
Second (resizing column to header’s caption width, if it is wider then cells’ data) is a bit tricker. After a bit of research and trial & error I realized that the most reliable way to resize a column to a certain width is to resize data in a column cell. So here is the solution I came up with: If column header’s caption is wider than column’s data – take the data from the first cell in that column and encompass it in a DIV with width equal column header’s caption width. Confused? It will become clearer in a moment. Here is the JavaScript function that does the trick:
// Resizes grid columns to correct length // i_oGridView: Grid (parent/or child) which columns need resizing) function initGridColumns(i_oGridView) { // refefrence to grid columns var aGridCols = i_oGridView.get_columns(); if (!aGridCols) return; var iColCount = aGridCols.get_length(); if (iColCount == 0) return; var oCol, oCell, oFirstRow, iCapLength // looping thru grid columns, adjusting their length for (var I = 0; I < iColCount; I++) { oCol = aGridCols.get_column(I); if (!oCol.get_hidden()) { oFirstRow = i_oGridView.get_rows().get_row(0); oCell = oFirstRow.get_cell(oCol.get_index()); iCapLength = oCol.get_headerText().length * 8; // If header width is wider then data width - // resize column to header width if (iCapLength > oCell.get_element().offsetWidth) { oCell.get_element().innerHTML = '<div style="width:' + iCapLength + 'px">' + oCell.get_element().innerHTML + '</div>' } } } }
It accepts one parameter – grid control, which can be a WebDataGrid or GridView portion of WebHierarchicalDataGrid. The magic happens in Lines 23-28. Code checks if width necessary to display full caption (which is calculated in this case as caption text’s length * 8, your case may differ depending on font style and size), so if this width is bigger than current column width (which is determined by first row’s data cell’s offsetWidth, because other methods turned to be unreliable), anyway if this is the case – that cell’s data is surrounded by DIV of the header’s width.
Here is an example of calling this code for child bands. It can be placed in grid’s RowExpanded event:
function xMyGrid_RowExpanded(sender, eventArgs) { var aChildGrids = eventArgs.get_row().get_rowIslands(); for (var I = 0; I < aChildGrids.length; I++) { initGridColumns(aChildGrids[I]) } }
It loops thru child bands, calling the function to resize columns. The result – beautifully formatted grid:
UPDATE 3/30/2012: This worked fine in NetAdvantage circa 2009.2, but starting 2011.1 is no longer a viable solution – it became incredibly, excruciatingly slow. Apparently now for every resized cell a grid event is called which call internal setAbsoluteWidth
method thousands of times. I am still looking for an alternative because even 2011 versions of WHDG do not support autosizing.
UPDATE 4/2/2012: I think I may have found the workaround to speed this up. Grid has to be invisible at the time when InitGridColumns
runs. In my case grid is located inside of a DIV element, so, before calling the function display style of that DIV is set to NONE (and appropriate message like “Please wait. Loading…” is displayed) With this approach both initial load and paging take 1-2 seconds. Also since all dimensions (including offsetWidth
) will be 0 in NONE mode, you can skip checking for element width and apply the modification to all columns – it will display correctly for both long cells and short cells. With a few more optimizations and additions, function looks like this:
function initGridColumns(i_oGridView) { //if first row doesn't exist - grid is not populated - return var oFirstRow = i_oGridView.get_rows().get_row(0); if (!oFirstRow) return; // reference to grid columns var aGridCols = i_oGridView.get_columns(); if (!aGridCols) return; var iColCount = aGridCols.get_length(); if (iColCount == 0) return; var oCellElement, iCapLength; // looping thru grid columns, adjusting their length for (var I = 7; I < iColCount; I++) { iCapLength = aGridCols.get_column(I).get_headerText().length * 8; oCellElement = oFirstRow.get_cell(I).get_element(); oCellElement.innerHTML = '<div style="width:' + iCapLength + 'px">' + oCellElement.innerHTML + '</div>'; } }
This is great. It looks like your grid above is placed in a div with overflow set to ‘auto’. If that’s true, when you scroll the grid vertically, do the grid headers scroll up out of view?
Yes, if the DIV does the scrolling for your grid then entire grid will scroll including headers will scroll. You may have to implement a workaround (e.g. position element with headers absolutely) to keep headers in place.
i’ve tried absolute positioning and it doesn’t work.
This worked for me but I had to modify the following line:
oCellElement.innerHTML = ” + oCellElement.innerHTML + ”;
Note the added “px” indicator.
I think your website removed the html from my previous comment. I had to add “px” after “+ iCapLength + ‘ to get this to work.
@Galloway: Thanks! (Kicking myself, repeating: “style dimensions must include measurement units!) will update the code.
I ran into one more gotcha. When entering edit mode on a cell in the 1st row, the html is displayed (the div element wrapped around the cell value.) It doesn’t happen in cells that use an editor control like a drop down or a datepicker, but plain text and numeric cells are affected. I’m still trying to find a workaround for that issue
Works great!! Your solution saved my time. Thanks!
Any idea how to use it in vb.net?
@JKL – this has to be done on client-side i.e. in browser’s JavaScript, sever-side code at that point (vb.net etc.) doesn’t play a role.
Managed to do it entirely on server-side in code. I’m setting each column width in loop for every row to a larger size choosing from two: item(i).column.header.text.length * 7 and item(i).column.text.length * 5. I have a different constant values because the header font is larger. Didn’t have to do anything else. Works like a charm. Thanks for steering me in the right direction!
@JKL, glad you found a solution. This may not work well though if you have line-breaks, paragraphs etc. in your cells text (total text length might be big, but actual width is small, e.g. if a cell has a value like
1. Apples
2. Oranges
3. Cherries.
Also if your cells contain HTML markup – actual text field might be small, but the field itself big, e.g. if you display something with font-sizes, <H1>, or any other markup that changes text size – plus images can be displayed in the cell as well.