How do I navigate to a parent route from a child route?
Asked Answered
B

12

128

My problem is quite classic. I have a private part of an application which is behind a login form. When the login is successful, it goes to a child route for the admin application.

My problem is that I can't use the global navigation menu because the router tries to route in my AdminComponent instead of my AppCompoment. So my navigation is broken.

Another problem is that if someone want to access the URL directly, I want to redirect to the parent "login" route. But I can't make it work. It seems to me like theses two issues are similar.

Any idea how it can be done?

Benzyl answered 12/5, 2016 at 20:31 Comment(2)
please add some codeCasey
As pointed out by others, please add some code or the basic routes config so that your question can attract more precise answers.Cyclostyle
P
206

Do you want a link/HTML or do you want to route imperatively/in code?

Link: The RouterLink directive always treats the provided link as a delta to the current URL:

[routerLink]="['/absolute']"
[routerLink]="['../../parent']"
[routerLink]="['../sibling']"
[routerLink]="['./child']"     // or
[routerLink]="['child']" 

// with route param     ../../parent;abc=xyz
[routerLink]="['../../parent', {abc: 'xyz'}]"
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
[routerLink]="['../../parent']" [queryParams]="{p1: 'value', p2: 'v2'}" fragment="frag"

With RouterLink, remember to import and use the directives array:

