Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to navigate from child component to upper level routes using link params array in angular2?

My AppComponent has a @RouteConfig decorator that defines the top-level routes:

@RouteConfig([
  {
    path: '/',
    name: 'Home',
    component: HomeComponent
  },
  {
    path: '/about',
    name: 'About',
    component: AboutComponent
  },
  {
    path: '/profile/...',
    name: 'Profile',
    component: ProfileComponent
  }
])

export class AppComponent {
}

My ProfileComponent has a @RouteConfig decorator that defines the Profile child routes:

@RouteConfig([
  {path: '/', component: ProfileDetailsComponent, name: 'View', useAsDefault: true},
  {path: '/:id', component: ProfileDetailsComponent, name: 'Public'},
  {path: '/edit', component: ProfileEditorComponent, name: 'Edit'},
])

export class ProfileComponent {
}

When i'm inside ProfileDetailsComponent I can do redirects to other Profile routes but not others. I want to avoid specifying the url using navigateByUrl and use route names instead, using navigate. E.g.:

this.router.navigate(['View']); // Works
this.router.navigate(['About']); // Raises error that it does not exist

I read this answer here: Angular 2 - How to navigate to another route using this.router.parent.navigate('/about')

It uses:

this.router.parent.navigate(['About']);

Which is sort of ok, but solves my problem only when I know at declaration time where the redirect should go. I have multiple levels of nesting and determine the target route at runtime. I'm looking for a way to do something like:

this.router.navigate(['Level1', 'Level2', 'Level3']);

Which allows me to track somewhere the fully qualified name of the target route. Is this possible in any way?

like image 741
fips Avatar asked May 16 '16 16:05

fips


2 Answers

Prefix the route name with a slash to indicate that the route is a root route

this.router.navigate(['/About']); 
like image 106
Günter Zöchbauer Avatar answered Oct 04 '22 00:10

Günter Zöchbauer


This is where a microservice comes in handy, check out the service docs here. The idea is that the parent can listen for child requests to navigate and the child can broadcast said changes as desired.

Let's start with a simple object that will store the route name and the optional arguments:

export class NavArgs {
   constructor(routeName: string, args?: any) { }
}

Now let's define the microservice, with rxjs this is really easy:

import { Injectable } from '@angular/core'
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class NavigationService {
  private navigationRequestedSource = new Subject<string>();

  onNavigationRequested$ = this.navigationRequestedSource.asObservable();

  requestNaivation(navArg: string) {
    this.navigationRequestedSource.next(mission)
  }
}

Now a child component can consume it and request a navigation:

export class SomeChild {
   constructor(navService: NavigationService) { }
   invoke() {
      this.navService.requestNaivation(new NavArgs('SomeRoute'));
   }
}

And a parent component can listen for said request and act on it:

export class SomeParent {
   constructor(navService: NavigationService, router: Router) {
      this.navService
          .onNavigationRequested$
          .subscribe((navArgs: NavArgs) => {
              if (navArgs) {
                  if (navArgs.args) {
                      this.router.navigate([ navArgs.routeName, navArgs.args ]);
                  }
                  else {
                      this.router.navigate([ navArgs.routeName ]);
                  }
              }
      });
   }       
}

Obviously this is the very basic code example, there would need to be more imports and error handling and such. But hopefully you get the idea.

Note

It is important to ensure that both the parent and child use the same instance of this service, in order to do that - you must set it as a provider at the highest level where it is being used. That is because by default Angular2 creates a singleton for DI and uses a hierarchical approach. You must ensure that you do not mistakenly set it as a provider at a lower level, otherwise it will not work.

like image 44
David Pine Avatar answered Oct 04 '22 00:10

David Pine