When Angular 14 released and custom title strategies became a possibility, my mind immediately went to asking, "how can I dynamically set a page's title from a selector?"
I wrote an RFC in the NgRx community to pitch an API for doing this. I'd like to explain how it works, and how you can leverage it today (whether or not it joins an @ngrx/* package).
Example of configuring a dynamic title
All the code for the following example can be found in this StackBlitz demo.
Say I have a website where I can enter the name of an "action" in an input, and then "do" it by clicking a "Do Action" button.
When I click "Do Action", the title of my page reflects how many seconds have passed since the "action" was done.
In my Angular app routes, I have the route for the page configured using a tag function called ngrxTitle
that allows me to inline selectors into a string.
const routes: Routes = [
{
path: '',
component: AppComponent,
title: ngrxTitle`${counterFeature.selectCount} Seconds Since ${counterFeature.selectEvent}`,
},
];
The selector counterFeature.selectCount
selects the number of seconds since the button was clicked, while counterFeature.selectEvent
selects the name of the action entered in the input when the button was clicked. Using ngrxTitle
, I can templatize the title to include the latest results of multiple selectors like these.
ngrxTitle Implementation
ngrxTitle
is a tag function that processes a template literal with selectors.
For every selector, it generates a unique ID and replaces the selector with the string 'NgRxTitleSelector${ID}'
.
For example, when I ran my app, the title template literal was generated into the string 'NgRxTitleSelector${f35ace1e-28d8-4dc6-850a-f0900315ca8a} Seconds Since NgRxTitleSelector${40b2582b-832a-44f5-b6ce-f650518db278}'
.
Angular 14 allows developers to implement custom "title strategies". A TitleStrategy
is a class with an updateTitle
method that is called each time the route changes. This gives us the opportunity to change the title any way desired.
That means we can process the title template generated by ngrxTitle
and subscribe the selectors referenced by the template to produce a new title.
The NgRxTitleStrategy
starts with this basic structure:
export class NgRxTitleStrategy extends TitleStrategy {
private titleSubscription: Subscription | undefined;
updateTitle(snapshot: RouterStateSnapshot): void {
// Each time the route changes, cancel the last subscription
this.titleSubscription?.unsubscribe();
// Get the title using the base method
// When using ngrxTitle, this will be the special template string
const titleTemplate = this.buildTitle(snapshot);
// Create an Observable of the title built from the template
const title$ = this.selectTitleFromTemplate(titleTemplate);
// Continuously update the title as the selectors emit new values
this.titleSubscription = title$.subscribe((t) => this.title.setTitle(t));
}
}
In the app module, we can utilize the new title strategy in the providers
.
@NgModule({
declarations: [AppComponent],
providers: [{
provide: TitleStrategy,
useClass: NgRxTitleStrategy,
}],
imports: [
/* ... */
],
bootstrap: [AppComponent],
})
export class AppModule {}
Full implementation
See the gist below for the full implementation.
Top comments (0)