4

我目前的路线定义如下:

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);
    }    
}

我正在尝试做的事情:当我单击转到下一个播放器页面时,如果当前没有显示播放器,则过渡到 PlayerRoute,否则过渡到 PlayerRoute,以便在过渡完成后仍然显示播放器。

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

4

2 回答 2

5

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

路由器:

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

应用程序.hbs:

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

然后您可以覆盖您的renderTemplateforpageplayer路由以呈现到适当的模板中。澄清一下,page路由会显示你当前拥有的玩家路由(它依赖于page_id,但是页面有很多玩家,所以路由会根据页面显示玩家),player路由会根据player_id.

(作为旁注,我不认为你可以像现在这样通过 put resource playerunder嵌套资源resource players——我认为只有路由可以嵌套。)

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

我认为你的建议可行。从链接的示例中,您似乎需要创建“父”资源(不是嵌套路由,而是具有更通用的路径,例如 /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钩子建议。

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

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

我认为您必须小心不要在更通用的路线中呈现模板,因为如果您从 /page/1/player/2 移动到 /page/1/player/3,则不会重新输入页面路线.

于 2013-05-23T04:38:58.860 回答
4

虽然 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”模板渲染{{model.a}}{{model.b}}来自 AbController,但我认为有单独的控制器和模板更干净,并且它启用了可重用性。此外,其中一个控制器可能是一个 ArrayController,它会工作得非常好。

例子的JS Bin

于 2013-07-22T15:09:50.370 回答