【问题标题】:Multiple dynamic segments in ember.jsember.js 中的多个动态段
【发布时间】:2013-05-23 00:33:48
【问题描述】:

我目前的路线定义如下:

App.Router.map(function() {
    this.resource('players', { path: ':page_id' }, function() {
        this.resource('player', { path: ':player_id' });
    });
});

我的想法是我在左侧有一个玩家姓名列表。显示的播放器名称取决于 page_id。在右侧,我根据 player_id 显示单个玩家及其所有信息。问题是,两者都是独立的,这意味着我可以在第三个播放器页面上,同时显示列表中的第一个播放器,或者根本没有播放器。

我一直在尝试做的是这样的事情,这是 PlayersController 中的一个方法,当我点击进入下一个播放器页面时会调用它:

doTransition: function() {
    var players = App.Player.findAllForPage(this.playersPerPage, this.currentOffset);
    players.reopen({
        id: this.currentOffset
    });
    var playerController = this.get('controllers.player');
    var currentPlayer = playerController.getWithDefault('content');
    if (currentPlayer) {
        this.transitionToRoute('player', players, currentPlayer);
    } else {
        this.transitionToRoute('players', players);
    }    
}

我要做的事情:当我点击进入下一个播放器页面时,如果当前没有显示播放器,则过渡到 PlayersRoute,否则过渡到 PlayerRoute 以便转换完成后仍会显示播放器。

问题:有时 currentPlayer 变量并不总是为 null,即使当前没有显示任何玩家。有没有办法解决这个问题,也许是从某个地方获取当前路线?

【问题讨论】:

    标签: ember.js


    【解决方案1】:

    鉴于你说这两个部分(基于page_id 的玩家列表和基于player_id 的玩家信息)是完全独立的,在我看来你不会嵌套路线,而是有您有选择地渲染到的两个命名插座(称它们为leftright,或pageplayer 等)。

    路由器:

    App.Router.map(function() {
        this.resource('page', { path: ':page_id' });
        this.resource('player', { path: ':player_id' });
     });
    

    application.hbs:

    {{outlet page}}
    {{outlet player}}
    

    然后您可以覆盖您的renderTemplate 为您的pageplayer 路由呈现到适当的模板。澄清一下,page 路由会显示你当前拥有的玩家路由(它取决于 page_id,但页面有很多玩家,所以路由会根据页面显示玩家),player 路由会显示基于player_id的玩家信息。

    (顺便说一句,我认为你不能像现在这样将resource player 放在resource players 下嵌套资源——我认为只有路由可以嵌套。)

    编辑:使用具有多个动态段的单一路线

    我认为你的建议可行。从linked example 看来,无论如何您都需要创建“父”资源(不是嵌套路由,而是具有更通用的路径,例如 /page/ 和 /page/:page_id/player/:player_id)。然后,您可以通过 model 在适当的路由中单独设置模型,并为双动态分段路由提供 serialize 挂钩:

    serialize: function(model) {
        return {
            page_id : this.modelFor('page').get('id') 
            player_id : this.modelFor('player').get('id')
        };
    }
    

    请注意,我们不依赖传入的 model 对象,因为您说过页面和播放器面板可以完全独立,因此我们使用 modelFor 代替。

    我认为您还可以通过redirect 钩子处理有关要渲染的默认页面/要渲染的默认播放器的逻辑(如果此处没有建议)。

    最后,您将在 PagePlayer 路由中覆盖 renderTemplate 以实际进行渲染:

    renderTemplate: function(model, controller) {
      this.render("page", { into: "page" });
      this.render("player", { into: "player"});
    }
    

    我认为你必须小心不要在更一般的路线中呈现模板,因为如果你从 /page/1/player/2 移动到 /page/1/player/3,页面路线不是重新输入。

    【讨论】:

    • 这绝对很有意义。在这种情况下,我将有 1 个模板、2 个路由和 2 个控制器独立工作。我很好奇的一件事是,模型将如何序列化以创建 url?还会是 blabla.com/#/:page_id/:player_id 吗?
    • 嗯,不,如果路由是独立的,它们将被独立序列化。所以它要么是#/pages/:page_id 要么是#/players/:player_id——最近访问过的URL 只会影响其相应的出口。这也意味着 URL 并没有完全序列化应用程序的状态,只有 URL 中表示的出口!您是否正在寻找一个包含两个部分的 URL 的解决方案?
    • 绝对!这就是为什么我认为嵌套路由是唯一的解决方案。
    • 也许设置一条带有多个参数的路线是可行的方法?类似 this.resource('players', { path: 'players/:page_id/:player_id' });。 Reference
    • @Deli 好发现!这似乎会奏效。检查我的答案是否有可能的方法 - 我没有尝试过,但如果它有效,请告诉我
    【解决方案2】:

    虽然 Sherwin 的回答让我很好地了解了我的目标,但我只是想举一个完整的例子,大致了解我最终实施的内容。这可能对将来的参考有所帮助。

    我将通过让模型成为简单的 int 来简化它,这样我们就可以从 url 直接转换为模型,反之亦然。

    模板:

    <script type="text/x-handlebars">
      {{outlet a}}
      {{outlet b}}
    </script>
    
    <script type="text/x-handlebars" id="a">
      {{model}}
    </script>
    
    <script type="text/x-handlebars" id="b">
      {{model}}
    </script>
    

    应用:

    App = Ember.Application.create();
    
    App.Router.map(function() {
      // This route has 2 dynamic segments
      this.resource("ab", { path: "/:a/:b" });
    });
    
    App.IndexRoute = Ember.Route.extend({
      redirect: function() {
        // At the entry point, encapsulate the 2 models in the context object,
        // and transition to the route with dual dynamic segments
        this.transitionTo('ab', {a: 3, b:4});
      }
    });
    
    App.AbRoute = Ember.Route.extend({
      model: function(params) {
        // The model is {a, b} directly
        return params;
      },
    
      renderTemplate: function(){
        // Render in the named outlet using the right controller
        this.render('a', {into: 'application', outlet: 'a', controller: 'a'});
        this.render('b', {into: 'application', outlet: 'b', controller: 'b'});
      },
    
      serialize: function(model) {
        return {
          a: model.a,
          b: model.b
        };
      },
    
      setupController: function(controller, model) {
        // Setup each controller with its own model
        this.controllerFor('a').set('model', model.a);
        this.controllerFor('b').set('model', model.b);
      }
    });
    

    补充说明:

    本来可以有一个单独的“ab”模板从 AbController 渲染 {{model.a}}{{model.b}},但我认为单独的控制器和模板更简洁,并且它可以实现可重用性。此外,其中一个控制器可能是 ArrayController,它会工作得非常好。

    JS Bin of the example

    【讨论】:

      猜你喜欢
      • 2013-12-23
      • 1970-01-01
      • 1970-01-01
      • 2018-01-02
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 2020-05-01
      • 1970-01-01
      相关资源
      最近更新 更多