Getting Parent Route in EmberJS

I am making a multiple (kind of polymorphic) comment widget. I want a button that allows me to return to the parent route (for example, if I'm on / blog _posts / 1 / comments, I want the button to return me / blog _posts / 1).

I am currently using transitionToRoute('blog_post') , but this will not work in the end, because I want this code as a whole to run with any model (i.e. it knows nothing about the route name, t call ' blog_post '). I am probably looking for something like Rails' url_for or a way to say router.get('parent_route') (or controller.get('parent_route') ).

Any pointers or ideas? Thanks.

+6
source share
4 answers

In response to this question in 2013 on ember v0.9.8 or something else, the structure has come a long way since then. I think there might be a much better solution with the current version of the framework. Since I do not communicate with Ember, I can not really update this answer!

Inspired from a private function in the source code, add the following path to the routes that returns the name 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; } } }) 

Use internal routes as follows

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

Rudders

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

For actual code, open this and do CTRL + F for function parentRoute

+10
source

You can use the common template {{action }} in your template, but have the "return" features implemented in the router. This works because Ember creates bubbles in the goBack event first for the controller, then the current route, then the parent route, etc., until an action handler is found. In this case, there is no corresponding action on the controller, therefore it is processed by the current route. This preserves the specificity of your template / view / controller / specifier, but when you connect the widget, you can specify how to handle the "return".

In the example, the same button changes the route to different routes, depending on which route is the current route:

  • in the /posts route, the back button goes to /
  • in the /posts/new route, the back button goes to /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'); } } }); 

Template:

 <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> 
+6
source

Based on the Mudasi Ali guide and analyzing the source of Ember v1.5, I use the following:

Coffeescript (use coffeescript.org for forwarding if you want 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') 

The above parentRoute and parentRouteName on all your routes and two convenient functions parentController() and parentModel() , which return the parent controller and model, respectively, which can be useful in many situations, especially if you represent editing the resource as a nested route .

You can also define some actions to use in your views / controllers, etc. to cancel / reverse control as follows:

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

If you have a deep routing hierarchy and want to say skip the intermediate route, you just need to override goBack as follows:

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

Updated for Ember 2.6 in the file 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')); }) }); } }; 

On your routes, you can access the parent controller, for example, this.get('parentController') , and a model like this.get('parentModel')

+3
source

All Articles