【问题标题】:Nested routes in Ember JS and Ember RailsEmber JS 和 Ember Rails 中的嵌套路由
【发布时间】:2013-07-15 19:59:08
【问题描述】:

有人可以通俗地解释嵌套插座在 ember 模板中的工作方式吗?

特别是尝试从文档中理解这一点: http://emberjs.com/guides/routing/rendering-a-template/

“直接父路由没有渲染到主出口......”

这意味着当前路由试图渲染到父级 路由的模板,但父路由没有渲染模板,或者, 如果是,则表明父路由提供的模板没有 渲染到主模板中(即默认的 {{outlet}})。

更具体地说,我正在尝试了解如何在我的应用程序中创建嵌套视图层次结构。 它是三层深度的集合。我想根据集合的内容创建一系列可折叠的嵌套视图。数据结构可以是树状的。

图书馆 -> 每个图书馆有很多书 -> 每本书有很多页

寻找在实践中演示嵌套模板结构的说明性 jsbin 或代码示例。

想象一下这样的路由器:

App.Router.map(function() {

    this.resource('libraries', function() {
        this.route('new');

        this.resource('library', {path: ':library_id'}, function() {

            this.resource('books', function() {
                this.route('new');
                this.resource('book', {path: ':book_id'}, function() {

                    this.resource('pages', function() {
                        this.route('new');
                        this.resource('page', {path: ':page_id'}, function() {

                        }); // Page
                    }); // Pages

                }); // Book
            }); // Books

        }); // Library
    }); // Libraries

}); // map

【问题讨论】:

    标签: ember.js ember-rails


    【解决方案1】:

    一般来说,大多数模板语言都提供了一些方法来将页面的target 内容包装到主布局中。这允许将公共页面布局分离到另一个文件中,并将较小的目标模板放在不同的文件中。

    在 Ember 中对此进行了几次迭代,目前此功能由 {{outlet}} 助手提供。奥特莱斯是 Ember 将yield 放入布局的方式。

    outletyield 明显不同的区域是嵌套。在服务器端生成要简单得多。您只需要标记要让出的模板区域,然后调用以将内容块生成到该指定目标。

    但是,当内容的呈现切换到客户端 JavaScript 时,只有部分页面会按需更新。您不能再简单地将yield 直接放入标记中。你需要一个更聪明的yield 即:- outlet

    {{outlet}} 有两个方面。

    1. 一个标记,指示您要在哪里产生。这是{{outlet}} 助手。
    2. 将模板呈现到此插座的代码。这是renderTemplate 钩子内部使用的render 方法。

    默认情况下,{{outlet}} 不需要名称。这使它成为该模板的默认出口。一个模板中可以有很多这样的出口,它们可以通过给它一个名字来指定。例如:-

    {{outlet 'sidebar'}}
    {{outlet 'nav'}}
    

    这声明了 2 个名为“sidebar”和“nav”的网点。您现在可以将其他模板渲染到这些插座中。

    在没有明确出口名称的情况下使用默认出口。对于命名的网点,渲染是通过在RouterenderTemplate 钩子中调用render 来完成的。 为此,您可以在作为选项传递给render 方法的哈希中指定一个outlet 选项。

    renderTemplate() {
        this.render('recentPosts', { outlet: 'sidebar' });
    }
    

    在这里,模板recentPosts 将被渲染到其父模板内名为“sidebar”的插座中。

    当路由嵌套在其他嵌套路由中时,它们将渲染到最近的父出口。如果父资源没有默认出口,则使用它的父资源,依此类推,直到达到application 模板。

    当您在 Router 中声明 resourcethis.resource('posts'); 时,您是在根据约定指出一些事情。

    1. 使用布局模板posts 渲染posts 路由。
    2. (可选)使用模板 posts/index 渲染隐式 posts.index 路由。

    posts 模板包含所有帖子通用的布局及其子资源。至少它必须至少包含一个默认插座,例如{{outlet}}

    没有这个{{outlet}} 子路由将没有直接的父出口来渲染。然后,它们将在该父级的父级或最终在 application 模板的出口中呈现。发生这种情况时,您将看到"The immediate parent route did not render into the main outlet ..." 警告。发生这种情况时,请检查您的 outlets 的位置。

    posts.index 是给所有具有嵌套路由的资源的隐式路由。换句话说,如果您的资源具有嵌套路由,则无需显式声明嵌套的 this.route('index)`。

    这条index 路由可以显示该资源的内容。例如,对于posts.index,您可以显示所有posts 的列表。此隐式路由的第二个警告是该模型位于父posts 路由上。您必须使用needs api 在PostsIndexController 中获取此模型。

    needs: ['posts'],
    contentBinding: 'controller.posts'
    

    此外,posts.index 路由是可选的。您可以将用于显示帖子列表的 posts/index 中的 UI 直接放入 posts 模板本身。然而,这意味着任何子资源也将与帖子列表一起呈现,以及posts 中的出口。是否使用显式索引路由取决于需要显示的 UI。

    位于所有其他模板之上的是application 模板。它必须有一个outlet 用于渲染嵌套资源,并且通常包含页面共有的布局。如果您未指定应用程序模板,则将使用默认模板。这个生成的模板等同于{{outlet}},即:- 一个只有一个默认出口的模板。

    考虑以下路线。

    App.Router.map(function() {
        this.resource('posts', function() {
          this.route('new')
          this.resource('post', {path: ':post_id'}, function() {
            this.resource('comments', function() {
              this.route('new');
            });
          });
        });
    });
    

    这里,posts.new 将被渲染为 postsposts 将被渲染到 application 模板的默认出口中。下面列出了使用的其余模板。

    +---------------------------+--------------------------------------------------------+
    | Route                     | Templates used (default outlets)                       |
    +---------------------------+--------------------------------------------------------+
    | posts.index               | posts.index > posts > application                      |
    +---------------------------+--------------------------------------------------------+
    | posts.new                 | posts.new > posts > application                        |
    +---------------------------+--------------------------------------------------------+
    | posts.post.index          | post.index > post > posts > application                |
    +---------------------------+--------------------------------------------------------+
    | posts.post.new            | post.new > post > posts > application                  |
    +---------------------------+--------------------------------------------------------+
    | posts.post.comments.index | comments.index > comments > post > posts > application |
    +---------------------------+--------------------------------------------------------+
    | posts.post.comments.new   | comments.new > comments > post > posts > application   |
    +---------------------------+--------------------------------------------------------+
    

    可以通过为render 方法指定into 选项来更改此默认模板层次结构。

    renderTemplate: function() {
      this.render('posts', { into: 'sidebar' })
    }
    

    这里posts 模板将渲染到sidebar 模板的默认出口。

    就是这样。 Outlet 是另一个使用大量约定而不是配置的 ember 概念。默认设置非常好,同时易于自定义。

    【讨论】:

    • 感谢 Darshan 的详细概述。 Route --> Templates 表有助于澄清一些事情。在我完全理解之前,我会再读一遍这对夫妇。当涉及到嵌套行为时,我只需要牢记在心。
    • 你在哪里定义了路线'posts.post.new'?
    • @Darshan 你能否看看我的问题,它也解决了 emberjs 的路由器行为? stackoverflow.com/questions/17780344/…
    猜你喜欢
    • 2016-01-10
    • 2014-12-19
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多