Kendo UI 具有复杂数据的 TreeListView

Kendo UI TreeListViews with complex data

背景信息

简而言之,我希望实现 "mostly" 这里显示的内容...

http://demos.telerik.com/kendo-ui/treelist/remote-data-binding

...除了它有点令人费解,而且在我的例子中,数据来自多个基本端点 url。

我正在尝试构建一个通用查询构建页面,允许用户选择上下文,然后选择 "type"(或端点),然后从那里在该端点上构建自定义查询。

我已经设法达到我为简单查询执行此操作的地步,但现在我正在尝试处理更复杂的场景,在这些场景中我从相关端点检索 child 或更深层次的数据项.

考虑到这一点...

概念

我有许多端点,但并非所有端点都是 OData,而是主要遵循 OData v4 规则,因此我试图构建一个 "TreeGrid" 基于选择了一个端点,该端点将公开可用于查询的扩展选项。 我所有的端点都有一个名为 GetMetadata() 的自定义函数,它描述了该端点的类型信息,其中端点大部分基本上是一个 REST CRUD<T> 实现,它可能有也可能没有一些进一步的自定义函数处理其他一些业务场景。

因此,给定一个 HTTP get 请求,例如...

~/SomeContext/SomeType/GetMetadata()

...我会得到一个看起来很像 MVC/WebAPI 元数据容器的 object。 object 有一个名为 "Properties" 的 属性,其中一些是标量,一些是复数(如数据中所定义)。

我正在尝试构建一个 TreeListDataSource 或 HierarchicalDataSource object,我可以使用它来绑定到仅复杂属性的 Kendo treeList 控件,动态构建正确的 get url 并根据来自 parent 类型的 属性 信息列出该类型的复杂属性,根端点在页面上的其他控件中定义。

问题

我似乎无法弄清楚如何为 TreeGrid 配置 kendo 数据源 object 以获得所需的输出,我认为可能有两个原因之一...

  1. 根据此处显示的演示,TreeListDataSource object:http://demos.telerik.com/kendo-ui/treelist/local-data-binding 似乎暗示基于层次结构的控件需要平面数据源。
  2. 我不知道如何配置数据源,以便我可以传入 parent 元信息(来自源的数据项)以构建正确的端点 url 获取请求。
function getDatasource(rootEndpoint) {
    return {
        pageSize: 100,
        filter: { logic: 'and', filters: [{ /* TODO:possibly filter properties in here? */ }] },
        type: 'json',
        transport: {
            read: {
                url: function (data) {
                    //TODO: figure out how to set this based on parent
                    var result = my.api.rootUrl + endpoint + "/GetMetadata()";
                    return result;
                },
                dataType: 'json',
                beforeSend: my.api.beforeSend
            }
        },

        schema: {
            model: {
                id: 'Name',
                fields: {
                    Type: { field: 'Type', type: 'string' },
                    Template: { field: 'Template', type: 'string' },
                    DisplayName: { field: 'DisplayName', type: 'string' },
                    ShortDisplayName: { field: 'ShortDisplayName', type: 'string' },
                    Description: { field: 'Description', type: 'string' },
                    ServerType: { field: 'ServerType', type: 'string' }
                }
            }
            parse: function (data) {
                // the object "data" passed in here will be a meta container, a single object that contains a property array.
                $.each(data.Properties, function (idx, item) {
                    item.ParentType = data;
                    item.Parent = ??? where do I get this ???
                });

                return data.Properties;
            }
        }
    };
}

我的一些问题可能归因于元数据本身没有主键这一事实,我想知道使用解析附加生成的 guid 作为键是否是一个想法,但后来我认为 Kendo 在询问 children.

时使用 API 上的问题的 id

所以事实证明 kendo 除了从单个端点提供数据外,没有准备好做任何事情,而我在这里做的事情比那更复杂一点,而且由于数据是"not entity type data",我没有像键和外键这样的常见东西。

考虑到这一点,我选择将问题完全从 kendo 中移开,并通过 "hack that behaves like a normal kendo expand but not really" ...

简单地处理这种情况

在树形网格中,当 kendo 显示可扩展行时,它会在第一个单元格中呈现类似这样的内容 ...

没有扩展数据或没有绑定到服务器的数据源,此单元格不会呈现。

所以我伪造了它并在我的版本中添加了一个额外的 class .not-loaded.

这意味着我可以在单击我的 "fake expand" 时连接一个自定义的 js 块,以构建正确的 url,执行我的自定义操作,伪造/创建一些 id,然后将数据到数据源。

expandList.on('click', '.k-i-expand.not-loaded', function (e) {
    var source = expandList.data("kendoTreeList");
    var cell = $(e.currentTarget).closest('td');
    var selectedItem = source.dataItem($(e.currentTarget).closest('tr'));
    my.type.get(selectedItem.ServerType, ctxList.val(), function (meta) {
        var newData = JSLINQ(meta.Properties)
            .Select(function (i) {
                i.id = selectedItem.id + "/" + i.Name;
                i.parentId = selectedItem.id;
                i.Selected = my.type.ofProperty.isScalar(i);
                i.TemplateSource = buildDefaultTemplateSourceFor(i);
                return i;
            })
            .ToArray();

        for (var i in newData) {
            source.dataSource.add(newData[i]);
        }

        $(e.currentTarget).remove();
        source.expand(selectedItem);
        buildFilterGrid();
        generate();
    });
});

通过这种方式,kendo 得到了它对树视图列表的期望 "a flat set with parent child relationships",而我完成了所有繁重的工作。

我使用了一些 JSLINQ 魔法来让繁重的工作变得更轻松 "c# like"(毕竟我更喜欢 c#),但简而言之,它所做的只是获取扩展并使用的父项作为父项的 id 然后为当前项目生成一个新的 id 作为 parent.id + “/” + current.name,这样一切都是唯一的,因为对象上的 2 个属性不能具有相同的名称,并且两个对象由同一父对象引用时,父对象的前缀 属性 名称使引用唯一。

这不是理想的解决方案,但 telerik 就是这样,在这里破解,那里破解,通常有可能让它工作!

有些事情告诉我有更聪明的方法来做到这一点!