I'm trying to get the data from a Router whenever the Route changes but I'm not having success. Here I set the asdf
property
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent,
LoginComponent,
DashboardComponent,
OverviewComponent,
],
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot([
{ path: '', pathMatch: 'full', redirectTo: '' },
{ component: LoginComponent, path: 'login' },
{
children: [
{ path: '', pathMatch: 'full', redirectTo: 'overview', data: { asdf: 'hello' } },
{ component: OverviewComponent, path: 'overview', data: { asdf: 'hello' } },
], component: DashboardComponent,
path: '',
},
]),
],
})
export class AppModule { }
And here I can get the URL from the router when the route changes but asdf
is undefined :(
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { ActivatedRoute, NavigationEnd } from '@angular/router';
@Component({
selector: 'cs-map',
styleUrls: ['map.component.css'],
templateUrl: 'map.component.html',
})
export class MapComponent implements OnInit {
private routerSub;
constructor(private router: Router, private activatedRoute: ActivatedRoute) { }
public ngOnInit() {
this.router.events.subscribe((val) => {
if (val instanceof NavigationEnd) {
let url = val.url;
console.log(this.activatedRoute.snapshot.data['asdf']); // data is defined but asdf is not :(
}
});
}
}
How can I get asdf
's value?
Edit: I'm navigating to /overview
You can use the activated route to get active URL. (<RouterStateSnapshot>activatedRoute['_routerState']). url , if you like to type it.
ActivatedRoutelink. Provides access to information about a route associated with a component that is loaded in an outlet.
Something like this:
constructor(private router: Router,
private activatedRoute: ActivatedRoute)
{
this.router.events
.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => route.firstChild)
.switchMap(route => route.data)
.map(data => data['asdf'])
}
The following is updated to work with rxjs v6
constructor(private router: Router,
private activatedRoute: ActivatedRoute)
{
this.router.events
.pipe(
filter(event => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map(route => route.firstChild),
switchMap(route => route.data),
map(data => data['asdf']))
}
Here is a modified example using @Neelavar link example.
It might look long but it's simple, be patient, if you stick through it, it should work. Just following the steps outlined should take a few minutes.
In your routes array (you will find this either in app.module.ts or app-routes.module.ts or in some cases a routes.ts file).
If you can't find this, check basic routing setup in:
a basic setup is all you need!
export const routes: Routes = [
{ path: 'home', component: HomeComponent, data: {title: 'home'} },
{ path: '', pathMatch: 'full', redirectTo: '/home' },
];
RouteData.ts, I have it in the same folder space as app.module.ts
export class RouteData {
title: string;
}
This is just to add types for using the observable in typescript, the IDE can then autocomplete "title" or "id" or "animation" for me if I add that to the data class later.
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
import { RouteData } from './route-data';
Then above the constructor code, declare the variable
routeData$: Observable<RouteData>;
Then inside the constructor
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
) {}
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
) {
this.routeData$ = router.events.pipe(
filter(routeEvent => routeEvent instanceof NavigationEnd),
map(() => activatedRoute),
map(activatedRoute => activatedRoute.firstChild),
switchMap(firstChild => firstChild.data),
map((data: RouteData) => data)
);
}
Explanation of code adapted from @Tuizi link Example Comment:
For every event from router, filter only for the NavigationEnd event (when the router has completed navigation).
Then map (return) the currently activatedRoute.
Map the activatedRoute to the firstChild (The first child of this route in the router state tree).
Then a switchMap emits the data of this route, use a switchMap because each "data" that is emitted is an observable, the switch map will cancel the old observable when a new one is emitted, saving memory.
Map (return) the data object, assign it a type of RouteData.
Finally you can use this Observable in a template using async pipe
<span *ngIf="routeData$ | async as routeData">
{{ routeData.title | titlecase }}
</span>
*A note: "async as" breaks type checking in the template at the moment :(
github issue
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