I have browsed the Telerik forums many times in the past, but this is my first time posting. I am trying to have all of the columns in a RadGrid resize automatically every time the page loads. Currently, I am using the client-side resizeToFit method that I found recommended in many forum threads by Telerik employees as well as documented here:http://www.telerik.com/help/aspnet-ajax/grid-gridcolumn-resizetofit.html
The code I have below works perfectly when viewing the grid and when editing an existing row on the grid (as in, each column resizes to fit the widest control contained within its cells); however, when inserting a new row using the InitInsert command, the resizeToFit method does not cause the columns to expand to fit the widest control contained in their cells. Instead, the columns stay at the same size they were before initiating the insert command, and since the editing controls are wider than the read controls, the editing controls get cut off (although the columns expand fine as long as you're editing an existing row and not inserting a new one).
I have ensured that the code is getting hit by setting breakpoints, and I have verified that my RadGrid.ClientSettings.Resizing settings are set correctly. (I have AllowResizeToFit = true; ClipCellContentOnResize = false; AllowColumnResize = true; EnableRealTimeResize = false; AllowRowResize = false; ResizeGridOnColumnResize = true--all set at runtime in the code-behind, where I verified that it is being hit by setting breakpoints.)
I have considered setting each column width manually when the MasterTableView is in insert mode, but this is not a very good solution since I am using one RadGrid to display several different datasets (where the dataset to be displayed is determined by the module selected) and each dataset has its own set of columns, each with their own column names, data types, and controls. The only other option I can think of to work around this issue is to edit an existing item using editItem (http://www.telerik.com/help/aspnet-ajax/grid-gridtableview-edititem.html) when the MasterTableView is in insert mode (http://www.telerik.com/help/aspnet-ajax/grid-gridtableview-get-isiteminserted.html), but that does not look good at all and it takes the page longer to load after initiating an insert command.
Here is the code I have right now:
function pageLoad() {
var grid = $find('<%= RadGrid1.ClientID %>');
var view= grid.get_masterTableView();
var columns = view.get_columns();
for (var i = 0; i < columns.length; i++) {
columns[i].resizeToFit();
}
}10 Answers, 1 is accepted
The resize method does not take into consideration the controls inside the insert item of the grid in this case. The method determines the width of the column by the content in the tBody element of the grid's table and the <th> elements of the column headers. Normally the insert item is rendered as part of the tHead element of the table and it does not fall in the calculations of the resizeToFit method which ignores all rows in the tHead element except the one holding the column headers. In the case of editing the edit item is rendered as part of the tBody of the table so it is correctly picked up by the method and takes part in determining the width of the column.
One possible workaround here would be to manually call the resizeColumn client-side method of the masterTableView (width the preferred value) if the width of any control in the insert item cells exceeds the current width of the column for that cell.
Marin
Telerik
That definitely makes sense; however, I believe you may have missed the part of my original post where I refer to the fixes that I have already attempted and why they are not effective as solutions in this case (since you suggest using resizeColumn, which is the first attempted fix that I mention, although I admit that I did not include the exact method that I was referring to):
(From my original post)
I have considered setting each column width manually [using resizeColumn] when the MasterTableView is in insert mode, but this is not a very good solution since I am using one RadGrid to display several different datasets (where the dataset to be displayed is determined by the module selected) and each dataset has its own set of columns, each with their own column names, data types, and controls. The only other option I can think of to work around this issue is to edit an existing item using editItem (http://www.telerik.com/help/aspnet-ajax/grid-gridtableview-edititem.html) when the MasterTableView is in insert mode (http://www.telerik.com/help/aspnet-ajax/grid-gridtableview-get-isiteminserted.html), but that does not look good at all and it takes the page longer to load after initiating an insert command.
Is there a solution that would dynamically resize the column widths to fit their controls while in insert mode?
I would rather not use resizeColumn to explicitly set the width for each column when the width of any control in the insert item cells exceeds the current width of the column for that cell, since that method would amount to setting explicit widths for about 200 distinct columns in total (since as I mentioned, I am using one RadGrid on a base page to display several different datasets).
With your current code in pageLoad at the end of the first post you are already iterating over all the columns in the grid and calling resizeToFit for each of them. ResizeToFit performes some calculations and internally also calls the resizeColumn method with a proper value to change the width of the column. However in insert mode the value passed internally to the resizeColumn method is not the correct one. That's why my idea is to manually determine the correct width for that column and call the columnResize method manually once again to set the correct width. It's basically what the resizeToFit does but with your own custom logic in the case of insert mode.
Here is what the code might look like:
function pageLoad() { var grid = $find('<%= RadGrid1.ClientID %>'); var view = grid.get_masterTableView(); var columns = view.get_columns(); for (var i = 0; i < columns.length; i++) { columns[i].resizeToFit(); //if the grid is in insert mode and the width of the textbox exceeds the current width of the column then: masterTableView.resizeColumn(i, newWidth); } }This should not present such a big performance overhead since you are already iterating over each column, you simply further adjust its width to the correct one.
Let me know how this works in your case and if you have any other questions.Regards,
Marin
Telerik
Right, I definitely understand what you're saying, Marin. The only difficult part of using resizeColumn with custom logic (to imitate resizeToFit for an inserted row) is to dynamically determine each column's newWidth based on the width of the inserted row's controls.
Below I have included a change to the function from my original post. There is a comment where the value of newWidth should be placed, as I could use some help determining what methods/properties would allow me to dynamically find the width of the control contained in the inserted row's current column (columns[i]). Do you have any suggestions?
function pageLoad() { var grid = $find('<%= RadGrid1.ClientID %>'); var view= grid.get_masterTableView(); var columns = view.get_columns(); for (var i = 0; i < columns.length; i++) { if (view.get_isItemInserted()) {
var inserted = view.get_insertItem();
var newWidth = // Width of control contained in columns[i] view.resizeColumn(i, newWidth);
}
else columns[i].resizeToFit(); }} Indeed determining the new best fit width for the column is not a simple task. I overrode one of the internal client-side functions of the grid that takes care exactly of this part and modified it to also includes the rows in insert mode. (The general idea is to create a mock table container with certain styles (e.g. table-layout:auto) and populate it with the rows and cells of the original grid, then let the browser render this new mock container where each column will be automatically adjusted to its best fit size. From then on the algorithm simply calls resizeColumn to apply the newly calculated width for each column ). Below is all the code need to achieve your requirement and let the grid columns also resize properly when there is a row in insert mode:
function pageLoad() { var grid = $find('<%= RadGrid1.ClientID %>'); var masterTableView = grid.get_masterTableView(); var columns = masterTableView.get_columns(); for (var i = 0; i < columns.length; i++) { columns[i].resizeToFit(); } } Telerik.Web.UI.GridColumn.prototype._createFitTestContainer = function (table, skipHeaderCell) { var parent = table.parentNode; var containerId = parent.id + "_FitTestContainer"; var fitTestTableId = containerId + "_FitTestTable"; var fragment = document.createDocumentFragment(); var container = document.createElement("div"); fragment.appendChild(container); container.id = containerId; container.style.position = "absolute"; container.style.visibility = "hidden"; if (table.tBodies.length > 0) { container.innerHTML = "<table class='" + table.className + "' cellspacing='0' border='0' style='" + table.style.cssText + ";table-layout:auto;white-space:nowrap;width:auto;'><tbody>" + table.tBodies[table.tBodies.length - 1].innerHTML + "</tbody></table>"; } var fitTestTable = container.childNodes[0]; fitTestTable.id = fitTestTableId; var rowsToDelete = []; for (var i = 0, length = fitTestTable.rows.length; i < length; i++) { var row = fitTestTable.rows[i]; if (!(row.id && row.id.indexOf(table.id) > -1)) { rowsToDelete.push(row); } } var rowToDelete = rowsToDelete.pop() while (rowToDelete) { fitTestTable.deleteRow(rowToDelete.rowIndex); rowToDelete = rowsToDelete.pop(); } if (!skipHeaderCell) { var thead = fitTestTable.createTHead(); var headerRow = thead.insertRow(-1); var origRow = this.get_element().parentNode; var cells = origRow.cells; for (var i = 0, length = cells.length; i < length; i++) { var headerCell = headerRow.insertCell(i); headerCell.className = cells[i].className; headerCell.style.cssText = cells[i].style.cssText; headerCell.style.width = "auto"; if ($telerik.isIE && Sys.Browser.version <= 7) { //IE7 ignores white-space:nowrap, so use <nobr> instead headerCell.innerHTML = "<nobr>" + cells[i].innerHTML + "</nobr>"; } else { headerCell.innerHTML = cells[i].innerHTML; } } if (!!table.tHead && table.tHead.rows.length > 0) { var headerRows = table.tHead.rows; for (var j = 0, l = headerRows.length; j < l; j++) { var hRow = headerRows[j]; if (hRow.className && hRow.className.indexOf("rgEditRow") > -1) { var insertRow = thead.insertRow(-1); insertRow.className = hRow.className; var cells = hRow.cells; for (var i = 0, length = cells.length; i < length; i++) { var headerCell = insertRow.insertCell(i); headerCell.className = cells[i].className; headerCell.style.cssText = cells[i].style.cssText; headerCell.style.width = "auto"; headerCell.innerHTML = cells[i].innerHTML; } break; } } } } parent.appendChild(fragment.childNodes[0]); return document.getElementById(fitTestTableId); }You can check how the above code works in your scenario and let me know if you have any other questions.
Regards,
Marin
Telerik
I tried out the code that you included in your reply exactly as written (besides adding brackets to wrap the pageLoad function and removing an extra exclamation point at "if (!!table.tHead && table.tHead.rows.length > 0)") and it runs without error; however, when I try to insert a new row, I am still having the same issue where the column widths are too narrow to view the contained controls.
I set up multiple breakpoints, so I know the override function is definitely getting hit and it's also being called/run without error... I'm not quite sure where to go next at this point.
I'd appreciate any insight you have on how I can get this code working, and thanks for the continued support!
The exclamation point (both of them) are part of the if statement that I added to handle the case of the insert row in the table header. It is simply a boolean converter. Generally it is better to have boolean values in the if statement (especially more complex ones) instead of something like "undefined", "null" etc... In this case it is not really that important so you can remove both exclamation points if you want, without changing the behavior, but don't leave only one because this will reverse the condition and the code will never execute. I am attaching a sample runnable page that shows the code working correctly in all cases.
Marin
Telerik
I tried out your code sample and that works perfectly for me. However, using the exact same client code and structure within my own project yields no results unfortunately. I construct the RadGrid programmatically and add it to a PlaceHolder, but that shouldn't really matter since all of the client settings match up with your code sample. In addition, I set breakpoints within your code sample and within my own project to compare how the code runs, and both run identically (through the client code).
The only thing I can really thing of that would cause the client code to not work might be that I am using a few different GridTemplateColumns for custom controls, so maybe there is something in my ITemplate, IBindableTemplate class that is preventing the correct operation--I still need to review this class further..
But the surprising thing is that (the standard) resizeToFit() expands the GridTemplateColumns to fit the contained controls perfectly when in inline edit mode, yet the provided client code has no effect. Do you have any ideas about what may be preventing the correct operation of your code?
I was not able to replicate the issue with the template columns in Marin's sample project. Could you please provide us with a small runnable sample where the issue could be observed in order to investigate the it locally? A modified sample is attached to this reply for your reference.
Regards,
Kostadin
Telerik