123

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?

isherwood
  • 58,414
  • 16
  • 114
  • 157
Carl Boisvert
  • 2,173
  • 3
  • 17
  • 19

12 Answers12

201

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});
Tsvetan Ganev
  • 8,246
  • 4
  • 26
  • 43
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 1
    the `router.navigate(string)` method doesn't seem to exist in the current version of Angular (2.2). I searched in the [docs](https://angular.io/docs/ts/latest/api/router/index/Router-class.html) and only found `navigate(commands: any[], extras?: NavigationExtras) : Promise`. Or am I totally missing something? – Tomato Nov 23 '16 at 13:47
  • 2
    @Tomato, you need to put [] around the routes. For example, this.router.navigate(["../../parent"], {relativeTo: this.route}); – gye Jun 28 '17 at 13:42
  • 2
    how do you pass the `relativeTo` data when you are using [routerLink] in the html instead of typescript? – redfox05 Oct 20 '17 at 21:02
  • the same with services? – oCcSking Feb 25 '20 at 08:59
  • 1
    For some reason, in my case I have to use `../../../` instead of `../` to navigate to parent (`'/users'` from `'/users/1'`). – nelson6e65 Sep 20 '20 at 08:20
  • 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`. – Simon Hansen Jun 02 '21 at 13:15
73

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';

ne1410s
  • 6,864
  • 6
  • 55
  • 61
  • 7
    Rather than a date it would be more useful to mention the Angular version you happen to be using. – isherwood Mar 27 '18 at 16:11
  • @isherwood 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, – ne1410s Mar 27 '18 at 19:47
  • @ne1410s Thanks alot was missing the relative :this.route – Ian Samz Nov 29 '18 at 21:58
  • 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`. – Don Thomas Boyle Jan 21 '19 at 20:01
48

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) {

  }
Chris Lamothe
  • 1,473
  • 13
  • 11
  • 2
    Adding some explanation would make this answer more useful. – Sagar Zala Nov 16 '18 at 05:57
  • 1
    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 way – Terry Lam Jan 31 '19 at 16:22
  • @TerryLam: Works great for me. ng7 are you certain you are calling this from inside a component or a service provided in your component – Chris Lamothe Jan 31 '19 at 21:07
  • 1
    @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}). – Terry Lam Feb 01 '19 at 01:55
  • 2
    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. – Roganik Mar 20 '19 at 04:16
  • 2
    +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 }*. – Konrad Viltersten Dec 22 '19 at 17:39
  • awesome, thanks! I'm used to have empty Route full of children, so I needed to navigate `relativeTo: this.route.parent.parent` thanks again! – Mateo Tibaquira Feb 16 '20 at 03:34
12

without much ado:

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

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

Igor Zinin
  • 331
  • 3
  • 5
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
alexpls
  • 1,914
  • 20
  • 29
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 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. – Toby Speight May 13 '16 at 12:02
  • 1
    @TobySpeight Fair enough. I assumed `../` is known well enough, but in the end it's still ambiguous. Thanks for the hint. – Günter Zöchbauer May 13 '16 at 12:06
  • 1
    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. – Carl Boisvert May 13 '16 at 12:39
  • 1
    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)? – Konrad Viltersten Dec 22 '19 at 17:34
  • 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. – Günter Zöchbauer Dec 22 '19 at 18:01
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.)

Don Thomas Boyle
  • 3,055
  • 3
  • 32
  • 54
kayjtea
  • 2,979
  • 1
  • 20
  • 19
  • 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. – DesTroy Sep 08 '18 at 20:07
  • updated code to reflect Angular 6 changes and proper parent finding with parent and child containing children in routes. – Don Thomas Boyle Jan 21 '19 at 20:03
  • 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. – kayjtea Jan 25 '19 at 00:40
  • 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? – Vrajendra Singh Mandloi Jul 08 '20 at 18:22
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
  ) { }
Johansrk
  • 5,160
  • 3
  • 38
  • 37
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);
Carlinhos
  • 940
  • 2
  • 10
  • 21
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.

Krystian
  • 3,193
  • 2
  • 33
  • 71
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.

  • Please update your answer with some descriton why this works. Please see the [How to Answer](https://stackoverflow.com/help/how-to-answer). – Gerald Zehetner Nov 30 '20 at 17:28
0

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

uiSref="^"
Zuriel
  • 1,848
  • 1
  • 19
  • 32
-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
anlijudavid
  • 509
  • 6
  • 12