Hello!
At the moment, I am working at my new project - Page Health .
It is a SaaS platform which provides a page performance monitoring on the long run.
In this application I had a lot of cases, where I had to duplicate the code of my resolvers to make very, very similar things.
That's why I took thought about how to implement the DRY coding principle in my app.
First, I take a glance at official angular documentation .
And here I found an interesting way to implement resolvers with in-line functions.
export const myHero: Hero = {
// ...
}
@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'detail/:id',
component: HeroComponent,
resolve: {
hero: 'heroResolver'
}
}
])
],
providers: [
{
provide: 'heroResolver',
useValue: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => myHero
}
]
})
export class AppModule {}
So, I decided to create a function which will return a reusable provider.
export function createPageResolver(redirectRoute: string): Provider {
return {
provide: "pageResolver",
deps: [NotificationsService, PagesApiService, Router],
useFactory: (n: NotificationsService, p: PagesApiService, r: Router) => {
return new PageResolver(n, p, r, redirectRoute);
}
}
}
Let's explain it step by step:
provide - it is the name of my provider.
deps - is shorten for the word - dependencies. In my case I need some services to do my stuff and Router from @angular/router to redirect user if condition in resolve function is not match.
useFactory - unlike the example in the official docs, I need it, because in my case I need to return a new instance of resolver, not a simple value.
And actually code of my resolver.
... imports here
export class PageResolver implements Resolve<PageDto> {
constructor(
private notificationsService: NotificationsService,
private pagesApiService: PagesApiService,
private router: Router,
@Inject("redirectRoute") private redirectRoute: string,
) {}
resolve(route: ActivatedRouteSnapshot): Observable<PageDto> {
const param: string = route.params["id"];
const pageId: number = Number(param);
if (isNaN(pageId)) {
this.notificationsService.error("Invalid page id.");
this.router.navigate([this.redirectRoute]);
return of(null);
} else {
return this.pagesApiService.getUserPage(pageId)
.pipe(
catchError((e) => {
console.error(e);
this.notificationsService.error("Unable to get this page.");
this.router.navigate([this.redirectRoute]);
return of(null);
}),
);
}
}
}
By the way, the code can be extended with custom error message, depending on situation, but in my case a static message is completely enough.
Also, please note, that I did not add an @Injecable() decorator for my resolver class, because, injection happens in useFactory method.
If you do not fully understand how to use it, here is an example.
... imports here
const routes: Routes = [
{
path: "",
component: PageSpeedComponent,
children: [
... some other routes
{
path: ":id",
component: PageSpeedMetricsComponent,
data: {
title: "Chrome User Experience Report"
},
resolve: {
page: "pageResolver",
},
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [
createPageResolver("/user-experience"),
],
})
export class PageSpeedRoutingModule {}
Hope, this small technick will be useful for somebody :)
Top comments (2)
can you share repo link ?
ofc, github.com/IgorFilippov3/metrico