У меня есть, казалось бы, простая проблема. У меня есть компонент заголовка, в котором я хочу отобразить заголовок текущего активного маршрута. Для этого я добавляю ActivatedRoute в компонент заголовка и пытаюсь отобразить заголовок маршрута следующим образом:
export class HeaderComponent {
public title$;
constructor(private route: ActivatedRoute) {
this.title$ = route.title;
}
}
и html компонента
<header>
<h1>My Website - {{ title$ | async }}</h1>
</header>
Почему-то это не работает. Но я вижу, что заголовок, который я определил в разных маршрутах, обновляет заголовок окна браузера.
Кажется, ваш компонент заголовка используется в вашем ShellComponent, и я полагаю, что ваша конфигурация маршрутизации выглядит следующим образом:
const routes: Route[] = [
{
path: '',
component: ShellComponent, // <-- Header component is used here
children: [ // might be load children
{ path: 'route1', title: 'My title', component: ...}, // <-- title is here
...
]
}
]
Итак, если это правильно, вы можете видеть, что компонент заголовка расположен в дереве маршрутизации/инжектора/компонента над маршрутами с определенными заголовками.
Когда вы вводите ActivatedRoute в свой HeaderComponent, вы получите экземпляр маршрута этой оболочки.
{
path: '',
component: ShellComponent,
у него нет названия, поэтому вы его получите undefined
.
Что вы можете сделать, так это если у вас нет структуры с несколькими маршрутизаторами и розетками, вы можете вручную углубиться в дерево маршрутов, чтобы получить самый дочерний маршрут. Что-то вроде этого
constructor(private route: ActivatedRoute) {}
get leaf(): ActivatedRoute {
let leaf = this.route;
while (leaf.firstChild) {
leaf = leaf.firstChild;
}
return leaf;
}
и в шаблоне сделать
{{leaf.title | async}}
Вам следует быть осторожным со стратегией обнаружения изменений в ваших компонентах.
Ваш get leaf()
будет выполняться всякий раз, когда в этом компоненте будет обнаружено изменение, но если у вас есть OnPush
, вам придется пометить свой компонент для проверки при изменении маршрута вручную. Например, вы можете прослушивать router.events и всякий раз, когда происходит событие NavigationEnd
, делать markForCheck
, чтобы его обновить.
Или вы можете сделать смешанную версию, чтобы она работала с OnPush.
#route = inject(ActivatedRoute);
#router = inject(Router);
title$ = this.#router.events.pipe(
filter((evt) => evt instanceof NavigationEnd),
startWith(null),
switchMap(() => this.leaf.title)
);
get leaf(): ActivatedRoute {
let leaf = this.#route;
while (leaf.firstChild) {
leaf = leaf.firstChild;
}
return leaf;
}
и использовать в шаблоне
{{title$ | async}}
Таким образом, окончательное решение зависит от настройки вашей стратегии обнаружения изменений.
Рабочий результат: https://stackblitz.com/edit/stackblitz-starters-ca3d4z?file=src%2Fmain.ts
Ах, это имеет смысл. Решение немного сложнее, чем мне хотелось бы, но оно отлично работает.