5

与监视动态变化数据的“仪表板”应用程序中的网格一样,我的 (Telerik) Kendo UI 网格每隔 60 秒定期用新数据刷新:

grid.dataSource.data(freshData);
grid.refresh();  // have been informed this refresh may not be necessary

架构不会更改,但一些新行可能会显示在数据集中,而一些新行可能已被删除。

尽管grid.refresh()保留分组完好无损,并且排序状态也被保留,但任何折叠的组都会被扩展。

问题:如何保留(或恢复)组的展开/折叠状态(因此,专注于特定展开组而其他组折叠的用户不会因每个组被重新展开的定期更新而感到不便/沮丧默认)?

编辑:一些 Winforms 网格提供了一种在刷新数据之前对组展开/折叠状态“拍摄快照”的方法,然后在数据源刷新后重新应用该状态。如果 Kendo UI 网格中的组标题行具有 UID(在刷新后仍然存在),则可以完成。 但请参阅下面不涉及持久 UID 的建议方法。

用例:这是此功能的一个典型但有些戏剧性的用例。疾病控制中心正在按城市实时监测特定流感病毒的爆发情况。每 15 秒刷新一次数据集。他们碰巧现在专注于洛杉矶,并扩大了那个城市,而其他城市则倒塌了。如果整个网格每 15 秒膨胀一次,就会激怒 CDC 的医生,他们进去勒死程序员,然后回家打高尔夫球,洛杉矶的每个人都屈服了。剑道真的要为那场灾难负责吗?

可能的功能增强建议:忽略我对上述 UID 的建议。这是一个更好的方法。网格有

<div class="k-group-indicator" data-field="{groupedByDataFieldName}">
    ...
</div>

现在,如果该 k-group-indicator div 可以包含不同值的列表,data-field每个键的关联数据是相应部分的展开/折叠状态,则可以在制作之前将该列表保存到缓冲区中调用 dataSource.data(someNewData) 方法,然后在监听 dataBound 事件的事件处理程序中,可以重新应用这些展开状态。要找到分组值的相应分组部分,如果k-grouping-row可以有一个名为的属性group-data-value来保存特定分组部分的分组值,例如“销售”或“市场营销”,如果一个按数据分组 -字段称为部门。

<div class="k-group-indicator" data-field="dept" data-title="Dept" data-dir="asc">
       ...
   <div class="k-group-distinct-values">
     <div group-data-value="Sales" aria-expanded="false" />
     <div group-data-value="Events Planning" aria-expanded="true" />
   </div>  
</div>

然后在k-grouping-row<tr class="k-grouping-row" group-data-value="Sales">

4

5 回答 5

4

可以理解,这不是内置功能。这非常复杂,因为如果您有嵌套的分组,您将必须记住它所在的层次结构中的每个折叠组。由于项目将移入和移出 DataSource,这将是一个痛苦的跟踪。


也就是说,只要您不要变得太复杂,这是一种非常骇人听闻的方式来完成您想要的事情。它只是使用该groupHeaderTemplate属性为每个分组行添加一个 UID。我只是使用列名 + 值作为 UID,如果您进入多个分组,这在技术上是错误的,但对于一个示例来说已经足够了。

从那里,在您刷新之前,您可以从 Kendo 现在拥有的 ARIA 属性中找到折叠的组(旁注,您必须使用 2012 Q3 才能工作)。然后向下钻取并获取模板添加的 UID。

刷新后,您可以找到具有匹配 UID 的行并将它们传递给网格的.collapseGroup()函数以重新折叠它。

这是一个有效的 jsFiddle 演示了这一点。

以及来自 jsFiddle 复制/粘贴的代码(请注意,我仅在 City 列上设置模板,因此在此示例中只有 City 列将保留分组折叠!)

HTML:

<button id="refresh">Refresh</button>
<div id="grid" style="height: 380px"></div>

JavaScript:

var _getCollapsedUids = function () {
    var collapsedUids = [];
    $("#grid .k-grouping-row span[data-uid]")
        .each(function(idx, item) {
            if($(item)
               .closest(".k-grouping-row")
               .children("td:first")
               .attr("aria-expanded") === "false") {
                collapsedUids.push($(item).data("uid"));
            }
        }
    );
    return collapsedUids;
};

var _collapseUids = function (grid, collapsedUids) {
    $("#grid .k-grouping-row span[data-uid]")
        .each(function(idx, item) {
            if($.inArray($(item).data("uid"), collapsedUids) >= 0) {
                console.log("collapse: " + $(item).data("uid"))
                grid.collapseGroup($(item).closest("tr"));
            }
        }
    );
};

var refresh = function () {
    var collapsedUids = _getCollapsedUids();
    var grid = $("#grid").data().kendoGrid;
    grid.dataSource.data(createRandomData(50));
    _collapseUids(grid, collapsedUids);
};

$("#refresh").click(refresh);

$("#grid").kendoGrid({
    dataSource: {
        data: createRandomData(50),
        pageSize: 10
    },
    groupable: true,
    sortable: true,
    pageable: {
        refresh: true,
        pageSizes: true
    },
    columns: [ {
            field: "FirstName",
            width: 90,
            title: "First Name"
        } , {
            field: "LastName",
            width: 90,
            title: "Last Name"
        } , {
            width: 100,
            field: "City",
            groupHeaderTemplate: '<span data-uid="City-#=value#">#= value #</span>'
        } , {
            field: "Title"
        } , {
            field: "BirthDate",
            title: "Birth Date",
            template: '#= kendo.toString(BirthDate,"dd MMMM yyyy") #'
        } , {
            width: 50,
            field: "Age"
        }
    ]
});

