【问题标题】:Persisting jqGrid column preferences持久化 jqGrid 列首选项
【发布时间】:2012-01-15 09:51:26
【问题描述】:

我的 ASP.NET MVC 3 应用程序中有一些 jqGrid,它们有许多列。我在列定义中添加了以下内容以默认隐藏某些列:

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

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

然后我添加了这个来实现列选择器:

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

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

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

所以我现在可以很好地隐藏/显示列。现在,您将如何保存这些信息? D B?作为饼干?另一种方式?有没有一种首选的方式来存储这种真正是用户偏好的信息,而不是与数据本身相关的信息?


更多信息

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

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

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

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

我想要做的是提供一种方法来保留特定用户想要查看的列,这样他/她就不必在每次显示带有该网格的页面时重新选择这些列来查看。

【问题讨论】:

  • 您的问题的答案可能很难取决于您的要求。 IceCreamID 的示例我发现不是最好的,因为我个人不明白为什么需要将信息放在网格中。例如,您可以将信息作为行 ID 放置。您可以使用额外组合的 rowid,例如 'IceCreamID'+'_'+'RecipeID'。您应该以任何方式发布有关您的网格和环境的更多信息。
  • Oleg,在问题中查看我的附加信息。
  • 您尝试过我 5 天前发布的代码吗?很高兴看到您对我的回答有任何意见。
  • @Oleg - 是的,我今天早上看到了。谢谢。这几天一直在做其他工作。当然,我很快就会对此发表评论。 :)
  • my new answer 包含我对您问题的回答的扩展版本,因此您可能会感兴趣。

标签: asp.net-mvc asp.net-mvc-3 jqgrid


【解决方案1】:

我发现你的问题很有趣。在很多情况下,关于保存网格用户状态的问题很有趣。对于使用 cookie 的此类问题,有一些有趣的答案(例如,参见 here)。

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

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

所以我会花一些时间来实现两个演示,展示它是如何实现的。由于很多原因,我在演示中使用了localStorage。我从那里只提到两个:

  1. Cookie 是一种向服务器发送或从服务器发送永久不同信息的方式,而这并不是真正需要的。它会增加 HTTP 标头的大小并降低网站的性能(例如,请参阅 here)。
  2. Cookie 有非常严格的限制。对应于 rfc2109 的 6.3 或 rfc6265 的 6.1 部分:每个 cookie 至少 4096 个字节,每个域至少 50 个 cookie(在 rfc2109 中为 20 个),总共至少 3000 个 cookie(在 rfc2109 中为 300 个)。所以cookies不能用来保存太多的信息。例如,如果您要保存每个网页的每个网格的状态,您可以快速达到限制。

另一方面,localStorage 受到所有现代浏览器的支持,并将在从 IE8 开始的 Internet Explorer 中得到支持(请参阅here)。 localStorage 将自动保存每个来源(如 a1.example.com、a2.example.com、a3.example.com 等),并且每个来源有 5 MB 的任意限制(请参阅here)。因此,如果您仔细使用空间,您将远离任何限制。

所以我在演示中使用了localStorage。我还应该提一下,如果浏览器支持并使用其他存储,则有一些像jStorage 这样的插件使用localStorage,但对于像IE6/IE7 这样的旧浏览器,你的界面相同。如果您只有较小的存储空间:128 kB 而不是 5 MB,但最好是 4K,后者用于 cookie(请参阅here)。

现在关于实施。我创建了两个演示:this,它是扩展版本:this

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

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

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

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

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'`)定义为不同页面上的不同值。

The second demo 是第一个使用我的old answer 到您的另一个问题的技术的扩展。该演示使用搜索工具栏,并在高级搜索表单和搜索工具栏之间同步附加信息。

更新next answer 包含上述代码的扩展版本。它显示了如何另外持久化选定的行(或行)。 Another answer 展示了如何持久化树形网格的展开节点列表,并在页面重载时展开节点。

【讨论】:

  • 优秀。按“清除保存的设置按钮”应该也重新加载网格恕我直言。
  • 我添加了 window.location.reload() 作为快速而肮脏的修复。这显示了原始设置。
  • @Oleg:如果使用鼠标对列重新排序,则不会保留新的列顺序。在这种情况下如何保持新的列顺序?
  • @Andrus:查看我最近的另一个answer,它展示了如何监控列的重新排序。应该只在定义为函数的sortable 内调用saveColumnState
  • @Oleg JSON.parse(window.localStorage.getItem(storageItemName)); 停止在 Android 中执行 javascript。 (您可以在三星测试实验室中使用现场设备远程测试)。将JSON.parse 替换为$.parseJSON 后,它也可以在Android 中使用。
猜你喜欢
  • 1970-01-01
  • 2010-10-28
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 2014-08-08
  • 2013-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多