B Hull
B Hull

Reputation: 3223

how to change page title in angular2 router

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 {}

Upvotes: 60

Views: 47908

Answers (15)

Gokul Kadnar
Gokul Kadnar

Reputation: 21

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"
  }
];

Upvotes: 0

asmmahmud
asmmahmud

Reputation: 5044

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+.

Upvotes: 13

emcee22
emcee22

Reputation: 1889

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'} }

Upvotes: 0

Mujahid
Mujahid

Reputation: 127

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);
    });

}

Upvotes: 2

Ajitesh Sinha
Ajitesh Sinha

Reputation: 41

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));
   }

Upvotes: 0

Suhel
Suhel

Reputation: 957

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']);
    })
  }

Upvotes: 3

Dudi
Dudi

Reputation: 3079

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);
        });

    }


}

Upvotes: 2

drew moore
drew moore

Reputation: 32680

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:

Upvotes: 60

Martin Cremer
Martin Cremer

Reputation: 5572

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'
  }
}

Upvotes: 18

Devner
Devner

Reputation: 7255

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');
  }

}

Upvotes: 2

Burak Tasci
Burak Tasci

Reputation: 907

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.

Upvotes: 0

Ali Adravi
Ali Adravi

Reputation: 22743

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

Upvotes: 5

John
John

Reputation: 17481

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;
}

Upvotes: 3

Yoav Schniederman
Yoav Schniederman

Reputation: 5391

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');
   }
}

Upvotes: 3

Shailesh  kala
Shailesh kala

Reputation: 1852

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:

https://github.com/vinaygopinath/ng2-meta

Upvotes: 11

Related Questions