惯用Emberjs用于嵌套路由但非嵌套模板

时间:2013-06-09 18:28:34

标签: ember.js ember-router

这是Understanding Ember routes的后续行动。

主视图/详细信息视图很棒,但我正在尝试使用分层URL路由而不嵌套模板。但是,我仍然需要访问父模型,例如面包屑链接和其他引用。

因此/users/1/posts应显示用户1的帖子列表。/users/1/posts/1应显示用户1的帖子1,但不应在user模板的{{1}内呈现}}。相反,它应该完全取代{{outlet}}模板。但是,我仍然需要访问user模板中的当前用户,以便我可以链接回用户,显示用户的姓名等。

首先我试过这样的事情(方法#1):

post

这会将App.Router.map(function() { this.resource('user', { path: '/users/:user_id' }, function() { this.resource('posts', function() { this.resource('post', { path: '/:post_id' }); }); }); }); ... App.PostRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); }, renderTemplate: function() { this.render('post', { into: 'application' }); } }); 模板替换为user模板,如预期的那样。但是,当我单击浏览器的后退按钮时,post模板不会再次渲染。显然,后视图被销毁但父视图未被重新插入。这里有几个问题提到了这一点。

然后我让它用这样的东西(方法#2):

user

但这对我来说似乎有些苛刻而且不是很干。

首先,我需要在App.Router.map(function() { this.resource('user', { path: '/users/:user_id' }, function() { this.resource('posts'); this.resource('post', { path: '/users/:user_id/posts' }, function() { this.resource('post.index', { path: '/:post_id' }); }); }); ... App.PostRoute = Ember.Route.extend({ model: function(params) { return App.User.find(params.user_id); }, setupController: function(controller, model) { controller.set('user', model); } }); App.VideoIndexRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); } }); App.PostIndexController = Ember.ObjectController.extend({ needs: 'post' }); 中再次检索User并将其作为临时变量添加到PostRoute(如果路线是正确嵌套,我可以在PostController中设置needs: 'user'属性。此外,这可能会或可能不会对后端产生影响,具体取决于ember-data的适配器实现或用于从服务器检索数据的任何技术(即它可能导致不必要的第二次调用加载{{ 1}})。

我还需要一个额外的`PostIndexController'声明来添加新的依赖项,这不是什么大问题。

另一件感觉不对的是PostController在路由器配置中出现两次(一个嵌套,一个不嵌套)。

我可以处理这些问题而且它确实有效,但我想,总的来说,这似乎是强迫而不是优雅。我想知道我是否缺少一些明显的配置,这些配置可以让我使用常规的嵌套路由来执行此操作,或者如果有人建议使用更多“Ember.js方式”来执行此操作。

我应该提一下,不管方法#2的技术优点如何,我花了很长时间才弄清楚如何使它工作。它需要大量的搜索,阅读,试验,调试等才能找到合适的路径定义组合。我认为这不是一个非常独特的用例,用户可以非常直接地设置这样的东西,而无需花费数小时的试验和错误。如果最终成为正确的方法,我会很高兴在Ember.js文档中写下一些提示。

更新

感谢@spullen澄清这一点。我的情况并不像示例那么简单,因为有些子路径需要嵌套模板而有些不需要,但答案帮助我解决了问题。我的最终实现看起来像这样:

User

现在/users/:user_id/posts呈现App.Router.map(function() { this.resource('users', { path: '/users/:user_id' }, function() { this.resource('users.index', { path: '' }, function() { this.resource('posts') }); this.resource('post', { path: '/posts/:post_id' }, function() { this.resource('comments', function() { this.resource('comment', { path: '/:comment_id' }); }); }); }); }); 模板,但posts取代了所有内容。 users然后在postcomments下呈现,然后在post下呈现。

所有这些都是comment的子路径,因此所有人都可以访问用户模型而无需杂技,只需在每个需要的路线中执行comments

所以模板看起来像这样:

users

我不知道为什么this.modelFor('users')资源定义需要users |- posts post |- comments |-comment ,但如果我把它拿出来,Ember找不到{ path: '' }路由。我很想摆脱最后的遗迹。

1 个答案:

答案 0 :(得分:9)

您可以将父模板定义为仅显示插座并具有将在其中显示的索引路径。然后,对于嵌套资源,您可以执行相同的操作。

<script type="text/x-handlebars" data-template-name="user">
  {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="user/index">
  <h2>user/index</h2>
</script>

<script type="text/x-handlebars" data-template-name="posts">
  {{outlet}}
</script>

<script type="text/x-handlebars" data-template-name="posts/index">
  <h2>posts/index</h2>
</script>

这样它就不会成为主人/细节。

路由器将是:

App.Router.map(function() {
  this.resource('user', function() {
    this.resource('posts', function() { });
  });
});

然后,如果您需要获取有关父级的信息,可以使用modelFor。因此,如果你在帖子中,你可以this.modelFor('user');

这是展示这一点的jsbin

希望这有用。