JavaScript 请教关于 Ember.js 中如何把 Nested Routes 加载到同一个模板的问题

aidewoode · 2015年05月07日 · 最后由 aidewoode 回复于 2015年05月08日 · 2677 次阅读

本人新手,才接触 ember,现在有个问题被卡住了。所以请教一下论坛里的高手。

问题是这样的,我有一个 post 页面,然后需要在 post 页面里面加载相应的 comments,

router 是这样的

this.route("posts",{path: "/posts/:id"}, function() {
   this.route("comments");
 });

因为需要分页,所以写了 posts.comments 的 routes,让其从后端加载分好的 comments, 然后在 posts 的 template 里用{{outlet}} 加载 comments 的视图。

但现在就有个问题,我必须连接到 像 xxxxx/posts/1/comments 这样的 url 才能把 post 和 comments 都加载。 但是我想的是 能否从 xxxxx/posts/1 这样的 url 就能加载完整的页面。好像貌似 {{render}} helper 可以,

然后我用 render 加载试了一下,

{{render "posts.comments" posts.comments}} 

但是这样是错的,因为 render 的第二个参数,要指定一个 model 类型,但是我想用的是 posts.comments 的 routes 里面的 model,貌似好像没法。

所以我想请教该如何解决这个问题呢??

你得区分一下 front 和 backend. 前端是不同的页面通过 route 在跳转,而在 ember router 中准备数据. 你可以这样思考:

  1. PostRouter 中就加载好 posts 的第一页的 comments
  2. 写好 template 然后利用 {{render}} 传入 model
  3. 分页的操作在按照道理应该在 PostRouter 中的 actions 处理,远程加载数据。

{{render}} helper 的特点在文档中有写:

{{render}} does several things:

* When no model is provided it gets the singleton instance of the corresponding controller
* When a model is provided it gets a unique instance of the corresponding controller
* Renders the named template using this controller
* Sets the model of the corresponding controller

当然你这个特点应该将 {{render}} 换为使用 {{partial}} , 只是部分 comments 的 html 片段不一样,但是上下文中使用的 model 是一样的, 所以第二步中可以

  1. 在 template 中使用 {{partial 'comments'}} 不用传递当前 template 所对应的 controller 上下文中的 model, 他会自动拥有这个 context 可以直接使用
  2. 最好将 partial 使用的 template 使用 "_" 开头 (类似 rails 中的 partial html 命名). 例如:_comments.hbs , 里面就直接 {{#each post.comments as |comment|}} 使用就好

{{partial}} 寻找的几个特点在文档中也有写:

* The partial helper renders another template without changing the template context
* If a "_nav" template isn't found, the partial helper will fall back to a template named "nav".  ({{partial "nav"}})
* The parameter supplied to partial can also be a path to a property containing a template name

#1 楼 @wppurking

非常感谢啊,非常好的方法啊,学习了,但是这样的话,会不会让 posts 的 routes 里面 post 和 comment 混在一起了,后端 api 写出来感觉就不怎么清晰了,我想的是,能不能 post 的 routes 里面用一个 model,而在 post.comments 里面的 routes 里面用另外的一个 model,加载 post 相应的 comments,然后再在 post 的 的 template 中加载对应 comments 的视图和 model,这样我感觉比较清晰,不知道现在 ember 能不能实现这样的要求啊?

@aidewoode 如果需要在 /posts/1 的页面里面查看 post 和分页的 comments 你的 URL 应该需要 /posts/1/comments?page=N 这种形式了

这样你的 Router 就是你上面写的那样,而同时你需要手动准备

  • PostsCommentsRouter : 在这个里面准备你关于某个 post 的 comments 数据
  • PostsCommentsController : 在这里准备 template 里面的事件和需要收集的参数。
  • template/posts/comments.hbs : 这个与对应的 controller 对应使用。

这样设计 API 可能有点怪怪的,例如:你查看 topic 的 comments 理想的是 /topic/1 查看 topic 和这个 topic 的 comments, 要查看分页的 comments 会是 /topic/1?page=2 这样。

我说区分 front 和 backend 的意思是,其实 Ember 提供 双向绑定 的好处就是,你可以不用理睬 template 改如何展示你的 model 数据,因为 Ember 让你的数据在前端是"活"的,只要 Ember 所绑定的 data/model 发生变化 template 就会自动的变化,而这个思维与 backend 中的数据变化则一定需要重新 get 一个页面不太一样。

另外,我猜测你应该还是使用了 Ember-Data, 而 Ember-Data 中对于分页功能现在还没有尘埃落定 (我们看起来简单,实现起来还是有他们的难度) 参看两个 issue #1517 #2095 所以现在的意思就是,如果我们要做分页,还得自己想想办法,当渲染了 posts 后,在 PostsController 或者 PostsRouter 中自己再重新提交请求向 backend 要分页的 comments 数据,再 push 到 store 中让 Ember 自动处理变化的数据. (你会发现 Discourse 的分页取巧了,给了总个数,但没有给页码,而且是一直拖拽加载不是分页加载。当然这种形式也挺适合他们的需求)

#3 楼 @wppurking 确实是啊,现在确实在用 ember-data,前后端结合 ember-cli-pagination 和 will_paginate 进行分页,url 弄出来确实是很怪,看来如果没办法的话,还不得不自己实现一个分页了。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号