Knockout.js KnockoutJS ObservableArray数据分组

Knockout.js KnockoutJS ObservableArray数据分组,knockout.js,Knockout.js,KnockoutJS是否有一个功能,而我可以采取如下措施: var myArray = ko.observableArray([ { name: "Jimmy", type: "Friend" }, { name: "George", type: "Friend" }, { name: "Zippy", type: "Enemy" } ]); 然后在“类型”字段中选择distinct,生成如下结果: (pseudo code) var

KnockoutJS是否有一个功能,而我可以采取如下措施:

    var myArray = ko.observableArray([
      { name: "Jimmy", type: "Friend" },
      { name: "George", type: "Friend" },
      { name: "Zippy", type: "Enemy" }
    ]);
然后在“类型”字段中选择distinct,生成如下结果:

(pseudo code)
    var distinct = myArray.distinct('type')
      // Returns array of two arrays
      //  distinct[0] is an array of type=Friend
      //  distinct[1] is an array of type=Enemy 

我知道ko.utils.arrayGetDistinctValue,但这并不是我想要的。我也知道我可以使用ko.utils.ArrayGetDistincTvalue编写一些循环来获得我想要的,我只是想知道在KnockoutJS中是否还有其他我忽略的东西。

ko中没有任何其他东西可以让这更容易

有很多方法可以让这一切顺利进行。例如,您可以扩展ObservalArrays,使其具有一个
distinct
函数。然后,您可以创建您的observableArray,如下所示:

this.people = ko.observableArray([
       new Person("Jimmy", "Friend"),
       new Person("George", "Friend"),
       new Person("Zippy", "Enemy")
]).distinct('type');
distinct
函数可能如下所示:

ko.observableArray.fn.distinct = function(prop) {
    var target = this;
    target.index = {};
    target.index[prop] = ko.observable({});    

    ko.computed(function() {
        //rebuild index
        var propIndex = {};

        ko.utils.arrayForEach(target(), function(item) {
            var key = ko.utils.unwrapObservable(item[prop]);
            if (key) {
                propIndex[key] = propIndex[key] || [];
                propIndex[key].push(item);            
            }
        });   

        target.index[prop](propIndex);
    });

    return target;
};    
它支持链接,因此您可以使用不同的属性多次调用
distinct

此处示例:


这确实会在每次更改时重建一次索引,因此如果您有一个庞大的项目列表,那么您可能会希望探索其他方法(手动订阅)来添加/删除“索引”数组中的项目。

只想添加一点,即如果您两次调用此
.distinct()
方法(例如,可能从计算的可观测值),您将得到名为tweep-rinse和repeat的索引和相关的计算函数,您将面临性能问题

要解决此问题,请在函数顶部附近添加以下行:

if (target.index && target.index[prop]) return target; //Group by already set up, bail out.

我已经在JSFIDLE中简化了RP Niemeyer的版本,以便在不使用distinct函数的情况下执行相同的操作。请参阅:


谢谢尼迈耶

回答得很好。你能举一个例子来说明如何链接它(将一组可观察数组分组)?这是一个很好的例子。谢谢你Ryan Niemeyer。关于链接。它不想开箱即用。我不得不调整它
<ul data-bind="foreach: choices">
<li>
    <h2 data-bind="text: $data"></h2>
    <ul data-bind="foreach: $root.people">
        <!-- ko if: $parent === type() -->
        <li data-bind="text: name"></li>
        <!-- /ko -->
    </ul>
    <hr/>
</li>
var Person = function(name, type) {
   this.name = ko.observable(name);
   this.type = ko.observable(type);    
}

var ViewModel = function() {
    var self = this; 
    this.choices = ["Friend", "Enemy", "Other" ];
    this.people = ko.observableArray([
           new Person("Jimmy", "Friend"),
           new Person("George", "Friend"),
           new Person("Zippy", "Enemy")
    ]);

    this.addPerson = function() {
        self.people.push(new Person("new", "Other"));
    };

    this.removePerson = function(person) {
      self.people.remove(person);  
    };
};


ko.applyBindings(new ViewModel());