Last active
October 16, 2024 04:59
-
-
Save katowulf/2145adce2423d1b2f984555a6c1e87fb to your computer and use it in GitHub Desktop.
Dynamically set page title based on active route in Angular 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This can probably be simplified somehow. Not sure why I need to add it in the component to init the service. | |
import { Component, OnInit } from '@angular/core'; | |
import {TitleService} from "./@core/utils/title.service"; | |
@Component({...}) | |
export class AppComponent implements OnInit { | |
constructor(private titleService: TitleService) {...} | |
ngOnInit(): void { | |
this.titleService.init(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ... | |
@NgModule({ | |
... | |
providers: [ TitleService ], | |
}) | |
export class AppModule { ... } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// If a route is declared with a title attribute, it gets used, otherwise we just try to parse the url fragment | |
// Here's where the title attribute goes | |
const routes: Routes = [{ | |
path: '', | |
component: HomeComponent, | |
data: {title: "My Home Page"}, | |
}, { | |
path: 'detail/:id', | |
component: DetailComponent, | |
}]; | |
@NgModule({ | |
imports: [RouterModule.forChild(routes)], | |
exports: [RouterModule], | |
}) | |
export class ExampleRoutingModule { | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Credits and thanks: | |
// https://toddmotto.com/dynamic-page-titles-angular-2-router-events | |
// https://stackoverflow.com/questions/34597835/how-to-get-current-route | |
import { Injectable } from '@angular/core'; | |
import 'rxjs/add/operator/filter'; | |
import 'rxjs/add/operator/map'; | |
import 'rxjs/add/operator/mergeMap'; | |
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router'; | |
import { Title } from '@angular/platform-browser'; | |
const APP_TITLE = 'NoDice!'; | |
const SEPARATOR = ' > '; | |
@Injectable() | |
export class TitleService { | |
constructor( | |
private router: Router, | |
private activatedRoute: ActivatedRoute, | |
private titleService: Title, | |
) {} | |
init() { | |
this.router.events | |
.filter((event) => event instanceof NavigationEnd) | |
.map(() => { | |
let route = this.activatedRoute; | |
while (route.firstChild) route = route.firstChild; | |
return route; | |
}) | |
.filter((route) => route.outlet === 'primary') | |
.mergeMap((route) => route.data) | |
.map((data) => { | |
if ( data.title ) { | |
// If a route has a title set (e.g. data: {title: "Foo"}) then we use it | |
return data.title; | |
} else { | |
// If not, we do a little magic on the url to create an approximation | |
return this.router.url.split('/').reduce((acc, frag) => { | |
if ( acc && frag ) { acc += SEPARATOR; } | |
return acc + TitleService.ucFirst(frag); | |
}); | |
} | |
}) | |
.subscribe((pathString) => this.titleService.setTitle(`${APP_TITLE} ${pathString}`)); | |
} | |
static ucFirst(string) { | |
if ( !string ) { return string; } | |
return string.charAt(0).toUpperCase() + string.slice(1); | |
} | |
} |
Very good
working fine,thank You
Thanks. I made a few changes to have more conceptual titles.
import { Injectable } from '@angular/core';
import { map, filter } from 'rxjs/operators';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';
const APP_TITLE = 'Title';
const SEPARATOR = ' > ';
@Injectable({
providedIn: 'root'
})
export class TitleService {
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title,
) { }
static ucFirst(text: string) {
if (!text) { return text; }
return text.charAt(0).toUpperCase() + text.slice(1);
}
init() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => {
let route = this.activatedRoute;
while (route.firstChild) { route = route.firstChild; }
return route;
}),
filter((route) => route.outlet === 'primary'),
map((route) => route.snapshot),
map((snapshot) => {
if (snapshot.data.title) {
if (snapshot.paramMap.get('id') !== null) {
return snapshot.data.title + SEPARATOR + snapshot.paramMap.get('id');
}
return snapshot.data.title;
} else {
// If not, we do a little magic on the url to create an approximation
return this.router.url.split('/').reduce((acc, frag) => {
if (acc && frag) { acc += SEPARATOR; }
return acc + TitleService.ucFirst(frag);
});
}
}))
.subscribe((pathString) => this.titleService.setTitle(`${pathString} - ${APP_TITLE}`));
}
}
Just leaving a comment on how this thing saved me today.
Kudos for the op @katowulf
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
Thanks for that.
I had to modify it a bit for Angular 6,
You may check my fork & update if you like...