7

我正在制作一个可重用的(某种多态的)评论小部件。我想要一个使我能够返回父路由的按钮(例如,如果我在 /blog_posts/1/comments,我希望该按钮将我带回 /blog_posts/1)。

我目前正在使用transitionToRoute('blog_post'),但从长远来看这不会起作用,因为我希望这段代码可以在任何模型上通用运行(即它不会知道任何关于路线名称的信息,所以我不能调用'blog_post') . 我想我正在寻找像 Rails'这样的东西url_for,或者是一种说法router.get('parent_route')(或controller.get('parent_route'))。

任何指示或想法?谢谢。

4

4 回答 4

12

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

灵感来自源代码中的私有函数,将以下方法添加到返回名称的 RoutesparentRoute

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>

对于实际代码,打开并按 CTRL+F function parentRoute

于 2013-04-08T07:08:59.733 回答
6

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

在示例中,相同的按钮会导致路由更改为不同的路由,具体取决于哪个路由是当前路由:

  • 在路由/posts后退按钮过渡到/
  • 在路由/posts/new后退按钮过渡到/posts

JSBin 示例

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>
于 2013-04-08T02:45:25.817 回答
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')

上面提供了所有路由的属性parentRouteand和两个方便的函数,它们分别返回父控制器和模型,这在许多情况下都很有用,尤其是当您将资源编辑为嵌套路由时。parentRouteNameparentController()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)
于 2014-05-09T04:11:04.730 回答
3

在文件中更新了 Ember 2.6app/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')

于 2016-06-29T15:35:46.773 回答