就个人而言,我根本不喜欢这个解决方案。这太 hacky 并且太多 DOM 遍历。但是,如果不重新实现网格小部件,我想不出更好的方法来做到这一点。也许它对于你想要完成的事情或者给你一个更好的想法来说已经足够好了。


最后一点;我检查了 Kendo UI 源代码,它似乎没有跟踪哪些分组被展开/折叠。他们做的事情类似于我对 aria 属性所做的事情,而是检查驱动图标状态的类:

            if(element.hasClass('k-i-collapse')) {
                that.collapseGroup(group);
            } else {
                that.expandGroup(group);
            }

如果您没有使用 Kendo 2012 Q3 并且无法使用 aria-expanded 属性,则可以更改代码以检查图标类。

于 2012-12-21T03:15:06.783 回答
2

我已经启动了一个健壮的组状态保存网格扩展,该扩展旨在与 Kendo Grid 和 ASP.Net RadGrid(利用通用功能的特定于控件的实现)一起使用。

此扩展对Telerik 的组状态保存示例进行了重大改进,并增强了 RadGrid,没有其他可用的功能甚至可以与 Kendo UI 示例相提并论。您可以在此处查看改进列表,也可以在此处查看代码。

我想知道你的想法。

于 2015-05-08T10:54:56.147 回答
1

“回答”我自己的问题只是为了让答案编辑器中的代码格式更易读。这是讨论的延伸。

我同意嵌套分组更复杂。如果每个k-grouping-row都有一个属性,其中包含分组所基于的不同数据值数组的 JSON 表示,那么开发人员就有可能从每个折叠的 k 分组行中提取不同的数据值组合。(如果 k-grouping-row 直接指示它是展开还是折叠,但可以从它包含的单元格中获取该信息,这会有所帮助,对吧?)

有了这组折叠组的不同值,人们可以构建自己的折叠组映射。不同的数据值可以作为该映射中对象的键;每个不同的数据组合都是唯一的,并且仅与网格中的一个分组部分相关联,无论涉及多少嵌套级别。

例如,对于两层嵌套by Department by ProductType,我们会看到如下内容:

<tr class="k-grouping-row" data-distinct-values="['Sales','Toys, Games and Videos']">. 

Department 值为“Sales”,ProductType 值为“Toys, Games and Videos”。JSON 处理数据值中的逗号。

对于三层分组,state, city, zipcode我们将有:

   ...  data-distinct-values="['California','Beverly Hills','90210']"

这些数据值在创建组时是已知的,因此可以将它们作为唯一句柄注入到 k-grouping-row 中。

k-grouping-row尽管 distinct-values 是一个唯一的句柄,但它们并没有消除遍历 DOM 的需要,当人们想要重新应用折叠状态时访问每一个。然而剑道网格在默认情况下不必执行崩溃状态的恢复,如果认为这是一项过于昂贵的操作。但是您将为开发人员提供一种使用 来完成它的简单方法data-distinct-values=[...],并且开发人员可以自行决定性能下降(如果有的话)是否符合应用程序的要求。

于 2012-12-21T14:11:16.833 回答
1

开箱即用不支持此功能,但可以通过维护扩展组(或折叠集群)的数组来实现。

在高级别 - 您使用标记来查找组是折叠还是展开。然后维护一个扩展的组列表,并且仅在刷新网格时才扩展这些组。

在我的例子中,我使用默认的剑道图标,扩展组 (.ki-collapse) 与折叠组 (.ki-expand) 不同。

var expandedGroups = [];

我可以在全球范围内使用扩展组。根据您的需要修改它。然后在保存或丢弃剑道网格的更改时,我调用以下方法,即 - 在您的代码执行触发分组状态丢失的 grid.refresh() 或grid.dataSource.read() 之前调用它。

    function updateExpandedGroupsList() {
    expandedGroups = []; // reset state

    // find the list of group labels adjacent to expanded group icons
    var listOfExpandedGroupsLabels = $("#gridId .k-icon.k-i-collapse~span");
    for (i = 0; i < listOfExpandedGroupsLabels .length; i++) {
        expandedGroups.push(listOfExpandedGroupsLabels [i].innerHTML);
    }
  }

所以我在上述方法中所做的是找到所有指向下方的小扩展箭头的实例,然后找到具有组名称的兄弟跨度,我们需要将其存储在扩展组数组中以供以后使用.

现在我们有了它,您将执行重置网格的操作,并且可能会触发 dataBound 或其他事件。在那段代码中,你有一些东西(比如说)默认折叠所有组。在那里,您需要执行相反的过程:从迭代组控件中查找跨度和组名,并检查它是否在扩展组列表中。如果是,则不要折叠它(或展开它)。

    collapseGroups(expandedGroups);

调用折叠组并传递数组后:

  // method collapse groups, excluded groups will not be touched
    function collapseGroups(listOfExcludedGroups) {
    var grid = $("#gridId").data("kendoGrid");   
    if (!listOfExcludedGroups) {
        listOfExcludedGroups = [];
    }
        $(".k-grouping-row").each(function () {            
            var groupName = $(this).find("span")[0].innerHTML;
            if (groupName && listOfExcludedGroups.indexOf(groupName) > -1) {
                return; // continue
            }
            grid.collapseGroup(this);
        });   
    }
于 2019-12-17T20:59:12.893 回答
0

首先,您很少需要从代码中调用 refresh。网格(以及所有数据绑定的 Kendo 小部件)正在侦听数据源的更改,并将相应地刷新。

按照设计,不会保留组的展开/折叠状态。更改数据源将导致所有组扩展(这是它们的默认状态)。

于 2012-12-20T08:13:11.430 回答