敲除组列表为带有对象的更小列表

Knockout group list into smaller lists with objects

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

因此,我使用映射插件将它们映射到一个大列表中,但我需要将它们按员工分组到更小的列表中,这样我就可以为每个员工制作一个表(比如更小的视图模型),该表具有过滤和排序功能数据子集。

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

$(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 */
}]

展开下面的代码片段以查看它的工作原理。

$(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>