在EmberJS获得父路线

时间:2013-04-08 02:06:04

标签: ember.js

我正在制作一个可重用的(多态)评论小部件。我想要一个按钮,让我回到父路线(例如,如果我在/ blog_posts / 1 / comments,我想按钮将我带回/ blog_posts / 1)。

我目前正在使用transitionToRoute('blog_post'),但从长远来看这不会起作用,因为我希望这个代码一般可以运行任何模型(也就是说它不知道路线的名字,所以我无法调用'blog_post')。我想我正在寻找像Rails'url_for这样的东西,或者说router.get('parent_route')(或controller.get('parent_route'))的方式。

任何指针或想法?感谢。

4 个答案:

答案 0 :(得分:12)

这是在2013年为ember v0.9.8或其他东西回答的,从那时起框架已经走了很长一段路。我认为当前版本的框架可能有更好的解决方案。既然,我与Ember没有联系,无法真正更新这个答案!

从源代码中的私有函数启发,将以下方法添加到返回parentRoute

名称的路由中
Ember.Route.reopen({
  getParentRoute: function(){
    var route = this;
    var handlerInfos = route.router.router.currentHandlerInfos;
    var parent, current;

    for (var i=0, l=handlerInfos.length; i<l; i++) {
      current = handlerInfos[i].handler;
      if((current.routeName == route.routeName)||(current.routeName.match(/./) && current.routeName.split('.')[1] == route.routeName )){
        return parent.routeName;
      }
      parent = current;
    }
  }
})

使用内部路线如下

App.SomeRoute = Ember.Route.extend({
  events: {
    goBack: function(){
      this.transitionTo(this.getParentRoute());
    }
  }
})

车把

<script type="text/x-handlebars" data-template-name="some">
  <a href="#" {{action goBack}}>Back</a>
</script>

对于实际代码,请打开this并为 function parentRoute执行CTRL + F

答案 1 :(得分:6)

您可以在模板中使用通用{{action }},但在路由器中实现“返回”的细节。这是因为Ember bubbles up goBack事件首先发送到控制器,然后是当前路由,然后是父路由等,直到找到动作处理程序。在这种情况下,控制器上没有匹配操作,因此它由当前路由处理。这使您的模板/视图/控制器与特定内容无关,但是当您连接小部件时,您可以指定应该如何处理“返回”。

在示例中,相同的按钮会使路线更改为不同的路线,具体取决于当前路线的路线:

    路线/posts中的
  • 后退按钮转换为/
  • 路线/posts/new中的
  • 后退按钮转换为/posts

JSBin example

使用Javascript:

App = Ember.Application.create({});

App.Router.map(function() {
  this.resource('posts', function() {
    this.route('new');
  });
});

App.PostsRoute = Ember.Route.extend({
  events: {
    goBack: function(){
      this.transitionTo('index'); 
    }
  }
});

App.PostsNewRoute = Ember.Route.extend({
  events: {
    goBack: function(){
      this.transitionTo('posts'); 
    }
  }
});

模板:

<script type="text/x-handlebars" data-template-name="index">
  <h2>Index Content:</h2>
  {{#linkTo posts}}Posts{{/linkTo}}
  {{outlet}}
</script>

  <script type="text/x-handlebars" data-template-name="posts">
    <h2>Posts</h2>
    <button {{action goBack}}>Go back</button>
    {{#linkTo posts.new}}New{{/linkTo}}
    {{outlet}}
  </script>

  <script type="text/x-handlebars" data-template-name="posts/new">
    <h2>Posts/New</h2>
  </script>

答案 2 :(得分:3)

基于Mudasi Ali的领导和审阅Ember v1.5来源,我使用以下内容:

Coffeescript(如果你想要JS / ES,请使用coffeescript.org进行转换):

Ember.Route.reopen
  parentRoute: Em.computed ->
    r = @router.router
    if r.currentTransition
      handlerInfos = r.currentTransition.state.handlerInfos
    else
       handlerInfos = r.state.handlerInfos

    handlerInfos = this.router.router.state.handlerInfos
    return unless handlerInfos

    parent = @
    for info in handlerInfos
      break if info.handler == @
      parent = info.handler
    parent

  parentRouteName: Em.computed.alias('parentRoute.routeName')

  parentController: ->
    @controllerFor @get('parentRouteName')

  parentModel: ->
    @modelFor @get('parentRouteName')

上面提供了所有路由上的属性parentRouteparentRouteName以及两个分别返回父控制器和模型的便捷函数parentController()parentModel()。适用于许多情况,特别是如果您将资源编辑为嵌套路径。

您还可以在视图/控制器等中定义一些操作,以进行取消/返回处理,如下所示:

Ember.Route.reopen
  actions:
    goBack: ->
      @transitionTo @get('parentRouteName')

如果你有一个深层路由层次结构并想说跳过一个中间路由,你只需要覆盖goBack,如下所示:

App.SomeIntermediateRouteToSkipOnBack = Em.Route.extend
  actions:
    goBack: ->
      # skip the immediate parent and use the grandparent route
      @transitionTo @get('parentRoute.parentRouteName)

答案 3 :(得分:3)

更新了Ember 2.6 在档案app/initializers/parent_route.js

import Ember from 'ember';

var alreadyRun = false;

export default {
  name: 'parent-route',
  initialize: function() {
    if (alreadyRun) {
      return;
    } else {
      alreadyRun = true;
    }
    Ember.Route.reopen({
      parentRoute: Ember.computed(function() {
        let handlerInfos, i, info, len, parent, r;
        r = this.router.router;
        if (r.activeTransition) {
          handlerInfos = r.activeTransition.state.handlerInfos;
        } else {
          handlerInfos = r.state.handlerInfos;
        }
        if (!handlerInfos) {
          return;
        }
        parent = this;
        for (i = 0, len = handlerInfos.length; i < len; i++) {
          info = handlerInfos[i];
          if (info.handler === this) {
            break;
          }
          parent = info.handler;
        }
        return parent;
      }),
      parentRouteName: Ember.computed.alias('parentRoute.routeName'),

      parentController: Ember.computed(function() {
        return this.controllerFor(this.get('parentRouteName'));
      }),

      parentModel: Ember.computed(function() {
        return this.modelFor(this.get('parentRouteName'));
      })
    });

  }
};

在您的路线中,您可以访问像this.get('parentController')这样的父控件,以及this.get('parentModel')

这样的模型