Reputation: 111
I have a class implementing ErrorHandler and is provided at root level. I have 3 modules in my app of which 2 of them can use ErrorHandler at root level but one of them should have different version of ErrorHandler.
I have tried creating two implementations of ErrorHandler, one of which is provided at root level, I have decorated second service with {providedIn: ThreePageModule}, but this doesn't seems like working as whenever there is an error ex: HttpErrorResponse the root level ErrorHandler kicks in. I have looked at the angular documentation and it says when a child Module is lazy loaded it gets the provided service. Am I missing something here??
Below is the app.module.ts
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
FormsModule,
BrowserModule,
HttpClientModule,
AppRoutingModule
],
providers: [
....other services...
{
provide: HTTP_INTERCEPTORS,
useClass: HttpConfigInterceptor,
multi: true
},
{ provide: ErrorHandler, useClass: ExceptionHandlerService },
],
bootstrap: [AppComponent]
})
export class AppModule {}
AppRoutingModule.ts:
@NgModule({
imports: [
RouterModule.forRoot(appRoutes)
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
appRoutes.ts:
export const appRoutes: Routes = [
{
path: 'one',
loadChildren: './../one/one.module#OnePageModule'
},
{
path: 'two',
loadChildren: './../two/two.module#TwosPageModule'
},
{
path: 'three',
loadChildren: './../three/three.module#ThreePageModule'
}
];
ThreeModule.ts
@NgModule({
imports: [
...Imports...
],
entryComponents: [
ThreeComponent
],
providers: [DatePipe],
declarations: [
....Declarations.....
]
})
export class ClaimsPageModule { }
ThreeErrorHandlerService.ts
@Injectable({
providedIn: ThreePageModule
})
export class ThreeErrorHandlerService implements ErrorHandler {
constructor() { }
handleError(error: Error | HttpErrorResponse): void {
if (error instanceof HttpErrorResponse) {
return;
}
}
}
What I want is to use ThreeErrorHandlerService in ThreePageModule while still using ExceptionHandlerService in rest of the two modules.
Is this the way we achieve it or am I doing it wrongly.
Upvotes: 3
Views: 2683
Reputation: 11924
I think there is a way to achieve this.
export function errorHandlerFactory (r: Router): AbstractErrorHandler {
return r.url === '/foo' ? new ErrorHandlerThree('foo error!') : new ErrorHandlerOne('not foo !!')
}
export abstract class AbstractErrorHandler {
abstract getCrtErr: () => string;
}
export class ErrorHandlerOne implements AbstractErrorHandler {
constructor (public crtErr: string) { }
getCrtErr () { return 'err!' }
}
export class ErrorHandlerThree implements AbstractErrorHandler {
constructor (public crtErr: string) { }
getCrtErr () { return 'err!' }
}
@Component({
selector: 'my-app',
template: `
<button [routerLink]="'foo'">foo route</button>
<router-outlet></router-outlet>
`,
})
class AppComponent {
constructor (err: AbstractErrorHandler) {
console.log(err) // not foo !!
}
}
const routes: Routes = [
{ path: 'foo', loadChildren: () => import('./foo/foo.module').then(m => m.FooModule,) },
]
@NgModule({
imports: [
BrowserModule,
RouterModule.forRoot(routes),
],
declarations: [
AppComponent
],
providers: [
{ provide: AbstractErrorHandler, useFactory: errorHandlerFactory, deps: [Router] }
],
bootstrap: [AppComponent]
})
export class AppModule { }
@Component({
selector: 'foo-comp',
template: `this is foo!`,
})
export class FooComp {
constructor (err: AbstractErrorHandler) {
console.log('foo', err) // foo error!
}
}
const routes: Routes = [
{ path: '', component: FooComp, }
]
@NgModule({
declarations: [FooComp],
imports: [
CommonModule,
RouterModule.forChild(routes),
],
providers: [
{ provide: AbstractErrorHandler, useFactory: errorHandlerFactory, deps: [Router] }
],
Note that you might need to track class instances inside app.tokens.ts
as you might not want a new instance every time a component injects your this dependency.
Upvotes: 3