14

In my app Im trying to dynamically change the title in my header component depending on the page that Im on, so In my header component I want to use a

<h1>{{title}}</h1>

and I want it to change depending on the page that I am on. Now the header is fixed so it's on every page

below is an image of what im trying to change enter image description here

Basically if im on the home page I want it to say home and then if Im on an about page I want it to change to about..

Not sure how I can go about this and everything ive researched has been to change the title in the <head></head> tags

Smokey Dawson
  • 8,827
  • 19
  • 77
  • 152

5 Answers5

26

You can create a service dedicated for updating the title in your header component. Simply inject the service in your header component and subscribe to a dedicated BehaviorSubject. Then you can inject this service in any component you have and use the setTitle method from that component which will update the title in the header component. Check out the following code

//headerTitle.service.ts
@Injectable()
export class headerTitleService {
  title = new BehaviorSubject('Initial Title');

  setTitle(title: string) {
    this.title.next(title);
  }
}

//header.component.ts
title = '';

constructor(private headerTitleService: HeaderTitleService) {}

ngOnInit() {
  this.headerTitleService.title.subscribe(updatedTitle => {
    this.title = updatedTitle;
  });
}

//header.component.html
<h1>{{title}}</h1>

//about.component.ts
constructor(private headerTitleService: HeaderTitleService) {}

ngOnInit() {
  this.headerTitleService.setTitle('About');
}

Working demo

Aamir Khan
  • 2,945
  • 2
  • 25
  • 32
  • In my header component I want to be able to have a `

    {{title}}

    ` and `title` being the heading of the page depending on the page Im on so If im on an about page I want the h1 to be like `

    About Page

    `
    – Smokey Dawson Nov 13 '17 at 05:00
  • Igot an error `Cannot find name 'BehaviorSubject'.` – Smokey Dawson Nov 13 '17 at 05:45
  • How do I subscribe to BehaviorSubject? – Smokey Dawson Nov 13 '17 at 05:46
  • You will have to import it `import {BehaviorSubject} from 'rxjs/subject/BehaviorSubject';` – Aamir Khan Nov 13 '17 at 05:46
  • import it into my service? – Smokey Dawson Nov 13 '17 at 05:46
  • im getting the error `cannot find module 'rxjs/subject/BehaviorSubject';` – Smokey Dawson Nov 13 '17 at 05:47
  • My bad, the current import should be `import { BehaviorSubject } from 'rxjs/BehaviorSubject';`. And yes, you must import it into your service. – Aamir Khan Nov 13 '17 at 05:48
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158825/discussion-between-a61nn5-and-aamir-khan). – Smokey Dawson Nov 13 '17 at 05:52
  • 2
    Works, but always throws an error: `ERROR Error: "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.` - any idea how to fix this? – Patric Jun 24 '19 at 22:26
  • @Tagas I am also getting the same error ERROR Error: "ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. are you able to fix this issue? – Manu Sep 29 '20 at 13:34
  • @Patric @Manu as angular video you can make the change component to be in setTimeOut like this `setTimeout(() => { this.headerTitleService.setTitle('About'); }, 0);` – Samir Nabil Jan 02 '23 at 08:31
2

Use the title service in @angular/platform-browser and add router component with data property.

const appRoutes: Routes = [
  { path: 'home',component:HomeComponent , data:{title:'Home'}}

  ];

Call this function in the root component

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)
      .subscribe((event) => this.titleService.setTitle(event['title']));
  }
}
1

use title service in browser platform to change the title dynamically. refer this link for more information

app.module.ts

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

app.component.ts

// Import the native Angular services.
import { Component } from '@angular/core';
import { Title }     from '@angular/platform-browser';

@Component({
selector: 'app-root',
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 );
  }
}
Prithivi Raj
  • 2,658
  • 1
  • 19
  • 34
0

Based on OP's requirement, it seems OP needs to bind a string property to the page.

In your component have a property. Since its a fix string you can initialize it on each component like:

 public title:string = 'About me';

and in your HTML just:

<h1>{{title}}</h1>

Update:

Since it is to be bound to a constant header component, you will have to emit an event from each component using EventEmitter and listen to it across multiple components in your app and accordingly update the title property.

As suggested by Aamir in comments: You can have a service, wherein you can create an Observable and then update its next value in each component. The observable can then be subscribed in the header component to update the title property.

Saurabh Tiwari
  • 4,632
  • 9
  • 42
  • 82
0

You can achive this by subscribing to Router events as follows

private setTitleFromRouteData(routeData) {
    if (routeData && routeData['title']) {
        this.pageTitle = routeData['title'];
    } else {
        this.pageTitle = 'No title';
    }
}

private getLatestChild(route) {
    while (route.firstChild) {
        route = route.firstChild;
    }
    return route;
}

private subscribeToRouteChangeEvents() {
    // Set initial title
    const latestRoute = this.getLatestChild(this.activeRoute);
    if (latestRoute) {
        this.setTitleFromRouteData(latestRoute.data.getValue());
    }
    this.router.events.pipe(
        filter(event => event instanceof NavigationEnd),
        map(() => this.activeRoute),
        map((route) => this.getLatestChild(route)),
        filter((route) => route.outlet === 'primary'),
        mergeMap((route) => route.data),
    ).subscribe((event) => {
        this.setTitleFromRouteData(event);
    });
}

I have written a complete tutorial on this matter - https://medium.com/@CROSP/page-specific-dynamic-angular-components-using-child-routes-40f3cc47ce10

CROSP
  • 4,499
  • 4
  • 38
  • 89