Setup:
I'm dynamically creating multiple grids on a single page based on some table definition criteria passed into the page via an MVC template.
There are common columns that are easily defined, and then there are additional column values that vary by grid. (Each grid has a unique ID value)
I add the additional columns after each main grid has been defined, then use an ajax call to get the data to populate each grid.
Here's the code that is invoked on the main page:
@using ForecastMvc.Models; @model BuildMatricesModel @{ Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>@ViewBag.Title</h2> @Html.DisplayFor(x => x.Layouts)
Layouts is a list of type MatrixLayout.
MatrixLayout.cshtml is below:
@model ForecastMvc.DataLayer.MatrixLayout <div> <label class="font-weight-bold" id="headerLableForGrid_@Model.GridIndex">@Model.Description</label> </div> <table id="mainGrid_@Model.GridIndex"></table> <hr/> <script type="text/javascript"> // On load $(function () { // Define the grid $("#mainGrid_@Model.GridIndex").igGrid({ autoGenerateColumns: false, width: "100%", dataSource: new Array(0), // Just use an empty array to define the dataSource for now. We will populate it with data later dataSourceType: "json", scrolling: true, columns: [ { headerText: "", key: "RowType", dataType: "numeric", width: "0px" }, { headerText: "", key: "RowFormat", dataType: "numeric", width: "0px" }, { headerText: "", key: "Oversold", width: "25px", dataType: "string" }, { headerText: "", key: "Status", width: "25px", dataType: "string" }, { headerText: "", key: "OrderNumberInfo", width: "100px", dataType: "string" }, { headerText: "", key: "GeneralDescription", width: "200px", dataType: "string" }, { headerText: "", key: "RowDate", width: "150px", dataType: "string" }, { headerText: "", key: "RowDateFormat", dataType: "numeric", width: "0px" }, { headerText: "", key: "MultiIndicator", width: "20px", dataType: "string" }, { headerText: "", key: "FobOrTransfer", width: "100px", dataType: "string" }, { headerText: "Pkg", key: "PackageSize", width: "75px", dataType: "string" }, { headerText: "Brd Ft", key: "BoardFeet", width: "90px", dataType: "numeric", format: "###,###,###" } ], rowsRendered: function() { FormatGrid('@Model.GridIndex', @Html.Raw(Json.Encode(Model.LengthValues))); } }); // Add the length value columns to the grid. The AddLengthColumns function is in the main page AddLengthColumns('@Model.GridIndex', @Html.Raw(Json.Encode(Model.LengthValues))); // Get the data for the grid. The GetData function is in the main page GetData('@Model.GridIndex', @Html.Raw(Json.Encode(Model))); }); // End onLoad </script>
As you can see, the common column definitions are setup in the Page.OnLoad event, and the event handler is setup for each grid with the unique grid index and a list of the additional column values.
Following the grid definition, I then add the additional length columns in the AddLengthColumns function and then call the GetData function to invoke the Ajax call to get the data for that particular grid.
The matrix definition is passed back to the controller with each grid that is requesting the data. That way each ajax call is self-contained.
Here is the JavaScript for the main page:
<script type="text/javascript"> function GetData(gridIndex, matrixLayout) { $.ajax({ type: "POST", url: '@Url.Action("GetDataForTable", "Home")', data: matrixLayout, dataType: "json" // we are expecting JSON data back }) .done( function (json) { $("#mainGrid_" + gridIndex).igGrid("option", "dataSource", json); $("#mainGrid_" + gridIndex).igGrid("dataBind"); }) .fail( function(jqXhr, textStatus, errorThrown) { console.warn(jqXhr.responseText); alert(errorThrown + ' getJSON request failed for grid ' + gridIndex, textStatus); }) .always( function() { } ); } function AddLengthColumns(gridIndex, columnList) { // Get var cols = $("#mainGrid_" + gridIndex).igGrid("option", "columns"); // Set - Iterate through the columnList and add new columns for each length value in the list $.each(columnList, function(index, item) { var newColumn = { headerText: item, key: item, width: "75px", dataType: "number", format: "###,###,###" }; cols.push(newColumn); // This is how we signal when a column is oversold var oversoldColumn = { headerText: "", key: "Oversold" + item, width: '0px', dataType: 'bool' } cols.push(oversoldColumn); } ); // Finish $("#mainGrid_" + gridIndex).igGrid("option", "columns", cols); } function FormatGrid(gridIndex, dynamicColumnList) { var gridSelector = "#mainGrid_" + gridIndex; // Contains all the rows for this grid var rows = $(gridSelector).igGrid("rows"); if (rows.length === 0) return; // This happens on the first bind to an empty array, we need to ignore that binding $.each(rows, function (rowIndex, row) { try { var rowBold = $(gridSelector).igGrid("getCellValue", rowIndex, "RowFormat"); if (rowBold !== null && rowBold === 1 || rowBold === '1') { $(row).addClass("rowBoldFormat"); } } catch (e) { console.error("Error trying to bold row " + "Row = " + rowIndex + " " + e); } try { // Date Red/Green formatting var dateFormat = $(gridSelector).igGrid("getCellValue", rowIndex, "RowDateFormat"); if (dateFormat !== null && dateFormat !== undefined) { var dateCell = $(gridSelector).igGrid("cellById", rowIndex, "RowDate"); if (dateCell !== null && dateCell !== undefined) { if (dateFormat === 1) { $(dateCell).addClass("dateDisplayGreen"); } // 2 is red else if(dateFormat === 2) { $(dateCell).addClass("dateDisplayRed"); } } } } catch (e1) { console.error("Error trying to format Date. " + e1); } $.each(dynamicColumnList, function (columnIndex, dynamicColumn) { try { var oversoldCell = $(gridSelector).igGrid("getCellValue", rowIndex, "Oversold" + dynamicColumn); if (oversoldCell !== null && oversoldCell !== undefined && oversoldCell === true) { var lengthCell = $(gridSelector).igGrid("cellById", rowIndex, dynamicColumn); $(lengthCell).addClass("overSoldHighlight"); var orderCell = $(gridSelector).igGrid("cellById", rowIndex, "OrderNumberInfo"); $(orderCell).addClass("overSoldHighlight"); var generalDescriptionCell = $(gridSelector).igGrid("cellById", rowIndex, "GeneralDescription"); $(generalDescriptionCell).addClass("overSoldHighlight"); var rowDateCell = $(gridSelector).igGrid("cellById", rowIndex, "RowDate"); $(rowDateCell).addClass("overSoldHighlight"); var multiIndicatorCell = $(gridSelector).igGrid("cellById", rowIndex, "MultiIndicator"); $(multiIndicatorCell).addClass("overSoldHighlight"); } } catch (e2) { console.error("Highlight error for Grid = " + gridSelector + ". Column = Oversold" + dynamicColumn + ". Row = " + rowIndex + ". Error = " + e2); } }); }); } </script>
The problem I'm having is in the FormatGrid function for the dynamic columns. I've stepped through the JavaScript, and I'm finding the Oversold + dynamicColumn value and I'm finding each of the other columns where I need to change the background color, but the background color never changes.
What am I doing wrong? It's got to be something simple that I'm missing. Am I correct?
Hello,
I believe the issue is that the rows are being re-rendered after the formatting of the cells.
Note there are a lot of reasons for rendering the rows again, for example changing a page, or each interaction that causes data binding.
You should apply the formatting of the cells into the rowsRendered event. In this way the cells will receive their formatting every time rows are being rendered/re-rendered.
Hello Deyan,
Thanks for replying. I am using the rowsRendered event to apply formatting.
rowsRendered: function() { FormatGrid('@Model.GridIndex', @Html.Raw(Json.Encode(Model.LengthValues))); }
Ken
Hello Kenneth,
I've missed that one, but it seems correct. Can you confirm that the classes are applied to the cells?
Could those styles be overridden by something else?
I'm not sure. This is what I see in the debugger when I set a breakpoint after the length column is selected using this jQuery:
var lengthCell = $(gridSelector).igGrid("cellById", rowIndex, dynamicColumn); $(lengthCell).addClass("overSoldHighlight");
it selects something, and I add the class to it, but I can't tell if the selector is getting a TD element. I think the prevObject appears to point to the grid if that's of any help.
That is an empty object. It seems that the grid cannot find a cell with the specified parameters.
Note that cellById is using rowId(not rowIndex) and columnKey. Rows of an igGrid will have ids if you define primaryKey. To get the cell you can alternatively use cellAt and getVisibleIndexByKey:
var cellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", dynamicColumn); var lengthCell = $(gridSelector).igGrid("cellAt", rowIndex, cellIndex);
That helped a great deal, thank you. It's finding the cells now and applying the styling.
That's great. I'm glad to hear you got it working.