I am dynamically adding columns to a grid because I don't know the names of all the columns until runtime. That worked great until I needed to turn on filtering. There will be four preset views that will filter the data rows, showing and hiding rows based on the definition of the filter, which I do know at design time.
Here's the definition of the grid:
$(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", hidden: true }, { headerText: "", key: "RowFormat", dataType: "numeric", hidden: true }, { 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", hidden: true }, { 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: "###,###,###" } ], features: [ { name: "Filtering", type: "local", mode: "simple", filterSummaryAlwaysVisible: false, renderFilterButton: false, columnSettings: [ { columnKey: "RowFormat", allowFiltering: false }, { columnKey: "Oversold", allowFiltering: false }, { columnKey: "Status", allowFiltering: false }, { columnKey: "OrderNumberInfo", allowFiltering: false }, { columnKey: "GeneralDescription", allowFiltering: false }, { columnKey: "RowDate", allowFiltering: false }, { columnKey: "RowDateFormat", allowFiltering: false }, { columnKey: "MultiIndicator", allowFiltering: false }, { columnKey: "FobOrTransfer", allowFiltering: false }, { columnKey: "PackageSize", allowFiltering: false }, { columnKey: "BoardFeet", allowFiltering: false } ] } ], 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
The functions that add the dynamic columns and perform other duties are here:
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: FixLengthHeaderColumnNames(item), width: "75px", dataType: "number", format: "###,###,###" }; cols.push(newColumn); // This is how we signal when a column is oversold var oversoldColumn = { headerText: "", key: "Oversold" + FixLengthHeaderColumnNames(item), width: '0px', dataType: 'bool' } cols.push(oversoldColumn); } ); // Finish $("#mainGrid_" + gridIndex).igGrid("option", "columns", cols); // Now set the filtering for all those new columns to false var colSettings = $("#mainGrid_" + gridIndex).igGridFiltering("option", "columnSettings"); $.each(columnList, function (index, lengthColumnName){ var filterColumn = FixLengthHeaderColumnNames(lengthColumnName); var oversoldFilterColumn = "Oversold" + FixLengthHeaderColumnNames(lengthColumnName); for (var i = 0; i < colSettings.length; i++) { if (colSettings[i].columnKey === filterColumn || colSettings[i].columnKey === oversoldFilterColumn) { colSettings[i].allowFiltering = false; } } }); $("#mainGrid_" + gridIndex).igGridFiltering("option", "columnSettings", colSettings); } function FixLengthHeaderColumnNames(columnName) { return columnName.replace(/[^a-z,A-Z0-9_]/g, '_'); } 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 dateCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", "RowDate"); var dateCell = $(gridSelector).igGrid("cellAt", rowIndex, dateCellIndex); 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 lengthCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", dynamicColumn); var lengthCell = $(gridSelector).igGrid("cellAt", lengthCellIndex, rowIndex); $(lengthCell).addClass("overSoldHighlight"); var orderCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", "OrderNumberInfo"); var orderCell = $(gridSelector).igGrid("cellAt", orderCellIndex, rowIndex); $(orderCell).addClass("overSoldHighlight"); var generalDescriptionCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", "GeneralDescription"); var generalDescriptionCell = $(gridSelector).igGrid("cellAt", generalDescriptionCellIndex, rowIndex); $(generalDescriptionCell).addClass("overSoldHighlight"); var rowDateCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", "RowDate"); var rowDateCell = $(gridSelector).igGrid("cellAt", rowDateCellIndex, rowIndex); $(rowDateCell).addClass("overSoldHighlight"); var multiIndicatorCellIndex = $(gridSelector).igGrid("getVisibleIndexByKey", "MultiIndicator"); var multiIndicatorCell = $(gridSelector).igGrid("cellAt", multiIndicatorCellIndex, rowIndex); $(multiIndicatorCell).addClass("overSoldHighlight"); } } catch (e2) { console.error("Highlight error for Grid = " + gridSelector + ". Column = Oversold" + dynamicColumn + ". Row = " + rowIndex + ". Error = " + e2); } }); }); } function SwitchView(viewName) { // loop through each of the grid layouts and set the filter to display the proper view var layoutCount = @Model.Layouts.Count; switch (viewName) { case "ForecastByProduct": $("#title").html("Production Forecast Detail"); $("#productionForecastDetailRow").removeClass("displayInline").addClass("displayHidden"); $("#productionForecastSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#weekOfProductionSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#vmiProductionDetailRow").removeClass("displayHidden").addClass("displayInline"); break; case "ForecastByProduction": $("#title").html("Production Forecast Summary"); $("#productionForecastDetailRow").removeClass("displayHidden").addClass("displayInline"); $("#productionForecastSummaryRow").removeClass("displayInline").addClass("displayHidden"); $("#weekOfProductionSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#vmiProductionDetailRow").removeClass("displayHidden").addClass("displayInline"); break; case "ForecastVmi": $("#title").html("VMI Production Forecast Detail"); $("#productionForecastDetailRow").removeClass("displayInline").addClass("displayHidden"); $("#productionForecastSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#weekOfProductionSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#vmiProductionDetailRow").removeClass("displayInline").addClass("displayHidden"); break; case "ForecastWeekOf": $("#title").html("Week Of Production Forecast Summary"); $("#productionForecastDetailRow").removeClass("displayInline").addClass("displayHidden"); $("#productionForecastSummaryRow").removeClass("displayHidden").addClass("displayInline"); $("#weekOfProductionSummaryRow").removeClass("displayInline").addClass("displayHidden"); $("#vmiProductionDetailRow").removeClass("displayHidden").addClass("displayInline"); break; } for (var i = 0; i < layoutCount; i++) { SwitchGridView(viewName, i.toString()); } return false; } function SwitchGridView(viewName, gridIndex) { var filters = []; switch(viewName) { case "ForecastByProduct": filters = [ { fieldName: "RowType", expr: 10, cond: "equals", logic: "OR" }, // On Hand Inventory { fieldName: "RowType", expr: 20, cond: "equals", logic: "OR" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals", logic: "OR" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals", logic: "OR" }, // Production { fieldName: "RowType", expr: 50, cond: "equals", logic: "OR" }, // Picked / Ready { fieldName: "RowType", expr: 60, cond: "equals", logic: "OR" }, // Picked / Ready Summary { fieldName: "RowType", expr: 70, cond: "equals", logic: "OR" }, // Purchase Order { fieldName: "RowType", expr: 80, cond: "equals", logic: "OR" } // Inbound Transfer ]; break; case "ForecastByProduction": filters = [ { fieldName: "RowType", expr: 10, cond: "equals", logic: "OR" }, // On Hand Inventory //{ fieldName: "RowType", expr: 20, cond: "equals", logic: "OR" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals", logic: "OR" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals", logic: "OR" } // Production //{ fieldName: "RowType", expr: 50, cond: "equals", logic: "OR" }, // Picked / Ready //{ fieldName: "RowType", expr: 60, cond: "equals", logic: "OR" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "equals", logic: "OR" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "equals", logic: "OR" } // Inbound Transfer ]; break; case "ForecastVmi": filters = [ { fieldName: "RowType", expr: 10, cond: "equals", logic: "OR" }, // On Hand Inventory { fieldName: "RowType", expr: 20, cond: "equals", logic: "OR" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals", logic: "OR" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals", logic: "OR" } // Production //{ fieldName: "RowType", expr: 50, cond: "equals", logic: "OR" }, // Picked / Ready //{ fieldName: "RowType", expr: 60, cond: "equals", logic: "OR" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "equals", logic: "OR" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "equals", logic: "OR" } // Inbound Transfer ]; break; case "ForecastWeekOf": filters = [ { fieldName: "RowType", expr: 10, cond: "equals", logic: "OR" }, // On Hand Inventory //{ fieldName: "RowType", expr: 20, cond: "equals", logic: "OR" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals", logic: "OR" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals", logic: "OR" } // Production //{ fieldName: "RowType", expr: 50, cond: "equals", logic: "OR" }, // Picked / Ready //{ fieldName: "RowType", expr: 60, cond: "equals", logic: "OR" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "equals", logic: "OR" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "equals", logic: "OR" } // Inbound Transfer ]; break; } $("mainGrid_" + gridIndex).igGridFiltering("filter", filters); }
The problems I'm running into currently are these.
BTW - I am making the ajax call and getting a JSON return for the data, but the data is not showing up in the grid.
What am I doing wrong?
Hello,
Can you confirm when is the error received. Is it when setting the columnSettings or is it when applying the filter?
I'm not sure. I've stepped through the debugger when it's defining the columns and setting the columnSettings and it does not throw the error at that point. It gets all the way through the AddLengthColumns function and calls the Ajax call before it throws the error. (I think)
This sound like an issue into the filtering feature. I'll need some more time to investigate it and make sure it is really an issue.
Meanwhile you could access directly the filtering editors and set their option to disabled. Here's a fiddle to demo this - http://jsfiddle.net/dkamburov/czd7ey83/6/
After further investigations I saw that there is a difference when the filtering columnSettings are applied on initialization of the grid or afterwards.
Setting allowFiltering in columnSettings dynamically does not remove the filtering editor so I logged this behavior into our internal tracking system with number 270349. I've opened a private cases for you with number: CAS-207818-S0Z9B2 and have linked to it so that you'll be notified once the issue has been resolved. The next step will be to review it and offer a fix, or other resolution.
I will leave this case open and update you with any new information after the review. You can also continue to send updates to this case at any time.
You can view the status of the development issue connected to this case by selecting the "Development Issues" tab when viewing this case on the web site.
Please let me know if you need more information.
Thanks Deyan. Your fiddle code did help to get rid of the javascript errors that I was getting. I simply defined the grid in the return event in the ajax call when I know all the column names. However, switching the filtering view doesn't seem to work.
function SwitchGridView(viewName, gridIndex) { var filters = []; switch(viewName) { case "ForecastByProduct": filters = [ { fieldName: "RowType", expr: 10, cond: "equals" }, // On Hand Inventory { fieldName: "RowType", expr: 20, cond: "equals" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals" }, // Production { fieldName: "RowType", expr: 50, cond: "equals" }, // Picked / Ready { fieldName: "RowType", expr: 60, cond: "equals" }, // Picked / Ready Summary { fieldName: "RowType", expr: 70, cond: "equals" }, // Purchase Order { fieldName: "RowType", expr: 80, cond: "equals" } // Inbound Transfer ]; break; case "ForecastByProduction": filters = [ { fieldName: "RowType", expr: 10, cond: "equals" }, // On Hand Inventory { fieldName: "RowType", expr: 30, cond: "equals" }, // Available to Ship Inventory { fieldName: "RowType", expr: 50, cond: "equals" } // Picked / Ready //{ fieldName: "RowType", expr: 40, cond: "doesNotEqual" }, // Production //{ fieldName: "RowType", expr: 20, cond: "doesNotEqual" }, // Order Info //{ fieldName: "RowType", expr: 60, cond: "doesNotEqual" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "doesNotEqual" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "doesNotEqual" } // Inbound Transfer ]; break; case "ForecastVmi": filters = [ { fieldName: "RowType", expr: 10, cond: "equals" }, // On Hand Inventory { fieldName: "RowType", expr: 20, cond: "equals" }, // Order Info { fieldName: "RowType", expr: 30, cond: "equals" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals" } // Production //{ fieldName: "RowType", expr: 50, cond: "doesNotEqual" }, // Picked / Ready //{ fieldName: "RowType", expr: 60, cond: "doesNotEqual" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "doesNotEqual" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "doesNotEqual" } // Inbound Transfer ]; break; case "ForecastWeekOf": filters = [ { fieldName: "RowType", expr: 10, cond: "equals" }, // On Hand Inventory { fieldName: "RowType", expr: 30, cond: "equals" }, // Available to Ship Inventory { fieldName: "RowType", expr: 40, cond: "equals" } // Production //{ fieldName: "RowType", expr: 20, cond: "doesNotEqual" }, // Order Info //{ fieldName: "RowType", expr: 50, cond: "doesNotEqual" }, // Picked / Ready //{ fieldName: "RowType", expr: 60, cond: "doesNotEqual" }, // Picked / Ready Summary //{ fieldName: "RowType", expr: 70, cond: "doesNotEqual" }, // Purchase Order //{ fieldName: "RowType", expr: 80, cond: "doesNotEqual" } // Inbound Transfer ]; break; } // Apply the filters to the dataSource var dsArrayIndex = parseInt(gridIndex); var ds = dataSourceArray[dsArrayIndex]; if (ds !== undefined && ds !== null) { ds.filter(filters); $("mainGrid_" + gridIndex).igGrid("dataSourceObject", ds); } }