KnockoutJS ObservableArray data grouping

后端 未结 3 1364
鱼传尺愫
鱼传尺愫 2020-12-05 08:06

Does KnockoutJS have a feature whereas I could take something like:

    var myArray = ko.observableArray([
      { name: \"Jimmy\", type: \"Friend\" },
              


        
相关标签:
3条回答
  • 2020-12-05 08:40

    There is not anything else built into KO to make this any easier.

    There are many ways that you could make this work. For example, you could extend observableArrays to have a distinct function. Then, you can just create your observableArray like:

    this.people = ko.observableArray([
           new Person("Jimmy", "Friend"),
           new Person("George", "Friend"),
           new Person("Zippy", "Enemy")
    ]).distinct('type');
    

    The distinct function might look like:

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

    It supports chaining so you could call distinct multiple times with different properties.

    Sample here: http://jsfiddle.net/rniemeyer/mXVtN/

    This does rebuild the index once on each change, so if you have a huge list of items, then you would want to potentially explore other ways (manual subscriptions) for adding/removing items from the "index" arrays.

    0 讨论(0)
  • 2020-12-05 08:59

    I have simplified RP Niemeyer's version in jsfiddle to do the same without using the distinct function. Please refer here: jsfiddle

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

    Thanks Niemeyer.

    0 讨论(0)
  • 2020-12-05 09:01

    Just want to add to this that if you call this .distinct() method twice (like maybe from a computed observable), you'll get the indexes and associated computed function called twice - rinse and repeat and you've got a performance problem on your hands.

    To sort this out, add this line near the top of the function:

    if (target.index && target.index[prop]) return target; //Group by already set up, bail out.
    
    0 讨论(0)
提交回复
热议问题