import { ROUTER_DIRECTIVES } from '@angular/router';
@Component({
    directives: [ROUTER_DIRECTIVES],

Imperative: The navigate() method requires a starting point (i.e., the relativeTo parameter). If none is provided, the navigation is absolute:

import { Router, ActivatedRoute } from '@angular/router';
...
constructor(private router: Router, private route: ActivatedRoute) {}
...
this.router.navigate(["/absolute/path"]);
this.router.navigate(["../../parent"], {relativeTo: this.route});
this.router.navigate(["../sibling"],   {relativeTo: this.route});
this.router.navigate(["./child"],      {relativeTo: this.route}); // or
this.router.navigate(["child"],        {relativeTo: this.route});

// with route param     ../../parent;abc=xyz
this.router.navigate(["../../parent", {abc: 'xyz'}], {relativeTo: this.route});
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
this.router.navigate(["../../parent"], {relativeTo: this.route, 
    queryParams: {p1: 'value', p2: 'v2'}, fragment: 'frag'});

// navigate without updating the URL 
this.router.navigate(["../../parent"], {relativeTo: this.route, skipLocationChange: true});
Poised answered 7/8, 2016 at 3:55 Comment(6)
the router.navigate(string) method doesn't seem to exist in the current version of Angular (2.2). I searched in the docs and only found navigate(commands: any[], extras?: NavigationExtras) : Promise<boolean>. Or am I totally missing something?Priority
@Tomato, you need to put [] around the routes. For example, this.router.navigate(["../../parent"], {relativeTo: this.route});Premiere
how do you pass the relativeTo data when you are using [routerLink] in the html instead of typescript?Tedious
the same with services?Duramen
For some reason, in my case I have to use ../../../ instead of ../ to navigate to parent ('/users' from '/users/1').Foursquare
something good to know is, that router and activatedRoute need to be injected in the component itself, this can not be wrapped into a extra service and a method like goUp.Concord
I
74

This seems to work for me as of Spring 2017:

goBack(): void {
  this.router.navigate(['../'], { relativeTo: this.route });
}

Where your component ctor accepts ActivatedRoute and Router, imported as follows:

import { ActivatedRoute, Router } from '@angular/router';

Ichthyo answered 22/4, 2017 at 8:46 Comment(4)
Rather than a date it would be more useful to mention the Angular version you happen to be using.Makalu
@Makalu I agree. Apologies. If I remember correctly, I wrote it for Angular 4.0.x and it was still functional in 4.3.x. Unfortunately I have moved away from Angular now,Ichthyo
@Ichthyo Thanks alot was missing the relative :this.routeSyncretism
Note: Will NOT work with additional router segments on lazy loaded modules. EX: parentPath: 'work:queue' (which has children) and said children load child module with parameters. fullCurrentPath: 'work/shipping/module/list'. The above code can't load parentPath from fullCurrentPath.Ecg
C
52

You can navigate to your parent root like this

this.router.navigate(['.'], { relativeTo: this.activeRoute.parent });

You will need to inject the current active Route in the constructor

constructor(
    private router: Router,
    private activeRoute: ActivatedRoute) {

  }
Cavicorn answered 15/11, 2018 at 20:46 Comment(7)
Adding some explanation would make this answer more useful.Paltry
Many people suggest navigate to sibling by this.router.navigate(["../sibling"], {relativeTo: this.route}); However, this is not working anymore. I found this answer work probably. Instead of using '../' to navigate to parent. change relativeTo from this.route to this.route.parent is the correct wayCap
@TerryLam: Works great for me. ng7 are you certain you are calling this from inside a component or a service provided in your componentCavicorn
@ChrisLamothe: Oh yes I made a mistake. It works in general case. However, it doesn't work in auxiliary routes. That means this.router.navigate(['../sibling']) is working but not this.router.navigate([{outlets: {'secondary': ['../sibling']}}]). In auxiliary routing, I have to use this.router.navigate([{outlets: {'secondary': ['sibling']}}], {relativeTo:this.activatedRoute.parent}).Cap
Also, the navigation method from this answer this.router.navigate(['.'], {relativeTo: this.activeRoute.parent}); will work correctly in a case, when you use the same component in two paths: /users/create and /users/edit/123. In both cases it'll navigate to parent /users. The regular navigation with this.router.navigate([".."], {relativeTo: this.activeRoute}) will work only for the users/create but it won't work for the users/edit/123 because it'll navigate to not-existing /users/edit/ route.Religieuse
+1 for an alternative but personally, I'm a bit of a byte chaser and would invest an extra dot in the parameter, [".."], to eliminate reference to parent, { relativeTo: this.route }.Zilvia
awesome, thanks! I'm used to have empty Route full of children, so I needed to navigate relativeTo: this.route.parent.parent thanks again!Intervene
U
14

without much ado:

this.router.navigate(['..'], {relativeTo: this.activeRoute, skipLocationChange: true});

parameter '..' makes navigation one level up, i.e. parent :)

Unmentionable answered 12/11, 2019 at 14:44 Comment(2)
You might want to mention the purpose/need of skipLocationChange.Zilvia
In addition to the previous comment, add a reference to what does the "this.activeRoute" is related toGreenwald
T
9
constructor(private router: Router) {}

navigateOnParent() {
  this.router.navigate(['../some-path-on-parent']);
}

The router supports

  • absolute paths /xxx - started on the router of the root component
  • relative paths xxx - started on the router of the current component
  • relative paths ../xxx - started on the parent router of the current component
Titlark answered 13/5, 2016 at 8:19 Comment(5)
Although this code may answer the question, providing additional context regarding why and/or how it answers the question would significantly improve its long-term value. Please edit your answer to add some explanation.Buckeye
@TobySpeight Fair enough. I assumed ../ is known well enough, but in the end it's still ambiguous. Thanks for the hint.Engud
Thanks for the answer, I've been working on this website for quite some time, so Angular as obviously been updated since. I've try this solution in my current version and it doesn't work. Let me update and I'll comment back after.Benzyl
I don't get your code to work as expected. However, by adding explicitly , { relativeTo: this.route } as a second parameter in the call to navigate, it works. I'd chalk it up to a stupid typo if it hadn't been for the fact that your answers generally have an extreme degree of accuracy. Is it perhaps a change in behavior of the router since the answer was provided (3.6 years ago, which in Angular years is like a half'ish eternity)?Zilvia
This is an old answer and the router changed a lot at this time. I think my answer is just outdated considering that there are several answers with more upvotes. I'm not doing that much web UI stuff anymore and don't have all details on the top of my head.Engud
S
6

