【问题标题】:Getting parent route in EmberJS在 EmberJS 中获取父路由
【发布时间】:2013-04-08 02:06:03
【问题描述】:

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

我目前正在使用transitionToRoute('blog_post'),但从长远来看这不会起作用,因为我希望这段代码一般可以在任何模型上运行(即它对路线名称一无所知,所以我可以' t调用'blog_post')。我想我正在寻找类似 Rails 的url_forrouter.get('parent_route')(或controller.get('parent_route'))的说法。

有什么建议或想法吗?谢谢。

【问题讨论】:

    标签: ember.js


    【解决方案1】:

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

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

    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

    【讨论】:

    • 很好的答案 - 谢谢。我已经实现了这个,它很管用!
    • 请注意,您不能使用它来获取当前正在转换到的路由的父路由(例如在加载页面时),因为可能未设置 currentHandlerInfos。我试图在路由处理程序基类中使用它来获取父模型而不知道它的名称,不幸的是页面加载为时过早。
    • 所以这是获取当前路由的父路由名称的好方法,而不是调用该方法的路由对象的父路由名称。那是因为您通过 router 获取路由的层次结构。
    • @Huafu 这个是在框架还没有现在成熟的时候回答的。因此,我真的建议您阅读最新指南,以便找到与实现相同功能的最佳实践相关的良好线索。
    • 我们开始在我们的代码中使用这个人,但由于所有的依赖关系,我发现对它进行单元测试非常困难。我最终使用了这个(至少适用于简单的情况):return route.routeName.split('.').slice(0, -1).join('.'); 在这不起作用的地方有什么吗?
    【解决方案2】:

    您可以在模板中使用通用{{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>
    

    【讨论】:

    • 很好的答案 - 谢谢!我已将@Unspecified 标记为已接受,因为它会为我添加的每条新路线减少设置 - 但这将是一个非常好的实现,所以谢谢:)
    • 我认为这可以在 Ember.Route 类本身上实现,在路由初始化时动态添加 goBack 方法。这也干净多了。
    【解决方案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)
    

    【讨论】:

      【解决方案4】:

      为 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') 这样的模型

      【讨论】:

        猜你喜欢
        • 2013-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多