I've got a few jqGrids on my ASP.NET MVC 3 application that have a number of columns. I added the following to the column definitions to default some columns to be hidden:
colModel: [
{ name: 'IceCreamID', hidden: true},
{ name: 'RecipeID', hidden: true }
and this works nicely. Those columns aren't visible on my grid.
Then I added this to implement the column chooser:
var grid = $('#icecreamGrid');
grid.jqGrid('navButtonAdd', '#icecreamPager',
{ caption: "Columns", buttonicon: "ui-icon-calculator",
title: "Choose Columns",
onClickButton: function() {
grid.jqGrid('columnChooser');
}
});
Great, brings up the column chooser now. I then added the following to columns I never wanted to show up in the column chooser:
colModel: [
{ name: 'IceCreamID', hidden: true, hidedlg: true},
So I can now hide/show columns just fine. Now, how would you persist this information? DB? As a cookie? Other way? Is there a preferred way to store this sort of information that is really a user preference rather than something related to the data itself?
More Info
Based on Oleg's comment below, I want to provide a little more information.
The point here is that I've got grids with 10-15 columns which could be display based on the user's preference. For a simple example, one of my grid's has the following 9 columns:
IceCream|ShortName|HasNuts|SugarAdded|LimitedRun|PromoItem|Facility|FirstRun|LastRun
Users can hide/show any of these 9 columns based on their personal preferences.
What I want to do is provide a way to persist which columns a particular user wants to see so that s/he doesn't have to re-choose those columns to view each time the page with that grid is shown.
I found you question very interesting. The question about saving the user state of grid are interesting in many cases. There are some interesting answers on such problems which uses cookie (see here for example).
In my opinion saving of the grid state in database on the server or in the localStorage
is better way as the usage of cookie. The best way depends on the project's requirements in which you use it. For example the usage of the database storage on the server allows you to implement roaming state of the grid. If you use the localStorage
instead of cookies the user preferences will be lost if the user goes to another computer or just if the user will use another web browser on the same computer.
Another problem with the grid state is the maintenance. The information about the columns of the grid you hold typically in the JavaScript or HTML files and not in the database. In the case the both sources can be not synchronous on the changes in the grid. Different scenarios of the update problem could you easy imagine. Nevertheless the advantages of user's preferences so large in some scenarios that the problems with small disadvantages are not so important and can be solved relatively easy.
So I'll spend some time to implement two demos which shows how it can be implemented. I used localStorage
in my demos because of many reasons. I mention only two from there:
On the other side localStorage
are supported by all modern browsers and will be supported in Internet Explorer starting with IE8 (see here). The localStorage
will be automatically saved per origins (like a1.example.com, a2.example.com, a3.example.com, etc) and has arbitrary limit of 5 MB per origin (see here). So if you use the space carefully you will far from the any limits.
So I used in my demos the localStorage
. I should additionally mention that there are some plugins like jStorage which use localStorage
if it's supported by the browser and use another storage, but the same interface for you in case of old browsers like IE6/IE7. In the case you has only less size of storage: 128 kB instead of 5 MB, but it's better as 4K which one has for cookies (see here).
Now about the implementation. I creates two demos: this and it's extended version: this.
In the first demo the following states of grid will be saved and automatically restored on the page reload (F5 in the most web browsers):
multipleSearch: true
setting in the grid.In the same way one can extend (or reduce) the list of options which are the part of the saved grid state.
The most important parts of the code from the demo you will find below:
var $grid = $("#list"),
saveObjectInLocalStorage = function (storageItemName, object) {
if (typeof window.localStorage !== 'undefined') {
window.localStorage.setItem(storageItemName, JSON.stringify(object));
}
},
removeObjectFromLocalStorage = function (storageItemName) {
if (typeof window.localStorage !== 'undefined') {
window.localStorage.removeItem(storageItemName);
}
},
getObjectFromLocalStorage = function (storageItemName) {
if (typeof window.localStorage !== 'undefined') {
return $.parseJSON(window.localStorage.getItem(storageItemName));
}
},
myColumnStateName = 'ColumnChooserAndLocalStorage.colState',
saveColumnState = function (perm) {
var colModel = this.jqGrid('getGridParam', 'colModel'), i, l = colModel.length, colItem, cmName,
postData = this.jqGrid('getGridParam', 'postData'),
columnsState = {
search: this.jqGrid('getGridParam', 'search'),
page: this.jqGrid('getGridParam', 'page'),
sortname: this.jqGrid('getGridParam', 'sortname'),
sortorder: this.jqGrid('getGridParam', 'sortorder'),
permutation: perm,
colStates: {}
},
colStates = columnsState.colStates;
if (typeof (postData.filters) !== 'undefined') {
columnsState.filters = postData.filters;
}
for (i = 0; i < l; i++) {
colItem = colModel[i];
cmName = colItem.name;
if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
colStates[cmName] = {
width: colItem.width,
hidden: colItem.hidden
};
}
}
saveObjectInLocalStorage(myColumnStateName, columnsState);
},
myColumnsState,
isColState,
restoreColumnState = function (colModel) {
var colItem, i, l = colModel.length, colStates, cmName,
columnsState = getObjectFromLocalStorage(myColumnStateName);
if (columnsState) {
colStates = columnsState.colStates;
for (i = 0; i < l; i++) {
colItem = colModel[i];
cmName = colItem.name;
if (cmName !== 'rn' && cmName !== 'cb' && cmName !== 'subgrid') {
colModel[i] = $.extend(true, {}, colModel[i], colStates[cmName]);
}
}
}
return columnsState;
},
firstLoad = true;
myColumnsState = restoreColumnState(cm);
isColState = typeof (myColumnsState) !== 'undefined' && myColumnsState !== null;
$grid.jqGrid({
// ... other options
page: isColState ? myColumnsState.page : 1,
search: isColState ? myColumnsState.search : false,
postData: isColState ? { filters: myColumnsState.filters } : {},
sortname: isColState ? myColumnsState.sortname : 'invdate',
sortorder: isColState ? myColumnsState.sortorder : 'desc',
loadComplete: function () {
if (firstLoad) {
firstLoad = false;
if (isColState) {
$(this).jqGrid("remapColumns", myColumnsState.permutation, true);
}
}
saveColumnState.call($(this), this.p.remapColumns);
}
});
$grid.jqGrid('navButtonAdd', '#pager', {
caption: "",
buttonicon: "ui-icon-calculator",
title: "choose columns",
onClickButton: function () {
$(this).jqGrid('columnChooser', {
done: function (perm) {
if (perm) {
this.jqGrid("remapColumns", perm, true);
saveColumnState.call(this, perm);
}
}
});
}
});
$grid.jqGrid('navButtonAdd', '#pager', {
caption: "",
buttonicon: "ui-icon-closethick",
title: "clear saved grid's settings",
onClickButton: function () {
removeObjectFromLocalStorage(myColumnStateName);
}
});
Be carefully to define myColumnStateName
(the value `'ColumnChooserAndLocalStorage.colState'``) in the demo) to different values on the different pages.
The second demo is the extension of the first one using the technique from my old answer to your another question. The demo use the searching toolbar and synchronize additionally information between the advanced searching form and the searching toolbar.
UPDATED: The next answer contains extended version of the code included above. It shows how to persist the selected rows (or row) additionally. Another answer shows how to persist the list of expanded nodes of the tree grid and expand the nodes on the relaoding of the page.