Collection of objects of multiple models as the iterable content in a template in Ember.js

前端 未结 2 1190
萌比男神i
萌比男神i 2021-02-11 06:27

I am trying to build a blog application with Ember. I have models for different types of post - article, bookmark, photo. I want to display a stream of the content created by th

2条回答
  •  时光取名叫无心
    2021-02-11 07:02

    You can use a computed property to combine the various arrays and then use Javascript's built in sorting to sort the combined result.

    Combining the arrays and sorting them

    computed property to combine the multiple arrays:

      stream: function() {
        var post = this.get('post'),
            bookmark = this.get('bookmark'),
            photo = this.get('photo');
    
        var stream = [];
    
        stream.pushObjects(post);
        stream.pushObjects(bookmark);
        stream.pushObjects(photo);
        return stream;
      }.property('post.@each', 'bookmark.@each', 'photo.@each'),
    

    example of sorting the resulting computed property containing all items:

      //https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort
      streamSorted: function() {
        var streamCopy = this.get('stream').slice(); // copy so the original doesn't change when sorting
        return streamCopy.sort(function(a,b){
          return a.get('publishtime') - b.get('publishtime');
        });
      }.property('stream.@each.publishtime')
    });
    

    rendering items based on a property or their type

    I know of two ways to do this:

    1. add a boolean property to each object and use a handlebars {{#if}} to check that property and render the correct view
    2. extend Ember.View and use a computed property to switch which template is rendered based on which type of object is being rendered (based on Select view template by model type/object value using Ember.js)

    Method 1

    JS:

    App.Post = Ember.Object.extend({
      isPost: true
    });
    
    App.Bookmark = Ember.Object.extend({
      isBookmark: true
    });
    
    App.Photo = Ember.Object.extend({
      isPhoto: true
    });
    

    template:

      {{#each item in controller.stream}} {{#if item.isPost}}
    • post: {{item.name}} {{item.publishtime}}
    • {{/if}} {{#if item.isBookmark}}
    • bookmark: {{item.name}} {{item.publishtime}}
    • {{/if}} {{#if item.isPhoto}}
    • photo: {{item.name}} {{item.publishtime}}
    • {{/if}} {{/each}}

    Method 2

    JS:

    App.StreamItemView = Ember.View.extend({
      tagName: "li",
      templateName: function() {
        var content = this.get('content');
        if (content instanceof App.Post) {
          return "StreamItemPost";
        } else if (content instanceof App.Bookmark) {
          return "StreamItemBookmark";
        } else if (content instanceof App.Photo) {
          return "StreamItemPhoto";
        }
      }.property(),
    
      _templateChanged: function() {
            this.rerender();
        }.observes('templateName')
    })
    

    template:

      {{#each item in controller.streamSorted}} {{view App.StreamItemView contentBinding=item}} {{/each}}

    JSBin example - the unsorted list is rendered with method 1, and the sorted list is rendered with method 2

提交回复
热议问题