angular - Hur kan jag dynamiskt få värdet av 'title' för en rutt när det ändras under navigering?


Sammanhang och problem

Jag har definierat några rutter inuti en app-routing.module på följande sätt:

// imports

const routes: Routes = [
  { path: 'home', title: 'Home Route', component: HomeComponent },
  { path: 'other', title: 'Other Route', component: OtherComponent},
  { path: 'another', title: 'Yet Another Route', component: YetAnotherComponent },
  { path: '',   redirectTo: 'home', pathMatch: 'full' },
];

@NgModule({
  declarations: [],
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Och jag har också definierat en navigation-title.component som jag vill använda för att visa den aktuella routen som "My App | Home Route" eller "My App | Other Route", till exempel.

Det verkar dock inte finnas något enkelt sätt att binda till rutttiteln.

Saker jag har provat

Injicerar ActivatedRoute i min navigation-title-komponent

Jag försökte först injicera en private activatedRoute: ActivatedRoute och binda till this.activatedRoute.title (som är en Observable<string | undefined>) med en async-pipe, men denna aktiverade route verkar faktiskt inte ändras när du navigerar runt.

Koppla till routernavigeringshändelser

Nästa steg försökte jag prenumerera på routerhändelserna, specifikt på NavigationEnd, för att uppdatera titeln, men att hämta titeln från den aktiverade routen när navigeringen var klar resulterade alltid i att jag fick titeln på den föregående routen.

Bindning till routeruttaget

Slutligen kopplade jag till router-outlet:s (activate)-händelse med en händelsehanterare inuti min navigation-title.component med lite kod bakom (se denna gist för mer detaljer), men tyvärr resulterar detta i en stark koppling mellan min titelkomponent och router-outlet.

Finns det inte ett bättre (dvs. helt avkopplat) sätt att helt enkelt få rutttiteln från en injicerad Router eller ActivatedRoute på något sätt?

P.S.

Jag vill verkligen INTE arbeta med TitleService eftersom det inte alls är meningsfullt att låta en komponent sätta sidans titel när du redan kan definiera den i den rutt som ger upphov till nämnda komponent.

Svar #1

Jag har haft samma problem ganska länge och kunde fortfarande inte lösa det på ett sätt som tillfredsställer mig, men en fungerande lösning är att injicera Router och Title i din komponent och sedan prenumerera på händelserna av NavigationEnd.

Om du försöker få titeln genom getTitle() direkt efter att händelsen har utlösts får du fel titel (föregående sida), om du sätter en timeout får du rätt titel.

  constructor(private router: Router, private titleService: Title) {
    this.router.events.subscribe({
      next: (event) => {
        if (event instanceof NavigationEnd) {
          setTimeout(() => {
            const title = this.titleService.getTitle();
            console.log('Title: ', title);
          }, 50); //TODO: If no timeout it gets previous page title
        }
      },
    });
  }

Svar #2

Om titeln inte är dynamisk men du fortfarande vill göra något annorlunda, kan du använda titelsstrategin från Angular 14+

Källa: https://dev.to/brandontroberts/setting-page-titles-natively-with-the-angular-router-393j

@Injectable()
export class TemplatePageTitleStrategy extends TitleStrategy {
  constructor(private readonly title: Title) {
    super();
  }

  override updateTitle(routerState: RouterStateSnapshot) {
    const title = this.buildTitle(routerState);
    if (title !== undefined) {
      this.title.setTitle(`My App | ${title}`);
    }
  }
}
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [
    {
      provide: TitleStrategy,
      useClass: TemplatePageTitleStrategy
    }
  ]
})
export class AppRoutingModule {}