To navigate to the parent component regardless of the number of parameters in the current route or the parent route: Angular 6 update 1/21/19

   let routerLink = this._aRoute.parent.snapshot.pathFromRoot
        .map((s) => s.url)
        .reduce((a, e) => {
            //Do NOT add last path!
            if (a.length + e.length !== this._aRoute.parent.snapshot.pathFromRoot.length) {
                return a.concat(e);
            }
            return a;
        })
        .map((s) => s.path);
    this._router.navigate(routerLink);

This has the added bonus of being an absolute route you can use with the singleton Router.

(Angular 4+ for sure, probably Angular 2 too.)

Staging answered 22/11, 2017 at 4:4 Comment(4)
weirdly, this always returns an empty array, and achieves the same result as this._router.navigate([]), while this._router.navigate([[]]) takes to the parent route, if and only if the parent route isn't root itself.Fructuous
updated code to reflect Angular 6 changes and proper parent finding with parent and child containing children in routes.Ecg
Are you sure this isn't something specific to your use case? It would seem not appending the last path would turn ['orders', '123', 'items', 1] into just ['orders'], which doesn't seem right at all. In any case, we just went from Angular 5 to 7 and didn't touch this coded.Staging
their are number of div on my page.. on click of every div i pass query parms and load a component. now using browser back button i want to go back how to do that?Galsworthy
D
6

Another way could be like this

this._router.navigateByUrl(this._router.url.substr(0, this._router.url.lastIndexOf('/'))); // go to parent URL

and here is the constructor

constructor(
    private _activatedRoute: ActivatedRoute,
    private _router: Router
  ) { }
Danish answered 1/5, 2019 at 8:33 Comment(0)
A
2

My routes have a pattern like this:

  • user/edit/1 -> Edit
  • user/create/0 -> Create
  • user/ -> List

When i am on Edit page, for example, and i need go back to list page, i will return 2 levels up on the route.

Thinking about that, i created my method with a "level" parameter.

goBack(level: number = 1) {
    let commands = '../';
    this.router.navigate([commands.repeat(level)], { relativeTo: this.route });
}

So, to go from edit to list i call the method like that:

this.goBack(2);
Angularity answered 7/2, 2018 at 11:42 Comment(0)
A
2

Everyone suggesting using relative paths really forgets about the most important part: the relative path always depends on the (possible) params you have in your route.

As an example, if you have a child route edit/:id and your id is an URI formatted like /api/something/123 then in order to get to your parent using a relative route you need to use [../../../..']. In other words, treat the URL like a directory structure on your computer. Don't think of the route in terms of the definition created in your routing table.

Adamsite answered 5/6, 2022 at 11:2 Comment(0)
A
1

None of this worked for me ... Here is my code with the back function :

import { Router } from '@angular/router';
...
constructor(private router: Router) {}
...
back() {
   this.router.navigate([this.router.url.substring(0, this.router.url.lastIndexOf('/'))]);
}

this.router.url.substring(0, this.router.url.lastIndexOf('/') --> get the last part of the current url after the "/" --> get the current route.

Arthralgia answered 30/11, 2020 at 16:59 Comment(1)
Please update your answer with some descriton why this works. Please see the How to Answer.Kaylil
A
0

If you are using the uiSref directive then you can do this

uiSref="^"
Ashtonashtonunderlyne answered 15/12, 2019 at 16:17 Comment(0)
V
-2

My solution is:

const urlSplit = this._router.url.split('/');
this._router.navigate([urlSplit.splice(0, urlSplit.length - 1).join('/')], { relativeTo: this._route.parent });

And the Router injection:

private readonly _router: Router
Visualize answered 30/1, 2020 at 21:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.