4

I have an angular 6 application where i want to store the page title on every route change,

import { Router, NavigationEnd, NavigationStart, RoutesRecognized } from '@angular/router';

export class AppComponent implements OnInit {

    constructor (
        public router: Router
    ) {
    }

    ngOnInit() {
          this.router.events.subscribe(event => {

      if (event instanceof NavigationStart) {
        // console.log('Starting Navigation');
      }

      if (event instanceof NavigationEnd) {
        console.log('Ending Navigation ', document.title);
      }
  });
    }

the issue is whenever i want to access the title of the current page , it shows the previous title set but not the new title which is being set dynamically from the component level

Any suggestion how to fix this ?

user4965201
  • 973
  • 1
  • 11
  • 25
  • you can use a root provided service to set page's title and subscribe to the changes in the same service – Alon Yampolski Oct 03 '19 at 12:19
  • you can inject Title service provided by Angular framework, it has a function getTitle() which gives the title of current component. More info - https://angular.io/guide/set-document-title – Hemendra Oct 03 '19 at 12:21

5 Answers5

1

You can use the Title class in @angular/platform-browser,

Import statement

import{Title} from '@angular/platform-browser'

Inject it in the constructor

constructor(private title:Title){ }

Your router event subscription will look like

this.router.events.subscribe(event => {

      if (event instanceof NavigationStart) {
        // console.log('Starting Navigation');
      }

      if (event instanceof NavigationEnd) {
        alert(this.title.getTitle())
      }
  });
Aravind
  • 40,391
  • 16
  • 91
  • 110
1

I think you try to access the document title before it got reset by component level.

When you navigate to a route the router emits an event and after that the component gets initialized and your title will be reset here if I understood you correctly.

You can provide title data in your route for example:

const routes: Routes = [
    {
        path: 'my/route',
        component: MyComponent,
        data: {
           documentTitle: 'YOUR TITLE'
        }
    }
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class MyRouterModule { }
JuNe
  • 1,911
  • 9
  • 28
0

What if you do it using pure javascript so in your app constructor

 new MutationObserver(function(mutations) {
    console.log(mutations[0].target.nodeValue);
}).observe(
    document.querySelector('title'),
    { subtree: true, characterData: true }
);

demo

reference so1 reference 2

jitender
  • 10,238
  • 1
  • 18
  • 44
0

Are you setting your title in the router, or in a component?

UPDATE: I’ve just re-read the original question, and you do mention the page title is in your component. I tried like heck to get app.component.ts to retrieve the dynamic page title which was set in the currently displayed component, but was unable to do so. I experienced the same behavior that you described in your question: it kept returning the title from the previously clicked page, even when I tried to grab the title from the DOM document object.

I had to move my page title from the page component to app.routing-module.js to get app.component.ts to retrieve the correct current title.

Like you, I needed my title to be dynamic. I have Angular 14 and was able to set a dynamic title in the router via a resolver, and use the new TitleStrategy.getResolvedTitleForRoute() to return the title.

If you are still using an older version of Angular, then the below method will work for you … you just have to figure out how to set a title dynamically in the routing module :-)

ACCESSING CURRENT PAGE TITLE FROM APP.COMPONENT.TS VIA THE ROUTER

Let's say your app-routing module looks something like this...

app-routing.module.ts

const routes: Routes = [
  {
    path: 'posts/:postId',
    component PostDetailPageComponent,
    data: { title: 'My App - Post Page' }
  },
  { 
    path: 'users/:userId',
    component: UserDetailComponent,
    data: { title: 'My App - User Page' }

]

You should be able to access the titles in app.component.ts this way:

app.component.ts

import { Component } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router, RouterState } from '@angular/router';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  title = 'My Generic Title';

  constructor(private router: Router) { this.handleRouteEvents() }
  
  handleRouteEvents() {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        const p_title = this.getTitle(this.router.routerState, this.router.routerState.root).join('-');
        const p_path = event.urlAfterRedirects;
        const p_location = this._document.location.href;
                
        console.log('p_title: |', p_title, '|');
        console.log('p_path: ', p_path);
        console.log('p_location: ', p_location);
        
      }
    });
  }

  getTitle(state: RouterState, parent: ActivatedRoute): string[] {
    const data = [];
    
    if (parent && parent.snapshot.data && parent.snapshot.data['title']) {
      data.push(parent.snapshot.data['title']);
    }
    if (state && parent && parent.firstChild) {
      data.push(...this.getTitle(state, parent.firstChild));
    }
    return data;
  }
}

I hope this helps you out!

-1

You can set the title in you child's component constructor:

constructor() { 
    document.title =  "newTitle";
}

or even better, as suggested in one of the answers:

constructor(private titleService: Title) { 
    this.titleService.setTitle("newTitle");
}
NikNik
  • 2,191
  • 2
  • 15
  • 34