2013-04-08 76 views
6

我正在做一个可重用(多态)的评论部件。我想要一个按钮,使我可以返回到父路线(例如,如果我在/ blog_posts/1/comments,我希望按钮将我带回到/ blog_posts/1)。在EmberJS中获取父路由

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

任何指针或想法?谢谢。

回答

10

这在2013年的余烬v0.9.8或某事回答,框架从那以后很长的路要走。我认为目前版本的框架可能会有更好的解决方案。因为我没有联系Ember,所以不能真正更新这个答案!

在源代码从一个私有函数的启发,以下方法添加到如下

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

把手

它返回 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; 
    } 
    } 
}) 

使用内部路由的名称的路由

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

对于实际的代码,邻

CoffeeScript中(使用CoffeeScript的:基于Mudasi阿里的铅和审查我用灰烬V1.5源以下笔this并做了CTRL + F为function parentRoute

+0

很好的答案 - 谢谢。我已经实现了这一点,它的作品是一种享受! – iHiD 2013-04-08 13:47:57

+1

请注意,由于currentHandlerInfos可能未设置,因此您无法使用它来获取当前正在转换到的路由的父路由(例如,当正在加载页面时)。我试图在一个路由处理器基类中使用它来获取父类的模型而不知道它的名字,不幸的是页面加载太快了。 – 2013-07-04 06:35:19

+0

因此,这是获取CURRENT路由的父路由名称的好方法,而不是从中调用该方法的路由对象。那是因为你通过'router'获取了路由的层次结构。 – Huafu 2014-05-11 08:33:29

6

您可以使用您的模板通用{{action }}而拥有“回去”,在路由器中实现的具体细节。这是有效的,因为Ember bubbles upgoBack事件首先发送给控制器,然后是当前路由,然后是父路由等,直到找到操作处理程序。在这种情况下,控制器上没有匹配的动作,所以它由当前路由处理。这可以让你的模板/视图/控制器不受限于特定的细节,但是当你连接小部件时,你可以指定如何处理“返回”。

在该示例中相同的按钮会导致路由改变到这取决于路由是当前路线不同的路线:

  • 在路线/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> 
+0

大答案模型 - 谢谢!我已经标记@ Unspecified的被接受,因为它会涉及到我添加的每条新路由的更少设置 - 但这将是一个完美的实现,所以谢谢:) – iHiD 2013-04-08 13:48:51

+0

我认为这可以在Ember.Route类本身上实现,它在路由初始化期间动态添加goBack方法。这也更清洁。 – 2014-05-12 05:45:57

3

。org进行transpile如果你想JS/ES):

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

在文件更新了灰烬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')的parentcontroller和类似this.get('parentModel')