I am trying to change the page title from the router, can this be done?
import {RouteConfig} from 'angular2/router';
@RouteConfig([
{path: '/home', component: HomeCmp, name: 'HomeCmp' }
])
class MyApp {}
I am trying to change the page title from the router, can this be done?
import {RouteConfig} from 'angular2/router';
@RouteConfig([
{path: '/home', component: HomeCmp, name: 'HomeCmp' }
])
class MyApp {}
The Title
service @EricMartinez points out has a setTitle()
method - that's all you need to set the title.
In terms of doing it automatically on route changes, as of now there's no built-in way of doing this other than subscribing to Router
and calling setTitle()
in your callback:
import {RouteConfig} from 'angular2/router';
import {Title} from 'angular2/platform/browser';
@RouteConfig([
{path: '/home', component: HomeCmp, name: 'HomeCmp' }
])
class MyApp {
constructor(router:Router, title:Title) {
router.events.subscribe((event)=>{ //fires on every URL change
title.setTitle(getTitleFor(router.url));
});
}
}
That said, I emphasize as of now because the router is still under heavy development, and I expect (or at least hope) that we'll be able to do this via RouteConfig
in the final release.
EDIT:
As of the release of Angular 2 (2.0.0), a few things have changed:
Title
service are now here: https://angular.io/docs/ts/latest/api/platform-browser/index/Title-class.html'@angular/platform-browser'
router.subscribe
is now router.events.subscribe
in Angular2 –
Cavin getTitleFor(url)
this method returns what ? i.e value of name
in router config ? –
Extranuclear getTitleFor()
is no longer a thing. –
Pertain Here's my approach which works fine, especially for nested routes:
I use a recursive helper method to grab the deepest available title after a route has changed:
@Component({
selector: 'app',
template: `
<h1>{{title | async}}</h1>
<router-outlet></router-outlet>
`
})
export class AppComponent {
constructor(private router: Router) {
this.title = this.router.events
.filter((event) => event instanceof NavigationEnd)
.map(() => this.getDeepestTitle(this.router.routerState.snapshot.root));
}
title: Observable<string>;
private getDeepestTitle(routeSnapshot: ActivatedRouteSnapshot) {
var title = routeSnapshot.data ? routeSnapshot.data['title'] : '';
if (routeSnapshot.firstChild) {
title = this.getDeepestTitle(routeSnapshot.firstChild) || title;
}
return title;
}
}
This is assuming, that you have assigned page titles within the data property of your routes, like this:
{
path: 'example',
component: ExampleComponent,
data: {
title: 'Some Page'
}
}
router.routeSnapshot.root.data
, but it appears that it can be nested based on how the route is setup. This answer worked for me. –
Puppet this.title = this.getDeepestTitle(this.activatedRoute.snapshot.root);
for this to work on the first visit. –
Quillen For Angular 4+:
If you want to use route custom data to define page title for every route path, the following approach will work for the nested routes and with angular version 4+:
You can pass page title in your route definition:
{path: 'home', component: DashboardComponent, data: {title: 'Home Pag'}},
{path: 'about', component: AboutUsComponent, data: {title: 'About Us Page'}},
{path: 'contact', component: ContactUsComponent, data: {title: 'Contact Us Pag'}},
Now, most important in your upper level component (ie AppComponent
), you can globally catch the route custom data on every route change and update the page title:
import {Title} from "@angular/platform-browser";
import { filter, map } from 'rxjs/operators';
export class AppComponent implements OnInit {
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private titleService: Title
) { }
ngOnInit() {
this.router
.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => {
let child = this.activatedRoute.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['title']) {
return child.snapshot.data['title'];
} else {
return null;
}
}
return null;
})).subscribe( (title: any) => {
this.titleService.setTitle(title);
});
}
The above code is tested against angular verion 4+.
import { BrowserModule, Title } from '@angular/platform-browser';
and set the providers: [Title]
in the Module, and also have to add import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map';
in the Component. Otherwise you can get some errors. –
Endodontics Its really very easy to do this, you can follow therse steps to see the immediate effects:
we provide the Title service in bootstrap:
import { NgModule } from '@angular/core';
import { BrowserModule, Title } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
],
providers: [
Title
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Then import this service in the component you want:
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
@Component({
selector: 'my-app',
template:
`<p>
Select a title to set on the current HTML document:
</p>
<ul>
<li><a (click)="setTitle( 'Good morning!' )">Good morning</a>.</li>
<li><a (click)="setTitle( 'Good afternoon!' )">Good afternoon</a>.</li>
<li><a (click)="setTitle( 'Good evening!' )">Good evening</a>.</li>
</ul>
`
})
export class AppComponent {
public constructor(private titleService: Title ) { }
public setTitle( newTitle: string) {
this.titleService.setTitle( newTitle );
}
}
now click on those links to see the title changing.
you can also use ng2-meta for changing page title and description as well,you can refer to this link:
Title
service of angular2 extra in your code, thanks for answer. –
Mcgannon Angular 2 provides a Title Service see Shailesh answer is just copy of that code.
I our app.module.ts
import { BrowserModule, Title } from '@angular/platform-browser';
........
providers: [..., Title],
bootstrap: [AppComponent]
Now move to our app.component.ts
import { Title } from '@angular/platform-browser';
......
export class AppComponent {
public constructor(private titleService: Title ) { }
public setTitle( newTitle: string) {
this.titleService.setTitle( newTitle );
}
}
Put the title tag on your component html and it will read and set for you.
If you want to know how to set it dynamically and further detail see this article
import {Title} from "@angular/platform-browser";
@Component({
selector: 'app',
templateUrl: './app.component.html',
providers : [Title]
})
export class AppComponent implements {
constructor( private title: Title) {
this.title.setTitle('page title changed');
}
}
This is what I went with:
constructor(private router: Router, private title: Title) { }
ngOnInit() {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.title.setTitle(this.recursivelyGenerateTitle(this.router.routerState.snapshot.root).join(' - '));
}
});
}
recursivelyGenerateTitle(snapshot: ActivatedRouteSnapshot) {
var titleParts = <string[]>[];
if (snapshot) {
if (snapshot.firstChild) {
titleParts = titleParts.concat(this.recursivelyGenerateTitle(snapshot.firstChild));
}
if (snapshot.data['title']) {
titleParts.push(snapshot.data['title']);
}
}
return titleParts;
}
reverse()
), this.title.setTitle(this.title.getTitle().split(' - ')[0] + ' - ' + this.recursivelyGenerateTitle(this.router.routerState.snapshot.root).reverse().join(' - '));
. –
Garrett unshift()
instead of push()
and then reverse()
. –
Garrett Angular 6+ I have modify the old code using new Pipe() and its working fine.
import { Title } from '@angular/platform-browser';
import { filter, map, mergeMap } from 'rxjs/operators';
...
constructor(
private router: Router,
public activatedRoute: ActivatedRoute,
public titleService: Title,
) {
this.setTitle();
}
....
setTitle() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route: any) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route: any) => route.data)).subscribe((event) => {
this.titleService.setTitle(event['title']);
console.log('Page Title', event['title']);
})
}
Here's the simplest way to change the Title of the page, when pages/views are navigated (Tested as of Angular @2.3.1). Simply apply the following solution to all the views you have and you should be good to go:
Example Code in About Us page/view:
import {Title} from "@angular/platform-browser";
export class AboutUsComponent implements OnInit {
constructor(private _titleService: Title) {
}
ngOnInit() {
//Set page Title when this view is initialized
this._titleService.setTitle('About Us');
}
}
Example Code in Contact Us page/view:
import {Title} from "@angular/platform-browser";
export class ContactusComponent implements OnInit {
constructor(private _titleService: Title) {
}
ngOnInit() {
//Set page Title
this._titleService.setTitle('Contact Us');
}
}
In the below example:
-We added object of data: { title: 'NAME' } to any routing object.
-We set a basic name ("CTM") for uploading time (when clicking F5 for Refreash..): <title>CTM</title>
.
-We added "TitleService" class.
-we handle Routher events by filtering them from app.component.ts.
index.html:
<!DOCTYPE html>
<html>
<head>
<base href="/">
<title>CTM</title>
</head>
...
app.module.ts:
import { NgModule, enableProdMode } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TitleService } from './shared/title.service';
...
@NgModule({
imports: [
BrowserModule,
..
],
declarations: [
AppComponent,
...
],
providers: [
TitleService,
...
],
bootstrap: [AppComponent],
})
export class AppModule { }
enableProdMode();
title.service.ts:
import { Injectable } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRouteSnapshot } from '@angular/router';
@Injectable()
export class TitleService extends Title {
constructor() {
super();
}
private recursivelyGenerateTitle(snapshot: ActivatedRouteSnapshot) {
var titleParts = <string[]>[];
if (snapshot) {
if (snapshot.firstChild) {
titleParts = this.recursivelyGenerateTitle(snapshot.firstChild);
}
if (snapshot.data['title']) {
titleParts.push(snapshot.data['title']);
}
}
return titleParts;
}
public CTMGenerateTitle(snapshot: ActivatedRouteSnapshot) {
this.setTitle("CTM | " + this.recursivelyGenerateTitle(snapshot).join(' - '));
}
}
app-routing.module.ts:
import { Injectable } from '@angular/core';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MainComponent } from './components/main.component';
import { Router, CanActivate } from '@angular/router';
import { AuthGuard } from './shared/auth/auth-guard.service';
import { AuthService } from './shared/auth/auth.service';
export const routes: Routes = [
{ path: 'dashboard', component: MainComponent, canActivate: [AuthGuard], data: { title: 'Main' } },
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { useHash: true }) // .../#/crisis-center/
],
exports: [RouterModule],
providers: [
..
]
})
export class AppRoutingModule { }
export const componentsOfAppRoutingModule = [MainComponent];
app.component.ts:
import { Component } from '@angular/core';
import { Router, NavigationEnd, ActivatedRouteSnapshot } from '@angular/router';
import { TitleService } from './shared/title.service';
@Component({
selector: 'ctm-app',
template: `
<!--<a [routerLink]="['/dashboard']">Dashboard</a>
<a [routerLink]="['/login']">Login</a>
<a [routerLink]="['/']">Rooting</a>-->
<router-outlet></router-outlet>
`
})
export class AppComponent {
constructor(private router: Router, private titleService: TitleService) {
this.router.events.filter((event) => event instanceof NavigationEnd).subscribe((event) => {
console.log("AppComponent.constructor: Setting HTML document's Title");
this.titleService.CTMGenerateTitle(this.router.routerState.snapshot.root);
});
}
}
Working fine in Angular 6 and 6+ with Pipe and map method instead of using filter
Step1: routing setup
{path: 'dashboard', component: DashboardComponent, data: {title: 'My Dashboard'}},
{path: 'aboutUs', component: AboutUsComponent, data: {title: 'About Us'}},
{path: 'contactUs', component: ContactUsComponent, data: {title: 'Contact Us Page'}},
step2: in your app.module.ts import module
import { BrowserModule, Title } from '@angular/platform-browser';
then in provider add providers: [title]
Step 3 In your main component import
import { Title } from "@angular/platform-browser";
import { RouterModule, ActivatedRoute, Router, NavigationEnd } from "@angular/router";
import { filter, map } from 'rxjs/operators';
constructor(private titleService: Title, private router: Router, private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.router.events.pipe(map(() => {
let child = this.activatedRoute.firstChild;
while (child) {
if (child.firstChild) {
child = child.firstChild;
} else if (child.snapshot.data && child.snapshot.data['title']) {
return child.snapshot.data['title'];
} else {
return null;
}
}
return null;
})).subscribe(title => {
this.titleService.setTitle(title);
});
}
I can also recommend @ngx-meta/core plugin plugin that I've just released, in the case if you're looking for a method to set page title and meta tags dynamically.
Angular 6+
if route configured as follow :-
Routes = [
{ path: 'dashboard',
component: DashboardComponent,
data: {title: 'Dashboard'}
}]
**Then in component constructor title can be set as follow :- **
constructor( private _titleService: Title, public activatedRoute: ActivatedRoute) {
activatedRoute.data.pipe(map(data => data.title)).subscribe(x => this._titleService.setTitle(x));
}
Simple generic way to set the title:
import { Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private titleService: Title
) {}
ngOnInit() {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
const { title } = this.activatedRoute.firstChild.snapshot.data;
this.titleService.setTitle(title);
}
});
}
}
where title
needs to be set on each route like:
{ path: '', component: WelcomeComponent, data: {title: 'Welcome to my app'} }
Simple, If you are using Angular Version greater than 14.0 you can simply put title in Routes array, Like -
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
title: "'My App - Home' // <-- Page title"
},
{
path: 'about',
component: AboutComponent,
title: "'My App - About Me' // <-- Page title"
}
];
© 2022 - 2024 — McMap. All rights reserved.
Title
service: angular.io/docs/ts/latest/api/platform-browser/index/… – Gentry