как изменить заголовок страницы в роутере angular2

Пытаюсь изменить заголовок страницы с роутера, можно ли это сделать?

import {RouteConfig} from 'angular2/router';
@RouteConfig([
  {path: '/home', component: HomeCmp, name: 'HomeCmp' }
])
class MyApp {}

person B Hull    schedule 05.01.2016    source источник
comment
Используйте службу заголовков. Я знаю, что там есть ответ, но не могу его найти.   -  person Eric Martinez    schedule 05.01.2016
comment
Новая ссылка на сервис Title: angular.io/ docs/ts/latest/api/platform-browser/index/   -  person weltschmerz    schedule 08.10.2016
comment
См. также stackoverflow.com/questions/38644314/   -  person Günter Zöchbauer    schedule 03.03.2017
comment
У меня была такая же проблема, и лучший ответ, который я нашел, был подтвержденным ответом на этот вопрос: stackoverflow.com/questions/38644314/   -  person moshtaba morsali    schedule 14.02.2018
comment
Новая ссылка на сервис Title angular.io/guide/set-document-title   -  person Alf Moh    schedule 13.08.2018


Ответы (13)


На Title сервис, на который указывает @EricMartinez имеет метод setTitle() — это все, что вам нужно для установки заголовка.

Что касается автоматического выполнения при изменении маршрута, на данный момент нет встроенного способа сделать это, кроме подписки на Router и вызывая setTitle() в обратном вызове:

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

Тем не менее, я подчеркиваю на данный момент, потому что маршрутизатор все еще находится в стадии интенсивной разработки, и я ожидаю (или, по крайней мере, надеюсь), что мы сможем сделать это через RouteConfig в финальном выпуске.

РЕДАКТИРОВАТЬ:

С момента выпуска Angular 2 (2.0.0) кое-что изменилось:

person drew moore    schedule 05.01.2016
comment
Также router.subscribe теперь router.events.subscribe в Angular2 - person Romesh; 07.12.2016
comment
getTitleFor(url) что возвращает этот метод? то есть значение name в конфигурации маршрутизатора? - person Kaleem Ullah; 02.02.2017
comment
Если я правильно читаю документы, getTitleFor() больше не существует. - person Brendan; 17.02.2017
comment
Я нашел этот ответ немного более подробным - person adamdport; 05.07.2017

Вот мой подход, который отлично работает, особенно для вложенных маршрутов:

Я использую рекурсивный вспомогательный метод, чтобы получить самый глубокий доступный заголовок после изменения маршрута:

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

Предполагается, что вы назначили заголовки страниц в свойстве данных ваших маршрутов, например:

{
  path: 'example',
  component: ExampleComponent,
  data: {
    title: 'Some Page'
  }
}
person Martin Cremer    schedule 07.11.2016
comment
Я искал свойство данных в router.routeSnapshot.root.data, но оказалось, что оно может быть вложенным в зависимости от того, как настроен маршрут. Этот ответ сработал для меня. - person The Muffin Man; 16.02.2017
comment
Мне пришлось добавить this.title = this.getDeepestTitle(this.activatedRoute.snapshot.root);, чтобы это работало при первом посещении. - person Mel; 23.01.2018

Для Angular 4+:

Если вы хотите использовать пользовательские данные маршрута для определения заголовка страницы для каждого пути маршрута, следующий подход будет работать для вложенных маршрутов и с угловой версией 4+:

Вы можете передать заголовок страницы в определении маршрута:

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

Теперь, что наиболее важно, в компоненте верхнего уровня (т.е. AppComponent) вы можете глобально перехватывать пользовательские данные маршрута при каждом изменении маршрута и обновлять заголовок страницы:

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

Приведенный выше код протестирован на угловой версии 4+.

person asmmahmud    schedule 11.10.2017
comment
Большой! Просто еще несколько дополнений. Обязательно добавьте import { BrowserModule, Title } from '@angular/platform-browser'; и установите providers: [Title] в модуле, а также добавьте import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map'; в компонент. В противном случае вы можете получить некоторые ошибки. - person BogdanD; 13.04.2018

Это действительно очень легко сделать, вы можете выполнить следующие шаги, чтобы увидеть немедленный эффект:

мы предоставляем сервис Title в бутстрапе:

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

Затем импортируйте этот сервис в нужный вам компонент:

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

теперь нажмите на эти ссылки, чтобы увидеть изменение названия.

вы также можете использовать ng2-meta для изменения заголовка и описания страницы, вы можете обратиться к этой ссылке:

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

