坚持jqGrid列首选项

我有我的ASP.NET MVC 3应用程序有一些列jqGrids。 我将以下内容添加到列定义中以默认要隐藏的某些列:

colModel: [ { name: 'IceCreamID', hidden: true}, { name: 'RecipeID', hidden: true } 

这很好用。 这些列在我的网格上不可见。

然后我添加这个来实现列select器:

 var grid = $('#icecreamGrid'); grid.jqGrid('navButtonAdd', '#icecreamPager', { caption: "Columns", buttonicon: "ui-icon-calculator", title: "Choose Columns", onClickButton: function() { grid.jqGrid('columnChooser'); } }); 

太好了,现在提出列select器。 然后,我将以下内容添加到列select器中不想显示的列中:

 colModel: [ { name: 'IceCreamID', hidden: true, hidedlg: true}, 

所以我现在可以隐藏/显示列很好。 现在,你将如何坚持这个信息? DB? 作为一个cookie? 另一种方式? 有没有一种首选的方法来存储这种信息,这实际上是一种用户偏好,而不是与数据本身相关的东西?


更多信息

根据Oleg的评论,我想提供更多的信息。

这里的要点是我有10-15列的网格, 可以根据用户的喜好进行显示。 举一个简单的例子,我的一个网格有以下9列:

 IceCream|ShortName|HasNuts|SugarAdded|LimitedRun|PromoItem|Facility|FirstRun|LastRun 

用户可以根据他们的个人偏好来隐藏/显示这9列中的任何一列。

我想要做的是提供一种方法来保存特定用户希望看到的列,以便每次显示具有该网格的页面时他/她不必重新select这些列以查看。

我发现你的问题很有意思。 在很多情况下,关于保存网格用户状态的问题很有意思。 关于使用cookie的这些问题有一些有趣的答案(参见这里例子)。

在我看来,在服务器或localStorage数据库中保存网格状态是使用cookie的更好方法。 最好的方法取决于您使用它的项目要求。 例如,使用服务器上的数据库存储,可以实现网格的漫游状态。 如果您使用localStorage而不是cookie,则用户首选项将丢失,如果用户转到另一台计算机,或者只是用户在同一台​​计算机上使用另一个Web浏览器。

电网状态的另一个问题是维护。 通常在JavaScript或HTML文件中,而不是在数据库中,关于网格列的信息。 在这两种来源可以不同步在网格中的变化。 更新问题的不同场景可以轻松想象。 尽pipe如此,在某些情况下用户偏好的优势如此之大,以至于小缺点的问题并不那么重要,可以相对容易地解决。

所以我会花一些时间来实施两个演示,展示如何实现。 我在演示中使用了localStorage ,原因很多。 我只提到了两个:

  1. Cookies是永久向服务器发送不同信息的方式,而不是真正的要求。 它增加了HTTP头的大小,并降低了网站的性能(参见这里 )。
  2. Cookie有很严格的限制。 对应于rfc2109的6.3节或rfc6265的6.1节:每个cookie至less4096个字节,每个域至less50个cookie(rfc2109中的20个),总共至less3000个cookie(rfc2109中的300个)。 所以不能用来保存太多信息的cookies。 例如,如果要保存每个网页的每个网格的状态,可以快速达到限制。

另一方面,所有现代浏览器都支持localStorage ,IE8开始支持IE浏览器(见这里 )。 localStorage会自动保存为每个来源(如a1.example.com,a2.example.com,a3.example.com等),每个来源的任意限制为5 MB(请参阅此处 )。 所以,如果你仔细使用这个空间,你将远离任何限制。

所以我在我的演示中使用了localStorage 。 我还应该提到,有一些像jStorage这样的插件,如果浏览器支持使用localStorage ,并使用另一个存储,但在IE6 / IE7等旧浏览器中使用相同的接口。 在这种情况下,你只有更小的存储空间:128 kB而不是5 MB,但是最好是4K( 这里请参阅这里 )。

现在谈谈实施。 我创build了两个演示: 这个和它的扩展版本: 这个 。

在第一个演示中,网格的以下状态将被保存并在页面重新加载时自动恢复(大多数Web浏览器中的F5 ):

  • 哪一列是隐藏的
  • 列的顺序
  • 每列的宽度
  • 网格的sorting名称和sorting方向
  • 当前页码
  • 网格的当前filter和是否应用filter的标志。 我在网格中使用了multipleSearch: true设置。

以同样的方式可以扩展(或减less)作为已保存网格状态一部分的选项列表。

演示代码中最重要的部分将在下面find:

 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); } }); 

请小心在演示中定义myColumnStateName (值为“ColumnChooserAndLocalStorage.colState”)到不同页面上的不同值。

第二个演示是第一个使用从旧的答案到另一个问题的技术的扩展。 演示使用search工具栏,并在高级search表单和search工具栏之间同步附加信息。

更新 : 下一个答案包含上述代码的扩展版本。 它显示了如何坚持选定的行(或行)额外。 另一个答案显示了如何保留树网格的展开节点列表,并在页面重新展开时展开节点。