Ember 2.0: The new role of Routes, Controllers, and Components

Hello,

New(ish) Ember developer here, just looking for some clarification about where Routes, Controllers, and Components fit in Ember’s long-term vision. I’ve seen tutorials, StackOverflow answers, and blog posts about the roles of these three entities, but nothing geared towards the future (Ember 2.0 and beyond), now that Views are gone and Controllers are on their way out.

Could I just get some clarity about these three entities? Here are some specific questions that I have, as well as some statements that I believe to be true. Please correct me where I’m misguided.

Routes

A Route file/object is basically in charge of the initial code that runs when a new URL is hit. Routes and URLs have a 1:1 correspondence, so every Route describes what should happen when a certain URL/URL format is called, and each URL has up to one Route that describes it.

Currently, the Route is in charge of setting the Template that should be rendered, the Controller that should be used, and the Model to apply (if any).

Actions may be handled by the Route, but only after bubbling up through the Controller and/or Component(s). Usually, the only actions that should be handled by the Route pertain to transitioning to a different Route or switching out the Model. More specific actions should be handled at the Controller or Component level.

Once Controllers are removed from Ember, a Route will specify a routable Component instead of a Controller. Routable Components will more or less function exactly the same as Controllers do now. Instead of the Route defining the Template to render, the routable Component will specify the applicable Template.

Question: is each Route a singleton, or is it reinitialized each time it is activated? That is, if I set a property on the Route while it is active, will that property still exist on the Route the next time it is activated?

Controllers

Controllers will eventually be replaced by routable Components. Therefore, it is wise to avoid relying too much on any functionality possessed by Controllers that is not also a part of the Component behavior.

Right now, when a Route is called, one of its major jobs is to set up the Controller. The Controller is where all of the Route-specific logic should go, such as action handling, view-based properties, etc.

At the same time, it is wise to package functionality into reusable Components as much as possible. This promotes code reuse as well as separation of concerns.

Actions bubble from any Components, up through the Controller, and eventually to the Route. Thus, the Controller gets a chance to handle actions before the Route.

Again, my major question here is whether Controllers are singletons. Do I need to “reset” my controller each time it is called? Or do I get a new instance every time? And if I do need to reset it, to which hook should I bind?

One other question about Controllers: could someone please clarify which actions I should handle in the controller? Is it ever okay to apply a route or model transition from within a Controller, or should this always be handled by the Route?

Components

Components are the new jack-of-all-trades. Each Component has its own template, and is in charge of rendering and managing that template’s data and actions. A Component has its own private scope, and any variables needed for the Component to operate must be passed in when the Component is defined. Components are used all over the place to segment a web page or app into logically separate pieces. Components may also be used by other Components.

In general, it is currently considered good practice to treat data/variables passed into the Component as immutable within the Component, and fire actions instead of directly mutating them. This allows the parent Component/Controller to be in charge of modifying its own data. However, there are quite a few exceptions to this rule, including recommended Components such as emberx-select which binds to a property and mutates that property based on the current value of the select form field.

I assume Components are not singletons, since they are often re-used and sometimes even rendered in multiple places at the same time. There must be some class/instance pattern going on here.

Is it ever okay to transition to a different route from inside a Component? Or is this always something that should be handled by the Route?

Thanks for your time!

3 Likes

Routes and Controllers act as singletons, everything else you wrote sounds right from my experience. (everyone else feel free to correct the hell out of me).

Routable components aren’t arriving for at least a few months (and they said that six months ago), but in the meantime I think you’ve got the approach right. 99% of my controllers are empty autogenerated ones, and in the route’s template I just call a something like {{index-route-component}} and put all the logic in there. Skip the controller and let the route handle the actions you want like transitioning.

The only exception is query params which are still stuck in controllers for quite a while. So if you have query params for a route, you’ll have to explicitly make a controller for handling them.

The other big Ember thing that people are using a lot is Services. They’re singletons that aren’t tied to any route (the Ember Data store’s one) so you can use them to share state that doesn’t get wiped when the URL changes. It also makes actions easier: for big “global” actions, you could it all the way up to the ApplicationRoute (and pass data all the way back down to components). Or… your components could connect to an ExampleService and send data/messages back and forth through that service.

Ember doesn’t have good docs on services, but there are tons of articles about Flux stores for React, and that’s the same architecture idea with a different name.

In bullet point form!

  • Controllers (singletons) - move their logic into components or routes if you have the time, query params are stuck though

  • Routes (singletons) - handle actions and get data, especially for that route; for more general stuff see if you can let a service handle the load

  • Components (not singletons) - talk to routes, and talk to services or use them to send messages to other components

  • Services (singletons) - simple objects that are easy to connect to and awesome for any non-route-specific stuff. Woefully undocumented, so you have to read about Flux stores and pretend they’re talking about Ember.

7 Likes

I just created a simple Flux library for Ember GitHub - ilkkao/ember-cli-emflux: Basic state management library for Ember.js With it, it’s possible to define stores and then expose those stores to components via service. Very close to what you described in the bullet points.

What @2468ben said is spot on. I’m also using controllers/templates as placeholders for components, from where my application’s component tree starts.

Regarding the new role of controllers (and services) in Ember 2.0, I wrote this a few days ago: http://emberigniter.com/should-we-use-controllers-ember-2.0/ In the same vein, it elaborates on ideas described in that comment.

1 Like