在Ember.Route.setupController中访问参数的正确方式是什么?

18

Ember.Route.model可以访问params变量,但Ember.Route.setupController却不能。这对我来说很麻烦,因为我的路径有多个动态片段,我需要在模板中使用它们。

具体来说,我的路径是这样的:/project/:project_id/task/:task_id。请注意,一个任务可以属于多个项目,而不仅仅是一个。因此,我们无法仅仅通过查看任务本身来确定我们正在查看哪个项目:我们必须使用URL中找到的项目ID。以下是我目前的做法:

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);
  }
});

也许我有点多虑,这样做感觉有些取巧。如果该路由应该可以访问参数,那么它应该已经附加了一个params属性。是否有更好的方法?
编辑:我对上面的代码进行了一些更新。此外,我的路由如下:
App.Router.map(function() {
  this.resource('project', { path: '/project/:project_id' });
  this.resource('task', { path: 'project/:project_id/task/:task_id' });
});
2个回答

11

在setupController钩子中,您无法访问这些参数。 模型钩子可以访问params对象,因为它仅在通过URL进入应用程序时调用。

如果您确实知道要以这种方式执行代码,那么您的代码看起来非常不错。对于这段代码,你觉得哪里不对劲吗?当我看这段代码时,我在想为什么您没有将您的路由逻辑分割成一个 ProjectRoute 和一个下属的 TaskRoute。那对您是否有用呢?

更新:响应您的更改

嵌套资源可能是您情况下的关键:

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

由于TaskRoute被嵌套了,所以您需要将其重命名为ProjectTaskRoute:

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

这应该可以让您从路由中删除parentProjectId属性


啊,我之前不知道模型方法只在第一次加载时调用,但这解释了我看到的很多怪异行为。例如,如果我直接打开 /project/1/tasks/2,我的上面的代码就无法工作,因为 model 没有被调用,所以 parentProjectId 属性没有被设置。在这种情况下,我必须在 setupController 中使用 var parentProject = this.modelFor('project')。我确实有一个单独的 ProjectRoute。打开 /project/1 将显示项目的任务。点击任务将打开 /project/1/tasks/1。任务视图需要一个返回到项目的链接,所以我从 URL 中获取项目。 - NudeCanalTroll
现在它能工作了吗?我的想法也是使用this.modelFor("project")。当您通过/project/1/tasks/2进入应用程序时,应首先访问ProjectRoute及其模型钩子。之后,您可以使用modelFor来访问它。如果您使用ember-data对数据进行建模,那么在控制器中设置parentProject似乎有点多余。该属性不应该存在于TaskModel上吗? - mavilein
一个任务可以属于多个项目(将项目视为标签),因此,与其拥有“属于项目”的关联,不如拥有“拥有多个项目”的关联。因此,我无法仅通过查看任务来确定自己在哪个项目中(从而确定后退按钮应链接到哪里)。我必须检查URL。无论如何,我会尝试使用modelFor。我认为我的路由设置不正确,因此访问/project/1/task/2会首先触发TaskRoute。我想我需要将我的任务路由嵌套在我的项目路由内?我会更新我的问题以展示我的路由长什么样子。 - NudeCanalTroll
1
是的,你的路由应该嵌套!那么 ProjectRoute 就会被首先匹配。我会在有时间时评论你的更新。 - mavilein

2
自从Ember 1.8版本以来,Route类有一个paramsFor函数:paramsFor
import Route from '@ember/routing/route';

export default Route.extend({
    setupController(controller) {
        this._super(...arguments);
        const params = this.paramsFor('name.of.your.route')
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接