问题
I have defined a number of routes as follows:
export const AppRoutes: Routes = [
{path: '', component: HomeComponent, data: {titleKey: 'homeTitle'}},
{path: 'signup', component: SignupComponent, data: {titleKey: 'SIGNUP_FORM.TITLE'}},
{path: 'signin', component: SigninComponent, data: {titleKey: 'SIGNIN_FORM.TITLE'}},
{path: 'sendpasswordresetinformation', component: SendPasswordResetInformationComponent},
{path: 'password/reset/:userAccountToken', component: PasswordResetComponent},
{
path: 'dashboard', component: DashboardComponent, children: [
{path: '', component: DashboardSummaryComponent},
{
path: 'message', children: [
{path: '', component: MessageSummaryComponent, data: {titleKey: 'MESSAGE_LIST.TITLE'}},
{path: 'conversation/:otherId', component: MessageConversationComponent, data: {titleKey: 'XXX'}}]
},
{
path: 'useraccount', component: UserAccountComponent, children: [
{
path: '',
component: UserAccountSummaryComponent,
data: {titleKey: 'XXX'},
resolve: {
userAccount: UserAccountResolve
}
},
{path: 'address', component: UserAccountAddressComponent, data: {titleKey: 'ADDRESS_FORM.TITLE'}},
{path: 'email', component: UserAccountEmailComponent, data: {titleKey: 'EMAIL_FORM.TITLE'}},
{
path: 'emailnotification',
component: UserAccountEmailNotificationComponent,
data: {titleKey: 'EMAIL_NOTIFICATION_FORM.TITLE'}
},
{path: 'firstname', component: UserAccountFirstNameComponent, data: {titleKey: 'FIRST_NAME_FORM.TITLE'}},
{path: 'password', component: UserAccountPasswordComponent, data: {titleKey: 'PASSWORD_FORM.TITLE'}}]
}]
}];
Some of the routes are children of others.
I would like to find a way to retrieve the titleKey
property on data
regardless of whether the route is a top level route or the child of another.
Here is what I have tried:
export class AppComponent implements OnInit {
constructor(private translate: TranslateService,
private sessionService: SessionService,
private titleService: Title,
private activatedRoute: ActivatedRoute) {
let userLang = 'fr';
translate.use(userLang);
moment.locale(userLang);
}
ngOnInit() {
this.sessionService.reloadPersonalInfo();
}
setTitle($event) {
this.translate.get(this.activatedRoute.snapshot.data['titleKey'])
.subscribe(translation=>this.titleService.setTitle(translation));
}
}
this.activatedRoute.snapshot.data['titleKey']
is undefined
.
Can someone please advise how to retrieve a property on route data
regardless of the level of nesting of the route?
edit: After reading the official angular documentation about ActivatedRoute, I tried to use the map
operator on the data property of the ActivatedRoute
instance as follows:
@Component({
selector: 'app',
template: `
<section class="container-fluid row Conteneur">
<appNavbar></appNavbar>
<section class="container">
<router-outlet (activate)="setTitle($event)"></router-outlet>
</section>
</section>
<section class="container-fluid">
<appFooter></appFooter>
</section>
`,
directives: [NavbarComponent, FooterComponent, SigninComponent, HomeComponent, ROUTER_DIRECTIVES]
})
export class AppComponent implements OnInit {
constructor(private translate: TranslateService,
private sessionService: SessionService,
private titleService: Title,
private activatedRoute: ActivatedRoute) {
let userLang = 'fr';
translate.use(userLang);
moment.locale(userLang);
}
ngOnInit() {
this.sessionService.reloadPersonalInfo();
}
setTitle($event) {
this.activatedRoute.data.map(data=>data['titleKey'])
.do(key=>console.log(key))
.switchMap(key=>this.translate.get(key))
.subscribe(translation=>this.titleService.setTitle(translation));
}
}
and yet key
is always undefined...
回答1:
I stumbled on a nice tutorial with a clean solution: https://toddmotto.com/dynamic-page-titles-angular-2-router-events.
Here is what I finally came up with using the solution from the above tutorial and using the ng2 translate service in order to convert the titleKeys
specified in my route data into proper labels:
@Component({
selector: 'app',
encapsulation: ViewEncapsulation.None,
styleUrls: ['../styles/bootstrap.scss'],
template: `<section class="container-fluid row Conteneur">
<app-navbar></app-navbar>
<section class="container">
<router-outlet></router-outlet>
</section>
</section>
<section class="container-fluid">
<app-footer></app-footer>
</section>`
})
export class AppComponent implements OnInit {
constructor(private translate: TranslateService,
private sessionSigninService: SessionSigninService,
private titleService: Title,
private router: Router,
private activatedRoute: ActivatedRoute) {
let userLang = 'fr';
translate.use(userLang);
moment.locale(userLang);
}
ngOnInit() {
this.router.events
.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter(route => route.outlet === 'primary')
.mergeMap(route => route.data)
.mergeMap(data => this.translate.get(data['titleKey']))
.subscribe(translation => this.titleService.setTitle(translation));
}
}
回答2:
We had this same problem. We decided to go about it another way. Instead of trying to listen for the data emits on the ActivatedRoute, we subscribe to the events
Observable on the router itself:
import { Component } from "@angular/core";
import { NavigationEnd, Router } from "@angular/router";
declare var module: any;
@Component({
moduleId: module.id,
selector: "app-layout",
templateUrl: "main-layout.component.html"
})
export class LayoutComponent {
titleKey: string;
constructor(private router: Router){}
ngOnInit() {
this.router.events
.filter((event: any) => event instanceof NavigationEnd)
.subscribe(() => {
var root = this.router.routerState.snapshot.root;
while (root) {
if (root.children && root.children.length) {
root = root.children[0];
} else if (root.data && root.data["titleKey"]) {
this.titleKey = root.data["titleKey"];
return;
} else {
return;
}
}
});
}
}
Note that we're using the value in a component that is used at the top level but needs the data from the deepest child route. You should be able to pretty easily convert this to a service that emits events whenever the titleKey
changes value.
Hope this helps.
回答3:
Update
You may try below in AppComponent
,
constructor(private translate: TranslateService,
private sessionService: SessionService,
private titleService: Title,
private activatedRoute: ActivatedRoute) {
this.router.events.subscribe((arg) => {
if(arg instanceof NavigationEnd) {
console.log(this.getTitle(this.activatedRoute.snapshot));
}
});
}
getTitle = (snapshot) => {
if(!!snapshot && !!snapshot.children && !!snapshot.children.length > 0){
return this.getTitle(snapshot.children[0]);
}
else if(!!snapshot.data && !!snapshot.data['titleKey']){
return snapshot.data['titleKey'];
}
else{
return '';
}
}
seems little hacky but works.
Old
You may try below,
{
path: 'conversation/:otherId',
component: MessageConversationComponent,
data: {titleKey: 'XXX'},
// add below resolve
resolve: {
titleKey: MessageConversationResolve
}
}
add a new service MessageConversationResolve.ts and add it appropriately in providers.
import { Injectable } from '@angular/core';
import { Router, Resolve,ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AdminDetailResolve implements Resolve<any> {
constructor(private router: Router,
private titleService: Title) {}
resolve(route: ActivatedRouteSnapshot): Observable<any> | Promise<any> | any {
// route.data will give you the titleKey property
// console.log(route.data);
// you may consume titleService here to setTitle
return route.data.titleKey;
}
}
Below is angular version which supports above solution,
Angular 2 version : 2.0.0-rc.5
Angular Router version : 3.0.0-rc.1
Hope this helps!!
来源:https://stackoverflow.com/questions/38877123/retrieving-a-data-property-on-an-angular2-route-regardless-of-the-level-of-route