What's the difference between ember helpers, components and views?

I’ve been struggling a bit with these 3 elements since as far as I can tell they all serve the same purpose (making reusable view elements in our apps) however I’m not sure when to use one of the other, let’s say I want to create a button that changes it’s text to something else after being clicked on, I think any of the 3 options are right in this case or am I understanding how they work wrong?

PD: I could have included partials as an option too but it’s been a while since I hear of it were they deprecated?

5 Likes

This is what I’ve learned so far.

A partial is just a way to move a snippet of handlebars into another template. (Depending on whether/how you precompile your templates, this may mean a separate file.) It’s like #include in C. It’s literally the same as if you had copied and pasted your handlebars template. Partials, afaik, are not deprecated. They have their place; they’re just not a real abstraction.

Helpers are great when you find common patterns in your handlebars templates, or when you need a purely functional transformation of a value. When I say purely functional, I mean (1) no state, (2) no side-effects, and (3) only depends on the input parameters (and maybe context/controller). Pluralizing is the canonical example of this. Truncating and creating special links (with custom versions of linkTo) are other examples. Because handlebars helpers support blocks, these can be more sophisticated, creating conditionals or looping constructs. But I think the key question is, is it a pattern in my template? If the answer is yes, then a helper may be the right abstraction.

On the other hand, views are required whenever you have anything impure. If the thing you’re trying to abstract has its own state, has any side-effects, depends on global state, or has any kind of user interaction or DOM event handling, then a view may be what you’re looking for. Helpers are not designed for most (if not all) of these things. In general, you have models that are persisted, and you have application state that’s stored on controllers. But sometimes you need state that’s specific to the widget itself, and this should be kept out of the controller. In general, dependencies go like this V → C → M, i.e. views can depend on controllers, and controllers can depend on models, but not the other way around. For example, if you have a widget that has some kind of active or hover state that doesn’t affect anything besides how the widget appears, it will probably make more sense to keep that state on the view. The controller should be oblivious to it (if it’s possible). It should still work, for example, if you have multiple instances of the view in the same context (i.e. using the same controller).

I think the decision to go with a view versus a component is the only real judgment call. In many cases, I could see this going either way and it’s more about taste or what you consider to be the border between your application and a library component. The differences between views and components are more subtle. You instantiate a view in your template like {{view App.MyViewName}} but you instantiate a component like {{my-component-name}}. This may matter. If you’re planning on reusing your abstraction between apps, a component is probably the way to go since the class name is abstracted away. There are also differences with how actions within components work. If you find yourself typing {{action 'myAction' target=view bubbles=false}} a lot, that is a smell that may indicate you should be using a component since actions inside a component go to the component by default (not the controller) and also don’t bubble outside the component.

21 Likes

Thanks a lot for the thorough response it does clear a lot of misconceptions I had about these components, so to see if I understand correctly using my example as reference it’s better to go with either a view or a component since the buttons will have a state (loading) and a side effect (toggling elements, saving models, etc)?

From the little that you’ve mentioned, yes, it sounds like a view or component would be good.

Actually, there is a major difference, between templates and components. Components are views that are completely isolated. They have no access to the surrounding context or outer controller. You have to pass in the content you want it to use.

4 Likes

Thanks for pointing that out @ulisesrmzroche that’s a important aspect to keep in mind

Yehuda and Tom explained the different rendering techniques during one of their training sessions, and here’s a summary:

Views:

Don’t use views unless you’re a framework developer. They’ve made lots of enhancements to Handlebars and introduced Components, so views are no longer necessary. Views are used internally to power things like {{#if}} and {{outlet}}. If you feel you need to use a view, use a component instead.

Components

Completely isolated. All of its dependencies need to be passed in. There is no Controller for a component, and instead, it interacts with Ember.Component objects.

Partial

Partial inherits scope and controller from its parent. The behavior would be the same as just copying and pasting the partial into its parent. Partial is not meant as a reusable widget, it’s a way to split up your template into smaller parts.

Render

Render is a way to render a separate template inside of a template with a different scope and controller. Note: Render may no longer be necessary because of Components.

Helpers @jonnytran does a pretty good job of explaining it above.

9 Likes