What's the proper way to access parameters from within Ember.Route. setupController?

NudeCanalTroll picture NudeCanalTroll · Mar 19, 2013 · Viewed 16.9k times · Source

Ember.Route.model has access to the params variable, but Ember.Route.setupController does not. This is troublesome for me, because my path has multiple dynamic segments, and I need to use all of them in my template.

Specifically, my path looks like this: /project/:project_id/task/:task_id. Note that a task can belong to many projects, not just one. Therefore we can't tell what project we're looking at just be looking at the task itself: we have to use the project ID found in the URL. Here's how I'm doing it currently:

App.TaskRoute = Ember.Route.extend({

  // This works just fine:
  serialize: function(model) {
    return {
      task_id: model.get('id'),
      project_id: this.modelFor('project').get('id')
    };
  },

  model: function(params) {
    this.set('parentProjectId', params.project_id);

    return App.Task.find(params.task_id);
  },

  setupController: function(controller, model) {
    var parentProject = this.modelFor('project') ?
                        this.modelFor('project') :
                        App.Project.find(this.get('parentProjectId'));
    controller.set('parentProject', parentProject);

    controller.set('content', model);
  }
});

Maybe I'm being paranoid, this just feels hacky. If the route was meant to have access to the parameters, then it would already have a params property attached to it. Is there a better way?

EDIT: I made some update to the code above. Also, my routes look like this:

App.Router.map(function() {
  this.resource('project', { path: '/project/:project_id' });
  this.resource('task', { path: 'project/:project_id/task/:task_id' });
});

Answer

mavilein picture mavilein · Mar 19, 2013

You have no access to these params in the setupController hook. The model hook has access to a params object, because it is just called, when your app is entered via URL.

Your code looks quite fine, it you really know, that you want to do it this way. What does feel hacky to you about it? When looking at this code, i am asking myself why you did not split the logic of your Route into a ProjectRoute and a subordinated TaskRoute. Wouldn't that work for you?

Update: Response to your changes

Nesting resources is likely the key to success in your case:

App.Router.map(function() {
  this.resource('project', { path: '/project/:project_id' }, function(){
    this.resource('task', { path: '/task/:task_id' });
  });
});

Since the TaskRoute is nested not you have to rename it to ProjectTaskRoute:

App.ProjectTaskRoute = Ember.Route.extend({
...
});

This should enable you to remove the parentProjectId property from the Route.