Best practices for handling actions

Since Ember 1.0, actions triggered by the {{action}} helper can either be handled on the controller, or on the route(s), via an actions hash.

I’m curious what factors in to the decision about handling an action on the controller or to do it on the route.

Can we apply the “skinny controller - fat model” (here: fat route) strategy seen in servers-side frameworks, here, too? Would not the route do too much if it also handled events?

My general perception is that since routes play such a central role in Ember apps, it is better to have event-handling there, too. However, I’m pretty certain the picture is more nuanced and thus would like to hear how you guys do this.

Thank you.

3 Likes

I’d put the action in the controller only if it’s directly manipulating the data/state of that controller (like sorting or filtering). Otherwise, if the action affects the state of the whole application (for example opening a modal) it should be in the route.

2 Likes

I think this link may be helpful regarding putting action in “routes” http://madhatted.com/2013/8/31/emberfest-presentation-complex-architectures-in-ember

@allen2hsu In fact, that was the very presentation that set me thinking. One of its takeaways is that you should not have fat controllers and that probably includes not handling events there.

@quadule This makes sense, thank you.

Place actions depending on what kind of portability they require.

  • Do you use this controller/template combination multiple times? Often, actions fired from templates drawn with render are candidates for being handled on the controller.
  • Will this action possibly behave differently depending on the state of your app (as embodied in the current route)? If so the route is the obvious choice.
  • Allowing an action handler to force needs of another controller is a sign the action should likely be on the route.
  • If you have an action on the route but it must update several properties on the controller, consider having the route call a function on the controller (for example controller.startWorking()) instead of leaking knowledge of those properties to the route.

I often default actions to the route, especially for controllers that are tied to templates rendered by the default renderTemplate behavior. These are all just guidelines though, and you can bend the rules. Just think about the reason you are bending the rule before you do!

1 Like

Thank you, @mixonic. Defaulting to the route is my current course of action, too, but now I have some guidelines.

I personally avoid transitioning to routes in controller actions, and setting controller/model state in route actions. Sometimes this means an action is handled in two places, controller & route. In the case where the source of the action is a natural descendant of the controller the percolation is upward. In the case where the source of the action is not a descendant the action is handled first by the route that is a parent of both, and that route sends the action on to the relevant controller, rather than setting properties directly. In this way routes don’t need to know the internals of controllers, and controllers are (somewhat) robust to changes in the routing architecture.

1 Like

@lastobelus Really nice example of a separation of concerns. In the case where the percolation is upward, do you just call super in the controller’s event handler as below?

App.SongsController = Ember.ArrayController.extend({
  ...
  actions: function() {
    // handle event: set controller properties
    this.super();
  }
});

@balint you simply return true . See the “Bubbling” section in Route - 4.6 - Ember API Documentation. _super references the superclass’s action.

1 Like

Any thoughts on when to use view actions?

@moger777 I would suggest handling the action on the view only if the action’s effects are internal to the view (e.g setting a property that redraws parts of the view).