【问题标题】:Knockout group list into smaller lists with objects将列表分组为带有对象的较小列表
【发布时间】:2015-04-06 11:12:27
【问题描述】:

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    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;
    });
    

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

    [{ 分组:{ ID: /* ... */, 姓名: /* ... */ } items: [/* 对该组中所有员工对象的引用 */] }, { /* 相同的 */ }]

    展开下面的代码 sn-p 看看它的工作原理。

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

    【讨论】:

    • 是的,我知道您可以像这样进行分组,但我不确定您是否可以对较小的列表进行排序、过滤和添加其他功能。有什么方法可以在淘汰赛中使用此代码来做到这一点?
    • 当然你可以在淘汰赛中做到这一点。如果你想要一个过滤组,只需添加另一个过滤组的计算值。
    • 但据我了解,该组是计算出来的,而您在内存中没有分组吗?因此,如果您想对特定组进行排序,则必须再次对其进行分组,然后对特定组进行排序?
    • Knockout 计算缓存它们的值。除非有必要,否则它们不会重新计算(因为它们依赖于变化的可观察对象之一)。因此,您可以 - 例如 - 进行计算,输出 EmployeeGroup 视图模型数组(而不是像我一样的普通对象数组)。然后,这些视图模型中的每一个都可以有自己的计算来控制它们各自的data 是如何排序或过滤的。
    • plnkr.co/edit/vKHq0ZXkEvj8ocFZzrCj 我已将您的代码用作我的问题的基础,但我无法使排序适用于较小的数据子集。我在排序部分做错了什么?
    猜你喜欢
    • 1970-01-01
    • 2011-02-11
    • 2012-07-12
    • 2012-11-04
    • 2010-10-19
    • 1970-01-01
    • 2010-12-11
    • 2020-05-05
    • 1970-01-01
    相关资源
    最近更新 更多