person Shailesh kala    schedule 31.01.2017
comment
да, отличный ответ, с помощью этого мы также можем изменить заголовок и описание. Нет необходимости использовать Title дополнительный сервис angular2 в вашем коде, спасибо за ответ. - person Pardeep Jain; 31.01.2017
comment
@PardeepJain Будет ли это решение работать, даже если мое приложение загружается 4 секунды? Я использовал ng2-meta, и это не работает из-за времени загрузки моего приложения. (Я пробовал все, чтобы уменьшить время загрузки) - person AngularM; 08.02.2017
comment
Что, если пользователь введет URL-адрес страницы и нажмет Enter ИЛИ Обновит страницу, это сработает. Я вижу, вы копируете тот же код из документа :) angular. io/docs/ts/latest/cookbook/set-document-title.html - person Ali Adravi; 14.04.2017

Angular 2 предоставляет Title Service см. ответ Шайлеша просто копия этого кода.

Я наш app.module.ts

import { BrowserModule, Title } from '@angular/platform-browser';
........
providers: [..., Title],
bootstrap: [AppComponent]

Теперь перейдите к нашему 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 );
    }
}

Поместите тег заголовка в HTML-код вашего компонента, и он будет прочитан и установлен для вас.

Если вы хотите узнать, как установить его динамически и подробнее см. в этой статье

person Ali Adravi    schedule 14.04.2017

Вот с чем я пошел:

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;
}
person John    schedule 02.03.2017
comment
Фантастика, единственная настройка, которую я сделал, заключалась в том, чтобы обеспечить заголовок в документе HTML и настроить эту строку вашего кода (обратите внимание на reverse()), this.title.setTitle(this.title.getTitle().split(' - ')[0] + ' - ' + this.recursivelyGenerateTitle(this.router.routerState.snapshot.root).reverse().join(' - '));. - person Tim Harker; 28.04.2017
comment
Или же вы можете использовать unshift() вместо push(), а затем reverse(). - person Tim Harker; 28.04.2017

Angular 6+ Я изменил старый код, используя новый Pipe(), и он работает нормально.

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']);
    })
  }
person Suhel Khan    schedule 04.06.2018

Вот самый простой способ изменить заголовок страницы при навигации по страницам/представлениям (проверено на Angular @2.3.1). Просто примените следующее решение ко всем представлениям, которые у вас есть, и все будет готово:

Пример кода на странице/представлении "О нас":

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

}

Пример кода на странице/представлении "Свяжитесь с нами":

import {Title} from "@angular/platform-browser";

export class ContactusComponent implements OnInit {

  constructor(private _titleService: Title) {
  }

  ngOnInit() {
    //Set page Title
    this._titleService.setTitle('Contact Us');
  }

}
person Devner    schedule 08.05.2017
comment
Я настоятельно рекомендую этот ответ - person Muhammad Bilal; 05.05.2021

В приведенном ниже примере:

-Мы добавили объект данных: { title: 'NAME' } к любому объекту маршрутизации.

-Мы устанавливаем базовое имя ("CTM") для времени загрузки (при нажатии F5 для обновления ..): <title>CTM</title>.

-Мы добавили класс "TitleService".

- мы обрабатываем события маршрутизатора, фильтруя их из 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);
        });

    }


}
person Dudi    schedule 12.06.2017

Прекрасно работает в Angular 6 и 6+ с методом Pipe и map вместо использования фильтра

Шаг 1: настройка маршрутизации

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

шаг 2: в вашем модуле импорта app.module.ts

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

затем в провайдере добавьте провайдеров: [title]

Шаг 3 При импорте основного компонента

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

}
person Mujahid    schedule 04.01.2019

Я также могу порекомендовать плагин @ngx-meta/core, который я только что выпустил, в случай, если вы ищете метод для динамической установки заголовка страницы и метатегов.

person Burak Tasci    schedule 11.11.2016

Ангуляр 6+

если маршрут настроен следующим образом:-

Routes = [
     {  path: 'dashboard',
       component: DashboardComponent,
       data: {title: 'Dashboard'}
   }]

** Затем в конструкторе компонентов заголовок может быть установлен следующим образом: - **

 constructor( private _titleService: Title, public activatedRoute: ActivatedRoute) {
    activatedRoute.data.pipe(map(data => data.title)).subscribe(x => this._titleService.setTitle(x));
   }
person Ajitesh Sinha    schedule 25.06.2018

Простой общий способ установить заголовок:

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

}

где title необходимо установить на каждом маршруте, например:

{ path: '', component: WelcomeComponent, data: {title: 'Welcome to my app'} }
person emcee22    schedule 01.03.2020