Available in the Full Version
Data Grid - History.js Integration
This sample uses CTP (Community Technical Preview) features. The API and behavior may change when these features are released with full support.
This sample is designed for a larger screen size.
On mobile, try rotating your screen, view full size, or email to another device.
Ignite UI for jQuery controls are fully integrated with history.js – a popular framework for browser history support.
This sample demonstrates the Data Grid control integrated with history.js. Filter, sort, resize the list of footballers or change the grid page, to create a new view and send it using the generated browser URL.
Code View
Copy to Clipboard
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <!-- Ignite UI for jQuery Required Combined CSS Files --> <link href="http://cdn-na.infragistics.com/igniteui/2024.1/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" /> <link href="http://cdn-na.infragistics.com/igniteui/2024.1/latest/css/structure/infragistics.css" rel="stylesheet" /> <script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.8.3.js"></script> <script src="http://code.jquery.com/jquery-1.11.3.min.js"></script> <script src="http://code.jquery.com/ui/1.11.1/jquery-ui.min.js"></script> <!-- Ignite UI for jQuery Required Combined JavaScript Files --> <script src="http://cdn-na.infragistics.com/igniteui/2024.1/latest/js/infragistics.core.js"></script> <script src="http://cdn-na.infragistics.com/igniteui/2024.1/latest/js/infragistics.lob.js"></script> <!--Uncomment the histoy.js file, when you are using the pure HTML version of the sample--> <!--<script src="/js/jquery.history.js"></script>--> <style> .btn-container button { margin: 10px 10px 10px 0; width: 300px; } .seperator { float: left; } .clear { clear: both; } @media screen and (max-width: 500px) { .seperator { clear: both; } } </style> </head> <body> <div class="btn-container"> <button id="back">Previous State</button> <div class="seperator"></div> <button id="forward">Next State</button> <div class="clear"></div> <button id="copy">Copy Current Players</button> <div class="seperator"></div> <button id="mail">Send Players via e-mail</button> </div> <table id="gridHistoryJS"></table> <script src="/data-files/footballers.js"></script> <script> $(function () { var gridHistoryJS, manualStateChange = true, // true: fired by history go() and back() methods; false: fired when state is added to the history object. reverseState = [], // historyLength = window.History.storedStates.length, urlParams = window.location.search; if (window.History === undefined || window.History.getState === undefined) { alert("Please include the history.js library, by uncommenting the script reference"); return; } //--> Save igGrid state in the browser history object function addUndoState(feature, column, possibleUndo, oldValue) { var currState = window.History.getState(), data, undo = false; pos = previousPosition(feature, column); if (pos < 0) { data = { key: feature, value: column === null ? oldValue : (!oldValue) ? column : [column, oldValue] }; undo = possibleUndo; } else if (pos === 0) { data = null; } else { data = pos.data; } if (data !== null) { data.undo = undo; currState.data.undoData = data; manualStateChange = false; window.History.replaceState(currState.data); } } function previousPosition(feature, column) { var states = window.History.savedStates, length = states.length, index; for (index = length - 1; index >= 0; index--) { if (states[index].data.key === feature && (column === null || column !== null && states[index].data.value.indexOf(column) > -1)) { if (index === length - 1) { return 0; } else { return states[index]; } } } return -1; } function pushToBrowserHistory(state, title, url) { manualStateChange = false; $(state).extend({ "manualStateChange": false }); window.History ? window.History.pushState(state, title, url) : ""; } gridHistoryJS = (function initGrid() { var grid = $("#gridHistoryJS"); grid.igGrid({ primaryKey: "name", width: '100%', columns: [ { headerText: "Name", key: "name", dataType: "string", width: "12%" }, { headerText: "Team", key: "team", dataType: "string", width: "15%" }, { headerText: "Age", key: "age", dataType: "number", width: "7%" }, { headerText: "No.", key: "number", dataType: "number", width: "7%" }, { headerText: "Pos.", key: "position", dataType: "string", width: "8%" }, { headerText: "Goals", key: "goals", dataType: "number", width: "10%" }, { headerText: "Assists", key: "assists", dataType: "number", width: "10%" }, { headerText: "Yellow C.", key: "yellow", dataType: "number", width: "10%" }, { headerText: "Red C.", key: "red", dataType: "number", width: "7%" }, { headerText: "Salary", key: "salary", dataType: "number", format: "currency", width: "8%" } ], autofitLastColumn: false, autoGenerateColumns: false, dataSource: dataSource, features: [ { name: "Paging", type: "local", pageSize: 10, showPageSizeDropDown: false, pageIndexChanging: function (e, args) { addUndoState("page", null, false, args.currentPageIndex + 1, args.newPageIndex + 1); }, pageIndexChanged: function (e, args) { var pageIndex = args.pageIndex + 1, state = { key: "page", value: pageIndex }; pushToBrowserHistory(state, null, formURL("page", pageIndex)); } }, { name: "Sorting", type: "local", mode: "multi", modalDialogSortOnClick: true, columnSorting: function (e, args) { addUndoState("sort", args.columnKey, true, args.direction === "ascending" ? "descending" : "ascending"); }, columnSorted: function (e, args) { var columnKey = args.columnKey, dir = args.direction, state = { key: "sort", value: [columnKey, dir] }; if (!isEmptyValue(columnKey) && !isEmptyValue(dir)) { pushToBrowserHistory(state, null, formURL("sort", [columnKey, dir])); } } }, { name: "Filtering", type: "local", dataFiltering: function(e, args) { var expr = args.owner.grid.dataSource.settings.filtering.expressions, oldValue; oldValue = (expr.length > 0) ? expr[expr.length - 1].expr : null; addUndoState("filter", args.columnKey, true, oldValue); }, dataFiltered: function (e, args) { var columnKey = args.columnKey, expr = args.owner.grid.dataSource.settings.filtering.expressions[0], state, settings; if (expr === undefined) { settings = []; } else { settings = [columnKey, expr.cond, expr.expr]; } state = { key: "filter", value: settings }; pushToBrowserHistory(state, null, formURL("filter", settings)); } }, { name: "Resizing", columnResizing: function (e, args) { var originalWidth = args.owner.element.find("> thead > tr[data-header-row]").first().children("th").not("[data-skip=true]").get(args.columnIndex).offsetWidth; addUndoState("resize", args.columnKey, false, originalWidth); }, columnResized: function (e, args) { var columnKey = args.columnKey, width = args.originalWidth, state = { key: "resize", value: [columnKey, width] }; pushToBrowserHistory(state, null, formURL("resize", [columnKey, width])); } } ], rendered: function (e, args) { args.owner.element.find("tr td").css("text-align", "center"); args.owner.element.find("tr td:first-child").css("text-align", "left"); args.owner.element.find("tr td:last-child").css("text-align", "right"); setTimeout(function () { // Load Grid state from URL loadInitialStateFromUrl(); if (urlParams === "") { // By default "goals" and "assists" columns are sorted manualInitialSort(args); } }, 200); } }); return grid; })(); //<-- Save igGrid state in the browser history object //--> Recover igGrid state from the browser history object if (window.History && window.History.Adapter) { window.History.Adapter.bind(window, 'statechange', function (e, args) { var currState, undoState, state, prevState, stateOccurances; // isBackForward = (window.History.storedStates.length - historyLength) === 1; if ($("#sample-title")[0] !== undefined && $("#sample-title")[0].textContent !== undefined && $("#sample-title")[0].textContent.toLowerCase().indexOf("history.js") == -1) { // This check is not related to history.js integaration. It's done to integrate the sample with the Samples Browser. return; } // historyLength = window.History.storedStates.length; if (manualStateChange === true) { // Fired only when called externally from browser buttons currState = window.History.getState(); state = currState.data; undoState = state.undoData; switch (state.key) { // Load current state case "page": loadPagingState(state.key, state.value); break; case "sort": loadSortingState(state.key, state.value); break; case "filter": loadFilteringState(state.key, state.value); break; case "resize": loadResizingState(state.key, state.value); break; default: break; } // Load/Unload previous state if (undoState) { switch (undoState.key) { case "page": loadPagingState(undoState.key, undoState.value); break; case "sort": loadSortingState(undoState.key, undoState.value, undoState.undo); break; case "filter": loadFilteringState(undoState.key, undoState.value, undoState.undo); break; case "resize": loadResizingState(undoState.key, undoState.value); break; default: break; } } } manualStateChange = true; }); } //<-- Recover igGrid state from the browser history object //--> Load igGrid state from the browser URL function loadInitialStateFromUrl() { var params = urlParams, index, arrKeyValue; if (params !== "") { pairs = params.substring(1, params.length).split("&"); for (index = 0; index < pairs.length; index++) { arrKeyValue = pairs[index].split("="); loadGridState(arrKeyValue[0], arrKeyValue[1]); } // Recover URL window.History.pushState({}, null, params); } } function manualInitialSort(args) { args.owner.element.igGridSorting("sortColumn", "goals", "descending"); manualStateChange = false; addUndoState("sort", "goals", true, "ascending"); pushToBrowserHistory({ key: "sort", value: ["goals", "descending"] }, null, formURL("sort", ["goals", "descending"])); args.owner.element.igGridSorting("sortColumn", "assists", "descending"); manualStateChange = false; addUndoState("sort", "assists", true, "ascending"); pushToBrowserHistory({ key: "sort", value: ["assists", "descending"] }, null, formURL("sort", ["assists", "descending"])); } //<-- Load igGrid state from the browser URL //--> Load individual igGrid features function loadGridState(key, value) { switch (key) { case "page": loadPagingState(key, value); break; case "sort": loadSortingStateArray(key, value); break; case "filter": loadFilteringStateArray(key, value); break; case "resize": loadResizingStateArray(key, value); break; default: break; } } function loadPagingState(key, value) { if (gridHistoryJS.data("igGrid")) { gridHistoryJS.igGridPaging("pageIndex", value - 1); } } function loadSortingState(key, descriptor, undo) { var column = descriptor[0], status = descriptor[1]; if (gridHistoryJS.data("igGrid")) { if (undo) { gridHistoryJS.igGridSorting("unsortColumn", column); } else { gridHistoryJS.igGridSorting("sortColumn", column, status); } } } function loadSortingStateArray(key, value) { var columns = value.split(";"), i; if (gridHistoryJS.data("igGrid")) { for (i = 0; i < columns.length; i++) { gridHistoryJS.igGridSorting("sortColumn", columns[i].split("_", 1)[0], columns[i].split("_", 2)[1]); } } } function loadFilteringState(key, descriptor, undo) { if (gridHistoryJS.data("igGrid")) { if (undo || descriptor === undefined || descriptor.length === 0) { gridHistoryJS.igGridFiltering("filter", []); } else { gridHistoryJS.igGridFiltering("filter", [{ fieldName: descriptor[0], expr: descriptor[2], cond: descriptor[1] }]); } } } function loadFilteringStateArray(key, value) { var columns = value.split(";"), i; if (gridHistoryJS.data("igGrid")) { for (i = 0; i < columns.length; i++) { gridHistoryJS.igGridFiltering("filter", [{ fieldName: columns[i].split("_", 1)[0], expr: columns[i].split("_", 3)[2], cond: columns[i].split("_", 2)[1] }]); } } } function loadResizingState(key, descriptor) { if (gridHistoryJS.data("igGrid")) { gridHistoryJS.igGridResizing("resize", descriptor[0], descriptor[1]); } } function loadResizingStateArray(key, value) { var columns = value.split(";"), i; if (gridHistoryJS.data("igGrid")) { for (i = 0; i < columns.length; i++) { gridHistoryJS.igGridResizing("resize", columns[i].split("_", 1)[0], columns[i].split("_", 2)[1]); } } } //<-- Load individual igGrid features //--> Create URL function formURL(key, value, multiple) { var params = window.location.search, urlValue = value, urlIndex, currentUrl, currentColumnState; if (isEmptyValue(value)) { // remove parameters encoded in the URL urlIndex = params.indexOf(key + "="); params = params.replace(key + "=" + extractURLValue(key), ""); if (params === "?") { params = ""; } else { params = params.substring(0, urlIndex - 1) + params.substring(urlIndex, params.length); } } else { // add parameters encoded in the URL if (value instanceof Array) { urlValue = value[0]; for (urlIndex = 1; urlIndex < value.length; urlIndex++) { urlValue += "_" + value[urlIndex]; } } if (params === "") { params = "?" + key + "=" + urlValue; } else if (params.indexOf(key + "=") === -1) { params = params + "&" + key + "=" + urlValue; } else { currentUrl = key + "=" + extractURLValue(key); if (key === "page") { params = params.replace(currentUrl, key + "=" + urlValue); } else { currentColumnState = value[0] + "_"; if (currentUrl.indexOf(currentColumnState) > -1) { params = params.replace(getColumnState(currentUrl, currentColumnState), urlValue); } else { params = params.replace(currentUrl, currentUrl + ";" + urlValue); } } } } return params; } function extractURLValue(key) { var params = window.location.search, value = ""; value = params.substring(params.indexOf(key), params.length); value = value.substring(key.length + 1, (value.indexOf("&") > -1) ? value.indexOf("&") : value.length); return value; } function getColumnState(featureUrl, column) { var state, columnStartIndex, columnEndIndex; columnStartIndex = featureUrl.indexOf(column); state = featureUrl.substring(columnStartIndex, featureUrl.length); columnEndIndex = state.indexOf("&") > -1 ? state.indexOf("&") : state.length; state = state.substring(0, columnEndIndex); columnEndIndex = state.indexOf(";") > -1 ? state.indexOf(";") : state.length; state = state.substring(0, columnEndIndex); return state; } //<-- Create URL function isEmptyValue(value) { return value === undefined || value === null || value.length === 0; } $("#back").igButton().click(function () { window.history.back(); }); $("#forward").igButton().click(function () { window.history.forward(); }); $("#copy").igButton().click(function () { window.prompt("Copy URL and open it in a new tab or browser", window.location); }); $("#mail").igButton().click(function () { var link = "mailto: ?subject= List with Footballers&body= Use the following custom list with footballers: " + escape(window.location); window.location.href = link; }); }); </script> </body> </html>
var dataSource = [ { name: "Messi", team: "Barcelona", age: 26, number: 10, position: "FW", goals: 60, assists: 16, yellow: 2, red: 0, salary: 26.5 }, { name: "C. Ronaldo", team: "Real Madrid", age: 28, number: 7, position: "LW", goals: 55, assists: 12, yellow: 13, red: 1, salary: 25 }, { name: "Villa", team: "Atletico Madrid", age: 26, number: 7, position: "FW", goals: 16, assists: 5, yellow: 1, red: 0, salary: 12 }, { name: "Benzema", team: "Real Madrid", age: 25, number: 9, position: "CF", goals: 33, assists: 19, yellow: 0, red: 0, salary: 10 }, { name: "Fabregas", team: "Barcelona", age: 26, number: 10, position: "FW", goals: 43, assists: 16, yellow: 2, red: 0, salary: 14 }, { name: "Di Maria", team: "Real Madrid", age: 28, number: 22, position: "RW", goals: 9, assists: 13, yellow: 5, red: 2, salary: 8 }, { name: "Xavi", team: "Barcelona", age: 26, number: 7, position: "CM", goals: 16, assists: 5, yellow: 1, red: 0, salary: 14 }, { name: "Ozil", team: "Real Madrid", age: 25, number: 9, position: "AM", goals: 33, assists: 19, yellow: 0, red: 0, salary: 10 }, { name: "Iniesta", team: "Barcelona", age: 26, number: 8, position: "CM", goals: 6, assists: 20, yellow: 4, red: 0, salary: 12.5 }, { name: "Ramos", team: "Real Madrid", age: 27, number: 4, position: "CB", goals: 5, assists: 1, yellow: 14, red: 2, salary: 9 }, { name: "Neymar", team: "Barcelona", age: 21, number: 11, position: "FW", goals: 43, assists: 15, yellow: 3, red: 1, salary: 20 }, { name: "Isco", team: "Real Madrid", age: 21, number: 23, position: "AM", goals: 13, assists: 12, yellow: 4, red: 0, salary: 19 }, { name: "Pedro", team: "Barcelona", age: 26, number: 7, position: "FW", goals: 10, assists: 7, yellow: 6, red: 0, salary: 13 }, { name: "Iker", team: "Real Madrid", age: 32, number: 1, position: "GK", goals: 0, assists: 0, yellow: 1, red: 0, salary: 16 }, { name: "Valdes", team: "Barcelona", age: 31, number: 1, position: "GK", goals: 0, assists: 0, yellow: 12, red: 1, salary: 14 }, { name: "Higuain", team: "Napoli", age: 25, number: 9, position: "FW", goals: 9, assists: 13, yellow: 5, red: 1, salary: 8 }, { name: "Puyol", team: "Barcelona", age: 35, number: 4, position: "CB", goals: 2, assists: 0, yellow: 5, red: 0, salary: 18 }, { name: "Kaka", team: "Real Madrid", age: 31, number: 8, position: "AM", goals: 5, assists: 5, yellow: 1, red: 2, salary: 15 }, { name: "Sergio", team: "Barcelona", age: 25, number: 16, position: "CM", goals: 1, assists: 2, yellow: 11, red: 1, salary: 13.5 }, { name: "Alonso", team: "Real Madrid", age: 31, number: 14, position: "CM", goals: 8, assists: 0, yellow: 18, red: 0, salary: 14 }, { name: "Courtois", team: "Atletico Madrid", age: 20, number: 14, position: "GK", goals: 0, assists: 0, yellow: 0, red: 0, salary: 7 }, { name: "Koke", team: "Atletico Madrid", age: 21, number: 6, position: "MF", goals: 3, assists: 0, yellow: 0, red: 0, salary: 9 }, { name: "Falcao", team: "Monaco", age: 29, number: 9, position: "FW", goals: 21, assists: 5, yellow: 3, red: 0, salary: 24 }, { name: "Neuer", team: "Bayern Munich", age: 27, number: 1, position: "GK", goals: 0, assists: 0, yellow: 2, red: 0, salary: 12 }, { name: "Ribery", team: "Bayern Munich", age: 30, number: 7, position: "LW", goals: 11, assists: 23, yellow: 4, red: 1, salary: 16 }, { name: "Schweinsteiger", team: "Bayern Munich", age: 29, number: 31, position: "CM", goals: 9, assists: 15, yellow: 10, red: 0, salary: 17 }, { name: "Lewandowski", team: "Borussia Dortmund", age: 24, number: 9, position: "CF", goals: 36, assists: 9, yellow: 5, red: 0, salary: 12 }, { name: "Reus", team: "Borussia Dortmund", age: 24, number: 11, position: "FW", goals: 19, assists: 11, yellow: 1, red: 0, salary: 8 }, { name: "Gotze", team: "Bayern Munich", age: 24, number: 11, position: "FW", goals: 16, assists: 16, yellow: 3, red: 0, salary: 15 }, { name: "Balotelli", team: "Milan", age: 23, number: 45, position: "FW", goals: 15, assists: 5, yellow: 3, red: 0, salary: 12 }, { name: "Buffon", team: "Juventus", age: 23, number: 1, position: "GK", goals: 0, assists: 0, yellow: 0, red: 0, salary: 12 }, { name: "Pirlo", team: "Juventus", age: 34, number: 21, position: "MF", goals: 8, assists: 18, yellow: 7, red: 0, salary: 11 }, { name: "Torres", team: "Chelsea", age: 29, number: 9, position: "FW", goals: 22, assists: 8, yellow: 0, red: 0, salary: 12 }, { name: "Mata", team: "Chelsea", age: 25, number: 10, position: "MF", goals: 20, assists: 18, yellow: 4, red: 0, salary: 15 }, { name: "Lampard", team: "Chelsea", age: 34, number: 8, position: "MF", goals: 17, assists: 10, yellow: 4, red: 0, salary: 17 }, { name: "Hazard", team: "Chelsea", age: 22, number: 17, position: "MF", goals: 13, assists: 18, yellow: 1, red: 1, salary: 14 }, { name: "Oscar", team: "Chelsea", age: 21, number: 11, position: "MF", goals: 12, assists: 6, yellow: 6, red: 0, salary: 10 }, { name: "Ramires", team: "Chelsea", age: 26, number: 7, position: "MF", goals: 9, assists: 18, yellow: 7, red: 0, salary: 11 }, { name: "Luiz", team: "Chelsea", age: 26, number: 4, position: "CB", goals: 7, assists: 1, yellow: 16, red: 0, salary: 12 }, { name: "Silva", team: "PSG", age: 28, number: 2, position: "DF", goals: 1, assists: 1, yellow: 10, red: 1, salary: 14 }, { name: "Berbatov", team: "Fulham", age: 32, number: 9, position: "FW", goals: 15, assists: 7, yellow: 4, red: 0, salary: 12 } ]