敲除 tbody 过滤器父/子

knockout tbody filter parent / childs

我有以下嵌套数据结构 (viewmodel):

projects ( projectid, project_name )
  |--- subprojects ( parent_projectid, subproject_name )

我想将 "subprojects" 过滤为 "parent_projectid",这是来自父项目 ("projectid") 的 ID。 "tbody" 应该自动渲染子项目,例如:

     <tbody >
            <!-- ko foreach: projects -->
            <tr>
                <td data-bind="text: projectid"></td>
                <td data-bind="text: project_name "></td>
                <td class="add" href="#" data-bind="click: addsubproject">Add Subproject</td>
            </tr>

    *** here should the filter applied : ***    
             <!-- ko foreach: subprojects // show only subprojects with "parent_projectid = projectid" -->
                    <tr>
                        <td></td>
                        <td data-bind="text: parent_projectid"></td>
                        <td data-bind="text: subproject_name "></td>
                    </tr>
                    <!-- /ko -->    
            <!-- /ko -->
        </tbody>

我该如何应用它?我不想在 viewmodel 中计算某些东西来获取过滤的子项目,过滤器 "mechanism" 应该只在渲染 tbody 中工作(如果可能的话)

一旦您不再认为您的观点应该是聪明的,这就很容易了。您的视图应该反映您的模型 - 不要强迫它做更多的事情。

如果要显示这个结构:

  • 父级 1
    • 儿童 1.1
    • 儿童 1.2
  • 父 2
    • 儿童 2.1
    • 儿童 2.2

那么这就是你的模型应该是什么样子的。相应地构建它:

// we only really have one type of object in your scenario, let's call it "Project"
function Project(data) {
    this.id = data.id;
    this.name = ko.observable(data.name);
    this.children = ko.observableArray(ko.utils.arrayMap(data.children, function (child) {
        // NB this is recursive
        return new Project(child);
    }));
}

// this will be the main viewmodel
function ProjectTree() {
    var root = new Project({id: 0, name: "root", children: data});
    this.projects = root.children;
}

假设您从服务器检索的 data 是项目对象的平面数组,让我们将它们预处理成树。再次-这是关键部分-如果要显示树形数据,则应该有树形数据。

$.get("projects.json").then(function (data) {
    var index = {}, children = {};
    // index objects by id and by parentid
    data.forEach(function (project) {
        index[project.id] = project;
        if (project.parentid in index) {
            children[project.parentid].push(project);
        } else {
            children[project.parentid] = [project];
        }
    });
    // link up everything into a tree
    Object.keys(index).forEach(function (project) {
        project.children = children[project.id] || [];
    });
    return children[0]; // or whatever the parent ID of top level projects is
}).done(function (data) {
    var vm = new ProjectTree(data);
    ko.applyBindings(vm);
});

现在视图可以是它应该的样子了 - 直截了当:

 <tbody data-bind="foreach: projects">
    <tr>
        <td data-bind="text: id"></td>
        <td data-bind="text: name"></td>
        <td class="add" href="#" data-bind="click: addsubproject">Add Subproject</td>
    </tr>
    <!-- ko foreach: children -->
    <tr>
        <td></td>
        <td data-bind="text: $parent.id"></td>
        <td data-bind="text: name"></td>
    </tr>
    <!-- /ko -->    
</tbody>