这是 Understanding Ember routes 的后续。
主/详细 View 很棒,但我试图在不嵌套模板的情况下创建一个分层 URL 路由。但是,对于面包屑链接和其他引用,我仍然需要访问父模型。
所以 /users/1/posts
应该显示用户 1 的帖子列表。而 /users/1/posts/1
应该显示用户 1 的帖子 1,但它不应该在 user
模板的 {{outlet}}
内呈现。相反,它应该完全替换 user
模板。但是,我仍然需要访问 post
模板中的当前用户,以便我可以链接回用户、显示用户名等。
首先我尝试了这样的事情(方法#1):
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
模板。但是当我单击浏览器的后退按钮时,user
模板不会再次呈现。显然 post View 被破坏但父 View 没有重新插入。这里有几个问题提到了这一点。然后我让它与这样的东西一起工作(方法#2):
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'
中设置 PostController
属性)。此外,这可能会或可能不会对后端产生影响,具体取决于 ember-data 的适配器实现或用于从服务器检索数据的任何技术(即,它可能会导致不必要的第二次调用 load User
) .我还需要一个额外的 `PostIndexController' 声明来添加新的依赖项,这没什么大不了的。
感觉不对的另一件事是
/users/:user_id/posts
在路由器配置中出现了两次(一个嵌套,一个不嵌套)。我可以处理这些问题并且它确实有效,但我想,总的来说,它似乎是被迫的,而不是那么优雅。我想知道我是否遗漏了一些明显的配置,可以让我使用常规嵌套路由执行此操作,或者是否有人建议使用更多“Ember.js 方式”来执行此操作。
我应该提一下,不管方法 #2 的技术优点如何,我都花了很长时间才弄清楚如何让它发挥作用。需要大量搜索、阅读、试验、调试等,才能找到正确的路由定义组合。我想这不是一个非常独特的用例,用户应该非常简单地设置这样的东西,而无需花费数小时的反复试验。如果最终是正确的方法,我很乐意在 Ember.js 文档中为此编写一些提示。
更新:
感谢@spullen 澄清这一点。我的案例不像示例那么简单,因为有些子路由需要嵌套模板而有些则不需要,但答案帮助我弄清楚了。我的最终实现看起来像这样:
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
模板下渲染,但 post
替换了所有内容。 comments
然后在 post
和 comment
下渲染,依次在 comments
下渲染。它们都是
users
的子路由,因此所有用户模型都可以在没有杂技的情况下访问,只需在需要的每个 Route 中执行 this.modelFor('users')
即可。所以模板看起来像这样:
users
|- posts
post
|- comments
|-comment
我不知道为什么
{ path: '' }
资源定义需要 users.index
但如果我把它拿出来,Ember 找不到 users
路由。我很想摆脱最后的痕迹。
最佳答案
您可以将父模板定义为仅显示 socket 并具有将在其中显示的索引路由。然后对于嵌套资源,您可以做同样的事情。
<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这证明了这一点。
希望这会有所帮助。
关于ember.js - 用于嵌套路由但非嵌套模板的惯用 Emberjs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17012806/