Specify template for component based on property


#1

Let’s say I have the following data:

[
  {
    "type": "video",
    "url": "http://videos.com/2346",
    "title": "Awesome video!",
    "description": "An awesome video",
    "embed_url": "http://videos.com/v/2346.mp4"
  },
  {
    "type": "photo",
    "url": "http://photos.com/2346",
    "title": "Awesome photo!",
    "description": "An awesome photo",
    "embed_url": "http://photo.com/p/2346.jpeg"
  }
]

And I want to display it in the following template:

{{#each item in model}}
    <h1>{{item.title}}</h1>
    {{embedded-object item=item}}
{{/each}}

How can I setup the embedded-object component such that it will display a <video> element if the type property is video, and an <img> element if the type is photo?

One idea I had was to create computed properties on the component:

Ember.Component.extend({
    isVideo: function() {
        return this.get('type') == 'video';
    }.property('type'),
    isPhoto: function() {
        return this.get('type') == 'photo';
    }.property('type'),
    isRich: function() {
        return this.get('type') == 'rich';
    }.property('type'),
    isLink: function() {
        return this.get('type') == 'link';
    }.property('type'),
});

And then in the embedded-object component:

{{#if isVideo}}
  {{embed-video item=item}}
{{/if}}
{{#if isPhoto}}
  {{embed-photo item=item}}
{{/if}}
{{#if isRich}}
  {{embed-rich item=item}}
{{/if}}
 
{{#if isLink}}
  {{embed-link item=item}}
{{/if}}

But this doesn’t feel like it’s the correct thing to do. Any ideas?


#2

It depends how much custom logic you want for each of the individual embedded components, and how you want your html to look. One option if there’s not much logic is to have a switch statement based on the type which returns a template name that you can render with the handlebars partial helper. If you need more custom logic per type you can instead return components from that helper and render them with the handlebars view helper. You can see both options @ http://emberjs.jsbin.com/bacavoka/2/edit.


#3

I’ve done something similar for a view, so I assume a component would work similarly. The trick is to define the templateName property on the view, like this:

SomeView = Ember.View.extend({
  templateName: function(){
    return 'embedded-types/' + this.get('type');
  }.property('type')
}

If the type data are loaded asynchronously (or if the items change type), you may have to add an observer and do something like this in your view/component:

_templateChanged: function(){
  this.rerender();
}.observes('templateName')