javascript - knockout 组列表为带有对象的更小列表

标签 javascript .net asp.net-mvc knockout.js knockout-mapping-plugin

我有多名员工的每日数据,根据开始时间和结束时间,这可能意味着大量数据。

因此,通过映射插件,我将它们映射到一个大列表中,但我需要将它们按员工分组到更小的列表中,这样我就可以为每个员工创建一个表(如更小的 View 模型),该表具有针对该子集的过滤和排序数据。

这是我用静态数据创建的一个基本示例。

$(function () {
    var data = {
        Employees: [{
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 2,
            Name: "Employee2",
            Day: new Date(),
            Price: 112.54
        }, {
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 3,
            Name: "Employee3",
            Day: new Date(),
            Price: 12.54
        }]
    };

    // simulate the model to json conversion. from now on i work with the json
    var jsonModel = JSON.stringify(data);

    function employeeModel(data) {
        var employeeMapping = {
            'copy': ["Id", "Name", "Day", "Price"]
        };
        ko.mapping.fromJS(data, employeeMapping, this);
    }

    function employeeViewModel(data) {
        var self = this;
        var employeesMapping = {
            'Employees': {
                create: function (options) {
                    return new employeeModel(options.data);
                }
            }
        };
        ko.mapping.fromJSON(data, employeesMapping, self);
    }

    var productsModel = new employeeViewModel(jsonModel);
    ko.applyBindings(productsModel);
});
table {
    border-collapse: collapse;    
}
table, th, td {
    border: 1px solid black;
}
tr:nth-child(even) {
    background-color: white;
}
tr:nth-child(odd) {
    background-color: #C1C0C0;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<table>
  <tbody data-bind="foreach: Employees">
    <tr>
      <td><span data-bind="text:Id"></span>
      </td>
      <td><span data-bind="text:Name"></span>
      </td>
      <td><span data-bind="text:Day"></span>
      </td>
      <td><span data-bind="text:Price"></span>
      </td>
    </tr>
  </tbody>
</table>

最佳答案

一种可能性是使用计算值对数据进行分组。

self.EmployeeGroups = ko.pureComputed(function () {
    var employees = self.Employees(),
        index = {},
        group = [];

    ko.utils.arrayForEach(employees, function(empl) {
        var id = ko.unwrap(empl.Id);
        if ( !index.hasOwnProperty(id) ) {
            index[id] = {
                grouping: {
                    Id: empl.Id,
                    Name: empl.Name
                },
                items: []
            };
            group.push(index[id]);
        }
        index[id].items.push(empl);
    });

    return group;
});

会将您的数据从平面数组转换为:

[{
    grouping: {
        Id: /* ... */, 
        Name: /* ... */
    }
    items: [/* references to all employee objects in this group */]
}, {
    /* same */
}]

Expand the code snippet below to see it at work.

$(function () {
    var data = {
        Employees: [{
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 2,
            Name: "Employee2",
            Day: new Date(),
            Price: 112.54
        }, {
            Id: 1,
            Name: "Employee1",
            Day: new Date(),
            Price: 12.54
        }, {
            Id: 3,
            Name: "Employee3",
            Day: new Date(),
            Price: 12.54
        }]
    };

    var jsonModel = JSON.stringify(data);

    function employeeModel(data) {
        var employeeMapping = {
            'copy': ["Id", "Name", "Day", "Price"]
        };
        ko.mapping.fromJS(data, employeeMapping, this);
    }

    function employeeViewModel(data) {
        var self = this;

        self.Employees = ko.observableArray();
        self.EmployeeGroups = ko.pureComputed(function () {
            var employees = self.Employees(),
                index = {},
                group = [];

            ko.utils.arrayForEach(employees, function(empl) {
                var id = ko.unwrap(empl.Id);
                if ( !index.hasOwnProperty(id) ) {
                    index[id] = {
                        grouping: {
                            Id: empl.Id,
                            Name: empl.Name
                        },
                        items: []
                    };
                    group.push(index[id]);
                }
                index[id].items.push(empl);
            });

            return group;
        });

        // init
        var employeesMapping = {
            'Employees': {
                create: function (options) {
                    return new employeeModel(options.data);
                }
            }
        };
        ko.mapping.fromJSON(data, employeesMapping, self);
    }

    var productsModel = new employeeViewModel(jsonModel);
    ko.applyBindings(productsModel);
});
table {
    border-collapse: collapse;    
}
table, th, td {
    border: 1px solid black;
}
tr:nth-child(even) {
    background-color: #efefef;
}
tr:nth-child(odd) {
    background-color: #CCCCCC;
}
tr.subhead {
    background-color: #D6E3FF;
    font-weight: bold;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<table>
  <!-- ko foreach: EmployeeGroups -->
  <tbody>
    <!-- ko with: grouping -->
    <tr class="subhead">
      <td colspan="2">
        <span data-bind="text: Id"></span>
        <span data-bind="text: Name"></span>
      </td>
    </tr>
    <!-- /ko -->
    <!-- ko foreach: items -->
    <tr>
      <td><span data-bind="text: Day"></span></td>
      <td><span data-bind="text: Price"></span></td>
    </tr>
    <!-- /ko -->
  </tbody>
  <!-- /ko -->
</table>

<pre data-bind="text: ko.toJSON($root, null, 2)" style="font-size: smallest;"></pre>

关于javascript - knockout 组列表为带有对象的更小列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28363596/

相关文章:

c# - 这两个使用 foreach 的 IEnumerable<T> 代码之间会有性能差异吗?

c# - 使用 .net MVC 为什么我的列表不能在帖子中保留下来?

javascript - MVC 上的成功/失败消息

javascript - ASP MVC Controller 发布具有不同值的相同 html 输入名称

.net - 如何在 .Net 上处理不同的屏幕分辨率

javascript - 如何将 id 传递给函数?

c# - 在 C# 中将字符串存储为 UTF8

c# - 使外键(字符串字段)可为空

javascript - 如何在 React JS 中的另一个 axios get 中使用 axios 响应?

javascript - 如何正确转义 css/js 属性选择器 [attr=value] 中的属性值?