In the past year, I’ve spent a lot of time developing a large, complex single-page app using Ember.js. One of the challenges when dealing with a complex SPA is organizing the many views and components within the app, especially when dealing with naturally “typed” data.

In this situation we often found we wanted a different view or component based on the type of the data being presented. The advantage to this is it keeps our templates, controllers, and components from growing out of control.

In this post I’ll describe how my team solved the problem of dynamically binding different components based on typed data and also describe a great new helper that is coming in Ember.js 1.11, {{component}} .

The Problem

The problem we wanted to solve was how to dynamically render a different component based on some bound property. In our app, we had a data model that represented arbitrary operations. Each operation had a “type” property.

We needed components that would let users configure specific options on the operation, but each type warranted a different component, with different UI elements. For instance, when type was typea we might have two numerical inputs in our component, but when it was typeb there was a select and a custom graph.

All told, we have over 15 types. Including all these in one gigantic chain of if blocks in one template file was ugly and not very D.R.Y. We needed something better.

Option A: the {{dynamic-component}} Helper

One nice option that was, unfortunately, not available to us is the {{dynamic-helper}} component. This is a third-party library that lets you add a component based on some computed property:

{{dynamic-component type=typeWidget}}

While the controller has a typeWidget property:



export default Ember.Controller.extend({

typeWidget: function() {

return this.get('type').lowercase() + "-widget";

}.property('model.type')

})



Using this helper, when model.type is typea , a typea-widget (a component) will be rendered. Similarly, when model.type is typeb , a typeb-widget will be rendered. Unfortunately, not all projects use ember-cli, so it would be nice to have other options available. (It’s also being deprecated; more on that later!)

Option B: Cheat Using {{partial}}

Another trick to use is the {{partial}} helper. Partial lets you slap in any template you want—just pass it the name of the template, and it will use the current model, view, and controller. The approach here is to bind the name of the partial to the computed property, then (in each partial file) call the actual component you want to render:

{{partial typePartial}}

And the controller looks like:



export default Ember.Controller.extend({

typePartial: function() {

return this.get('type').lowercase() + "-partial";

}.property('model.type')

})



Finally, the partial template (e.g., typea-partial.hbs , etc.):

{{component typea-widget model=model}}

This approach works, but there is the added complexity of the partial files. However, it does have the advantage of avoiding a big chain of if blocks in the the calling template. When new types come into the system, the developer needs to add the template for the partial, the template for the component, and then (optionally) the javascript for the component.

Option C: In Ember 1.11+, use {{component}}!

The reason {{dynamic-component}} has been deprecated is, as of Ember 1.11, a {{component}} helper has been made available. It works similarly to {{dynamic-component}} :

{{component typeWidget model=model}}

While the controller has a typeWidget property:



export default Ember.Controller.extend({

typeWidget: function() {

return this.get('type').lowercase() + "-widget";

}.property('model.type')

})



The above code will render the typea-widget , typeb-widget , etc. and pass along any other bindings as you would do with a normal component. The component will change dynamically as the computed property changes.