Alex Navasardyan
Alex Navasardyan

Reputation: 536

Ember CollectionView with views that have different templates

Given that I have this code:

Ember.App.View = Ember.View.extend({
    templateName: "templateA"
});
Ember.App.View = Ember.View.extend({
    templateName: "templateB"
});
Ember.App.ViewC = Ember.CollectionView.extend({
    itemViewClass: "Ember.View",
    contentBinding: "SomeController"
});

Is there a way to add views with different templates to CollectionView?

Upvotes: 2

Views: 2788

Answers (3)

Jan Míšek
Jan Míšek

Reputation: 1657

In case you also need mutable view class you can use following tooling:

listview.hbs

 {{each item in list itemViewClass=view.Item}}

listview.js

import Ember from 'ember';
import { mutableView } from 'utils/mutable-view';

export default Ember.View.extend({

  Item: mutableView('content.type', function (type, container) {
    if (type === 'type_a') {
      return container.lookupFactory('view:item-a-view');
    }
    if (type === 'type_b') {
      return container.lookupFactory('view:item-b-view');
    }
  }),
});

and finally the utility method mutableView of mutable-view.js

import Ember from 'ember';

var mutableViewTemplate = Ember.Handlebars.compile('{{view view.DynamicView content=view.content}}');

export var mutableView = function(observes, viewSelector) {
  return Ember.View.extend({

    template: mutableViewTemplate,

    __dynamicViewCache: {},

    DynamicView: Ember.computed(observes, function () {
      var view;
      var cache = this.get('__dynamicViewCache');
      var modificator = this.get(observes);

      view = cache[modificator];
      if (view) {
        return view;
      }

      view = viewSelector(modificator, this.get('container'));
      if (view) {
        cache[modificator] = view;
        return view;
      }

      throw new Error(`Cannot determine view class for '${modificator}' of '${observes} '`);
    })
  });
};

Upvotes: 0

pangratz
pangratz

Reputation: 16163

You can make the templateName of the itemViewClass a computed property, see http://jsfiddle.net/pangratz666/vGHcD/:

App.MyView = Ember.View.extend({
    templateName: function() {
        var templateName = Ember.getPath(this, 'content.label');
        // return default template if there is no such template 
        return (!Ember.TEMPLATES[templateName]) ? 'default' : templateName;
    }.property('content.label').cacheable(),

    // rerender the view if the template name changes
    _templateNameChanged: function() {
        this.rerender();
    }.observes('templateName')
});

App.CollectionView = Ember.CollectionView.extend({
    itemViewClass: 'App.MyView'
});

Also take a look at the related question: Select view template by model type/object value using Ember.js

Upvotes: 6

pangratz
pangratz

Reputation: 16163

Another solution is to use ghempton/ember-layout, see http://jsfiddle.net/pangratz666/XhfYy/:

App.ViewA = Ember.View.extend({
    templateName: "templateA"
});
App.ViewB = Ember.View.extend({
    templateName: "templateB"
});

App.ItemView = Ember.View.extend({
    template: Ember.Handlebars.compile('{{dynamicView content}}')
});

App.CollectionView = Ember.CollectionView.extend({
    itemViewClass: 'App.ItemView'
});

App.controller = Ember.ArrayProxy.create({
    content: [App.ViewA.create(), App.ViewB.create()]
});​

Upvotes: 0

Related Questions