Angular 根据激活的路线及其 parents 设置标题

Angular setting title depending on activated route and its parents

我的目标: 我想全局监听路由器 NavigationEnd 事件,并根据路由自定义数据更改网页标题。

当前代码(在app.component.ts):

this.router.events.pipe(
  filter((ev) => ev 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.title.setTitle(event['title']));

来自 this tutorial

上面的代码可以,但是一点也不优雅,看需要的路由配置:

app-routing.module.ts

const routes: Routes = [
  {
    path: 'user',
    loadChildren: () => import(`./user/user.module`).then(m => m.UserModule),
    data: { title: "Pagina Utente" }
  },
  {
    path: 'admin', loadChildren: () => import(`./admin/admin.module`).then(m => m.AdminModule),
    data: { title: "Pannello Admin" }
  },

  { path: '**', component: HomeComponent },
];

admin-routing.module.ts:

const routes: Routes = [
  {
    path: '', component: AdminPanelComponent,
    children: [
      {
        path: 'users', component: UsersComponent,
        data: { title: 'Pannello Admin: Utenti' }
      },
      {
        path: 'comuni', component: ComuniComponent,
        data: { title: 'Pannello Admin: Comuni' }
      },

    ]
  }
];

如您所见,我已经指定 /admin 路由应该有 "Pannello Admin" 作为标题,但我需要为它的每个 children 路由一次又一次地写它。

我试图通过将 app.component.ts 代码更改为以下内容来解决此问题:

this.router.events.pipe(
  filter((ev) => ev instanceof NavigationEnd),
  map(() => this.activatedRoute),
  map((route) => {
    let title = route.data['title'] || '';
    while (route.firstChild) {
      route = route.firstChild;
      title+= route.data['title'];
    }
    return route;
  }),
  filter((route) => route.outlet === 'primary'),
  mergeMap((route) => route.data),
).subscribe((event) => this.title.setTitle(event['title']));

我希望这段代码能正常工作,并将我的标题设置为匹配路由的数据['title'] 属性 的串联。但是它不起作用,只是给出空标题(数据['title'] 由于某种原因总是未定义)

export class AppRouterModule {
   constructor(private router: Router, private eventService: EventService) {
      this.router.events.subscribe(event => {
         if (event instanceof NavigationStart) {
            this.eventService.StartNavigationSpinner();
         }
      });
   }
}

我将导航事件订阅放入 AppRouterModule 本身,然后当特定事件发生时,我将它发送到一个 eventService,所有加载的组件都会监​​听这个列表:

  this.EventService.NavigationStartEvent.subscribe(() => {
         if (this.showGlobalSpinner) return;
         this.showGlobalSpinner = true;
      });

事件服务是一个如下所示的服务:

export class EventService {
   NavigationEndEvent = new EventEmitter();
   NavigationStartEvent = new EventEmitter();
...

所有解析都在 app.router 模块中完成,只是将事件发送到任何已加载标题更改的订阅?它可以是任何加载的组件。

如果重写发生得太频繁,那是因为页面正在按 angular 的 routing/render 周期重新加载。值得怀疑的是路由中的 loadChildren 配置。

我认为您想要的是主页加载一次,并且仅在单个 child 页面更改时才更改标题。我相信这意味着您需要另一个 ngRouterOutput。 Angular 文档在这个概念上令人眼花缭乱。 children 可以存在于任何页面的想法。

我最终通过在我的 app.component.ts 构造函数中使用此代码解决了我的问题:

this.router.events.pipe(
  filter((ev) => ev instanceof NavigationEnd),
  map(() => this.activatedRoute),
).subscribe((activatedRoute: ActivatedRoute) => this.title.setTitle(activatedRoute.snapshot.data['title'] || 'Gestionale Incarichi'));