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?
Prefix the route name with a slash to indicate that the route is a root route
this.router.navigate(['/About']);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With