简体   繁体   中英

Ember.js: Group a model (using ArrayProxy)

I have an array whose items I want to group, and then display in this grouped fashion. It's all terribly confusing:

App.GroupedThings = Ember.ArrayProxy.extend({
  init: function(modelToStartWith) {
    this.set('content', Ember.A());        
    this.itemsByGroup = {};  

    modelToStartWith.addArrayObserver(this, {      
      willChange: function(array, offset, removeCount, addCount) {},
      didChange: function(array, offset, removeCount, addCount) {
        if (addCount > 0)
          // Sort the newly added items into groups
          this.add(array.slice(offset, offset + addCount))
      }
    });
  },

  add : function(things) {
    var this$ = this;

    // Group all passed things by day    
    things.forEach(function(thing) {
      var groupKey = thing.get('date').clone().hours(0).minutes(0).seconds(0);

      // Create data structure for new groups
      if (!this$.itemsByGroup[groupKey]) {
        var newArray = Ember.A();
        this$.itemsByGroup[groupKey] = newArray;
        this$.get('content').pushObject({'date': groupKey, 'items': newArray});
      }

      // Add to correct group
      this$.itemsByGroup[groupKey].pushObject(thing);
    });
  }
});


App.ThingsRoute = Ember.Route.extend({
  model: function() {
    return new App.GroupedThings(this.store.find('thing'));
  },
});

This only works if I use the following template:

{{#each model.content }}

These don't render anything (an ArrayController is used):

{{#each model }}
{{#each content }}
{{#each}}

Why? Shouldn't the ArrayController proxy to "model" (which is GroupedThings), which should proxy to "content"?

The reason this becomes a problem is that I then want to sort these groups, and as soon as I change the entire contents array (even using ArrayProxy.replaceContent()), the whole views rebuilt, even if only a single item is added to a single group.

Is there a different approach to this entirely?

I've tended to use ArrayProxies slightly differently when doing such things. I'd probably get Ember to do all the heavy lifting, and for sorting get it to create ArrayProxies based around a content collection, that way you can sort them automatically:

(note I haven't run this code, but it should push you off in the right direction)

App.GroupedThings = Em.ArrayProxy.extend({
  groupKey: null,
  sortKey: null,
  groupedContent: function() {
    var content = this.get('content');
    var groupKey = this.get('groupKey');
    var sortKey = this.get('sortKey');
    var groupedArrayProxies = content.reduce(function(previousValue, item) {
      // previousValue is the reduced value - ie the 'memo' or 'sum' if you will
      var itemGroupKeyValue = item.get('groupKey');
      currentArrayProxyForGroupKeyValue = previousValue.get(itemGroupKeyValue);
      // if there is no Array Proxy set up for this item's groupKey value, create one
      if(Em.isEmpty(currentArrayProxyForGroupKeyValue)) {
        var newArrayProxy = Em.ArrayProxy.createWithMixins(Em.SortableMixin, {sortProperties: [sortKey], content: Em.A()});
        previousValue.set(itemGroupKeyValue, newArrayProxy);
        currentArrayProxyForGroupKeyValue = newArrayProxy;
      }
      currentArrayProxyForGroupKeyValue.get('content').addObject(item);
      return previousValue;
    }, Em.Object.create());
    return groupedArrayProxies;
  }.property('content', 'groupKey', 'sortKey')
);

You'd then Create a GroupedThings instance like this:

var aGroupedThings = App.GroupedThings.create({content: someArrayOfItemsThatYouWantGroupedThatHaveBothSortKeyAndGroupKeyAttributes, sortKey: 'someSortKey', groupKey: 'someGroupKey'});

If you wanted to get the groupedContent, you'd just get your instance and get.('groupedContent'). Easy! :)

...and it'll just stay grouped and sorted (the power of computed properties)... if you want an 'add' convenience method you could add one to the Em.Object.Extend def above, but you can just as easily use the native ones in Em.ArrayProxy, which are better IMHO:

aGroupedThings.addObjects([some, set, of, objects]);

or

aGroupedThings.addObject(aSingleObject);

H2H

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM