Отображать заголовок маршрута в компоненте заголовка в Angular, всегда возвращает неопределенное значение

У меня есть, казалось бы, простая проблема. У меня есть компонент заголовка, в котором я хочу отобразить заголовок текущего активного маршрута. Для этого я добавляю ActivatedRoute в компонент заголовка и пытаюсь отобразить заголовок маршрута следующим образом:

export class HeaderComponent {
    public title$;

    constructor(private route: ActivatedRoute) {
        this.title$ = route.title;
    }
}

и html компонента

<header>
    <h1>My Website - {{ title$ | async }}</h1>
</header>

Почему-то это не работает. Но я вижу, что заголовок, который я определил в разных маршрутах, обновляет заголовок окна браузера.

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
0
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Кажется, ваш компонент заголовка используется в вашем 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

Ах, это имеет смысл. Решение немного сложнее, чем мне хотелось бы, но оно отлично работает.

Fabian 17.04.2024 23:03

Другие вопросы по теме