Fat routers, skinny controllers; skinny routers, fat controllers?


#1

What are best practices regarding code structure? Should most of your code go into the router? The controller? What would be the best division of responsibilities between the two?


#2

The way I think of it, the routers sets what data is displayed, the view manages how it is displayed, and the controller is responsible for anything in between. For example, a {{view}} cannot sort data, as best I know. A router probably should not sort data. Therefore, it’s a controller’s job to sort or filter data.


#3

I think I should supply some context for this question.

We are writing code to handle network and server errors associated with Ember Data objects. Especially for network errors, such as when internet connectivity is lost when trying to save objects, the code become quite complex.

So where should error-handling go? Is it better handled in the router or the controller?


#4

I think the controller is responsible for performing functions on the current dataset, which is configured by the router and presented by the view.

For instance if you had an app that tracked your favorite internet memes, the router would load the list of memes from a datastore, the view would create the html that actually displays the memes, and the controller would be responsible for things like “favorite-ing” or “star-ing” a meme, or for updating the order of the list.

Is this how y’all would approach the separation of concerns in such an application?


#5

I have a “sortedEmployees” type attribute on my Model. Do you think that’s a decent place for it to be, or should it also go on a controller?

The upside to this is I can simply call this in my model to retrieve the sorted version of “employees”.

{{#each employer.sortedEmployees }}

#6

This is the exact approach I’m following in my current application and am pretty happy with it. The only difference is that in my application the router is also responsible for adding/removing items from the list.


#7

Yes, that’s how we do it, too. But, we distinguish between view-controllers and model-controllers (View-controllers load model-controllers via the “needs” property). Our model-controllers own their data fetching mechanisms and the route only selects the mechanism it wants to use, like this:

App.GamesController = App.ResourceController.extend(
  #...
  loadPastGames: ->
    @setLoading true
    @findPastGames().then => @setLoading false
  
  loadAllGames: ->
    @setLoading true
    @findAll().then => @setLoading false

App.GamesNewRoute = App.AuthenticationFilter.extend(
  #...
  setupController: (controller, model) ->
    controller.startCreateGame()
    # needs tweaking so this can never be executed more than once:
    @controllerFor('games').loadPastGames() 

We’re not yet sure how this scales for a big app, though.

A “view-controller” then only receives the content from the model-controller it requires - if at all, very often the view can bind directly to the model-controller via e.g. {{ #each game in controllers.games }}.