From 202af0eb50237fbb217c9065926e8fa7e9aac5e2 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 5 Mar 2021 12:03:38 +0300 Subject: [PATCH 1/5] add HTTP Error Handling section to HTTP Requests document --- docs/en/UI/Angular/HTTP-Requests.md | 99 +++++++++++++++++- .../custom-error-handler-404-component.jpg | Bin 0 -> 6153 bytes .../custom-error-handler-toaster-message.jpg | Bin 0 -> 7589 bytes 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 docs/en/UI/Angular/images/custom-error-handler-404-component.jpg create mode 100644 docs/en/UI/Angular/images/custom-error-handler-toaster-message.jpg diff --git a/docs/en/UI/Angular/HTTP-Requests.md b/docs/en/UI/Angular/HTTP-Requests.md index ab1ac04097..f307c5811d 100644 --- a/docs/en/UI/Angular/HTTP-Requests.md +++ b/docs/en/UI/Angular/HTTP-Requests.md @@ -27,13 +27,13 @@ An `HttpInterceptor` is able to catch `HttpErrorResponse`  and can be used for ## RestService -ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by deafult. +ABP core module has a utility service for HTTP requests: `RestService`. Unless explicitly configured otherwise, it catches HTTP errors and dispatches a `RestOccurError` action. This action is then captured by the `ErrorHandler` introduced by the `ThemeSharedModule`. Since you should already import this module in your app, when the `RestService` is used, all HTTP errors get automatically handled by default. ### Getting Started with RestService -In order to use the `RestService`, you must inject it in your class as a dependency. +In order to use the `RestService`, you must inject it in your class as a dependency. ```js import { RestService } from '@abp/ng.core'; @@ -200,6 +200,99 @@ getSomeCustomHeaderValue() { } ``` +You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10). -You may find `Rest.Observe` enum [here](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/rest.ts#L10). +## HTTP Error Handling + +When the `RestService` is used, all HTTP errors are automatically handled by `ErrorHandler` which is a service that exposed by the `@abp/ng.theme.shared` package. + +### Custom HTTP Error Handler + +A custom HTTP error handler can be registered to an injection token named `HTTP_ERROR_HANDLER`. If a custom handler function is registered, the `ErrorHandler` executes that function. + +See an example: + +```js +// http-error-handler.ts +import { ContentProjectionService, PROJECTION_STRATEGY } from '@abp/ng.core'; +import { ToasterService } from '@abp/ng.theme.shared'; +import { HttpErrorResponse } from '@angular/common/http'; +import { Injector } from '@angular/core'; +import { throwError } from 'rxjs'; +import { Error404Component } from './error404/error404.component'; + +export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) { + if (httpError.status === 400) { + const toaster = injector.get(ToasterService); + toaster.error(httpError.error?.error?.message || 'Bad request!', '400'); + return; + } + + if (httpError.status === 404) { + const contentProjection = injector.get(ContentProjectionService); + contentProjection.projectContent(PROJECTION_STRATEGY.AppendComponentToBody(Error404Component)); + return; + } + + return throwError(httpError); +} + +// app.module.ts +import { Error404Component } from './error404/error404.component'; +import { handleHttpErrors } from './http-error-handling'; +import { HTTP_ERROR_HANDLER, ... } from '@abp/ng.theme.shared'; + +@NgModule({ + // ... + providers: [ + // ... + { provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors } + ], + declarations: [ + //... + Error404Component], +}) +export class AppModule {} +``` + +In the example above: + + - Created a function named `handleHttpErrors` and defined as value of the `HTTP_ERROR_HANDLER` provider in app.module. After this, the function executes when an HTTP error occurs. + - 400 bad request errors is handled. When a 400 error occurs, backend error message will be displayed as shown below: + + ![custom-error-handler-toaster-message](images/custom-error-handler-toaster-message.jpg) + + - 404 not found errors is handled. When a 404 error occurs, `Error404Component` will be appended to the `` as shown below: + +![custom-error-handler-404-component](images/custom-error-handler-404-component.jpg) + + - Since `throwError(httpError)` is returned at bottom of the `handleHttpErrors`, the `ErrorHandler` will handle the HTTP errors except 400 and 404 errors. + + +**Note 1:** If you put `return` to next line of handling an error, default error handling will not work for that error. + +```js +export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) { + if (httpError.status === 403) { + // handle 403 errors here + return; // put return to skip default error handling + } +} +``` + +**Note 2:** If you put `return throwError(httpError)`, default error handling will work. + - `throwError` is a function. It can be imported from `rxjs`. + - `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`. + +```js +export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) { + if (httpError.status === 500) { + // handle 500 errors here + return; + } + + // you can return the throwError(httpError) at bottom of the function to run the default handler of ABP for HTTP errors that you didn't handle above. + return throwError(httpError) +} +``` diff --git a/docs/en/UI/Angular/images/custom-error-handler-404-component.jpg b/docs/en/UI/Angular/images/custom-error-handler-404-component.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e4b2f15c5075991203d8ad91bbd4eb42a9070d51 GIT binary patch literal 6153 zcmeIwc}&w+902fNDM#g~l&XV3X@pr+eu}EDr?l4+cOW5D>aH0o@xQ2rxA+M%x{2rw`J8GsEJohDJ{xaV`E?;}P<)0Zpre2T2{!!0_0(t?xfL=f^pcnXm3K(+j9WPHx3zCx3(gYMCztm3X zI6X9xOCFiX3P#MuKN@l&ctyLQ8a-xZQpJzKMt!tU6;uo1)pey45N!#fh<==__C@q2 z%y5p(hBo8F^h`aXwPRFqssS^X!W-|JRAPEvcluO!o-B@UQR{--G;7+g|D;@{Qm))rJN zb$~DZ6@GVeCI;>?-J8UY&{m4Kuu|BoYE7uTR2p$-__xLPoAFzfPdl7jXjet-_=njj z=Tby5TF4$TlAZ{=vN8&A|UKK(#_nV(8;h>sO}hJ`epn4A;2#4bDO0Qat@Y(+}? zQ32OJzLMzGdYS?k9(F78O}8WOI)@@PJqZgZB^<-WW(8#2#f^$W;s|!a#VmFOlN`&u z<+Sw7Ul|jAL{gYpi9&h1tJ}HS9v!f`?=pbFL7Itd)BbZ@*l*IdD5tK2@orsRcOMy@pOsv!^U8_JN3aS$;vlywl3zjJ6h? zlgR2;I!5;vCP&x%wMfsnX*jg1uf{g05vadQ$A_oAymN4!+(xo}B!09JeV#_3WJ~a7 zA-{g$_-8lcW~&D0;9gHs)T|^WnQ#(^JuA#ZLi5UOse;Mu#k6L{7=xR^;WJyh*e&mt zRMR2ym5~RTEf`HFH72S*Ji~jA=vLJ~r&9Mii=mNm#gZHLL79Sjb2LMgieErTJ!ZA3 zZm?5DWC=ExK)lo@E461NGDMWvh5S0K4*20QhP)}) zA0{}_tLgje!);I$_`K%6U(DU6M{yOGI9r#(bIGo0o&mR1t4^~O<@DEu2$gxFaEdNy zmf}YmrK3C~R9RB85(w|?^K^B=2VHp{Tkp@0KU8~$J0(NYuH6q&Ts;$(mb`%7LsZz* zQpzaTP-cer>j?afm$W}_{?zj^1PdPO%k=09iY-M&$VNVFFLvij~i{5*FK4eM# zK57AJL_UDxHp)C;+4(inUtSd4&TpaZ_8g^TDM^zs{XZb1xJbbMl_@9TiT z=HhaReNZm`*oo=E_5!Y( BlV|_{ literal 0 HcmV?d00001 diff --git a/docs/en/UI/Angular/images/custom-error-handler-toaster-message.jpg b/docs/en/UI/Angular/images/custom-error-handler-toaster-message.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c1cced8237a13bf0e18ec9d4e4b08ddb6f527c26 GIT binary patch literal 7589 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 S7su<%e?BPuAGJ7lJoaCszdtVk literal 0 HcmV?d00001 From 9dd4ee1674f0fe7fd8e04ec3e9716fdb1cc9fcc0 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 5 Mar 2021 12:05:03 +0300 Subject: [PATCH 2/5] add an import to the HTTP-Request.md --- docs/en/UI/Angular/HTTP-Requests.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/en/UI/Angular/HTTP-Requests.md b/docs/en/UI/Angular/HTTP-Requests.md index f307c5811d..aeb55578b8 100644 --- a/docs/en/UI/Angular/HTTP-Requests.md +++ b/docs/en/UI/Angular/HTTP-Requests.md @@ -286,6 +286,8 @@ export function handleHttpErrors(injector: Injector, httpError: HttpErrorRespons - `httpError` is the second parameter of the error handler function which is registered to the `HTTP_ERROR_HANDLER` provider. Type of the `httpError` is `HttpErrorResponse`. ```js +import { throwError } from 'rxjs'; + export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) { if (httpError.status === 500) { // handle 500 errors here From fe5399026fb75468a0692cf616acb14e941d7767 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 5 Mar 2021 12:10:06 +0300 Subject: [PATCH 3/5] create HTTP_ERROR_HANDLER injection token --- .../packages/theme-shared/src/lib/models/common.ts | 9 ++++++++- .../theme-shared/src/lib/tokens/http-error.token.ts | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts index 64047e0db7..0e8dd9e592 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts @@ -1,5 +1,7 @@ -import { Type } from '@angular/core'; +import { HttpErrorResponse } from '@angular/common/http'; +import { Injector, Type } from '@angular/core'; import { Validation } from '@ngx-validate/core'; +import { Observable } from 'rxjs'; export interface RootParams { httpErrorConfig: HttpErrorConfig; @@ -17,4 +19,9 @@ export interface HttpErrorConfig { }; } +export type HttpErrorHandler = ( + injector: Injector, + httpError: HttpErrorResponse, +) => Observable; + export type LocaleDirection = 'ltr' | 'rtl'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts b/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts index 62f2d2d593..39cb43a350 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts @@ -1,5 +1,5 @@ import { InjectionToken } from '@angular/core'; -import { HttpErrorConfig } from '../models/common'; +import { HttpErrorConfig, HttpErrorHandler } from '../models/common'; export function httpErrorConfigFactory(config = {} as HttpErrorConfig) { if (config.errorScreen && config.errorScreen.component && !config.errorScreen.forWhichErrors) { @@ -13,4 +13,6 @@ export function httpErrorConfigFactory(config = {} as HttpErrorConfig) { } as HttpErrorConfig; } -export const HTTP_ERROR_CONFIG = new InjectionToken('HTTP_ERROR_CONFIG'); +export const HTTP_ERROR_CONFIG = new InjectionToken('HTTP_ERROR_CONFIG'); + +export const HTTP_ERROR_HANDLER = new InjectionToken('HTTP_ERROR_HANDLER'); From 7e46a48e78d686e37bc2ebcde540fb8805e0a8ca Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 5 Mar 2021 12:11:05 +0300 Subject: [PATCH 4/5] execute custom error handler if it exists --- .../src/lib/handlers/error.handler.ts | 229 ++++++++++-------- 1 file changed, 124 insertions(+), 105 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index 1835b80eef..cad4567285 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -12,13 +12,14 @@ import { } from '@angular/core'; import { NavigationError, ResolveEnd } from '@angular/router'; import { Actions, ofActionSuccessful } from '@ngxs/store'; -import { Observable, Subject } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; +import { Observable, of, Subject, throwError } from 'rxjs'; +import { catchError, filter, map, switchMap } from 'rxjs/operators'; import snq from 'snq'; import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http-error-wrapper.component'; import { ErrorScreenErrorCodes, HttpErrorConfig } from '../models/common'; import { Confirmation } from '../models/confirmation'; import { ConfirmationService } from '../services/confirmation.service'; +import { HTTP_ERROR_HANDLER } from '../tokens/http-error.token'; export const DEFAULT_ERROR_MESSAGES = { defaultError: { @@ -70,28 +71,32 @@ export const DEFAULT_ERROR_LOCALIZATIONS = { export class ErrorHandler { componentRef: ComponentRef; + protected httpErrorHandler = this.injector.get(HTTP_ERROR_HANDLER, (_, err: HttpErrorResponse) => + throwError(err), + ); + constructor( - private actions: Actions, - private routerEvents: RouterEvents, - private confirmationService: ConfirmationService, - private cfRes: ComponentFactoryResolver, - private rendererFactory: RendererFactory2, - private injector: Injector, - @Inject('HTTP_ERROR_CONFIG') private httpErrorConfig: HttpErrorConfig, + protected actions: Actions, + protected routerEvents: RouterEvents, + protected confirmationService: ConfirmationService, + protected cfRes: ComponentFactoryResolver, + protected rendererFactory: RendererFactory2, + protected injector: Injector, + @Inject('HTTP_ERROR_CONFIG') protected httpErrorConfig: HttpErrorConfig, ) { this.listenToRestError(); this.listenToRouterError(); this.listenToRouterDataResolved(); } - private listenToRouterError() { + protected listenToRouterError() { this.routerEvents .getNavigationEvents('Error') .pipe(filter(this.filterRouteErrors)) .subscribe(() => this.show404Page()); } - private listenToRouterDataResolved() { + protected listenToRouterDataResolved() { this.routerEvents .getEvents(ResolveEnd) .pipe(filter(() => !!this.componentRef)) @@ -101,113 +106,127 @@ export class ErrorHandler { }); } - private listenToRestError() { + protected listenToRestError() { this.actions .pipe( ofActionSuccessful(RestOccurError), map(action => action.payload), filter(this.filterRestErrors), + switchMap(this.executeErrorHandler), ) - .subscribe(err => { - const body = snq(() => err.error.error, { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, - }); + .subscribe(); + } - if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { - const confirmation$ = this.showError(null, null, body); + private executeErrorHandler = err => { + const returnValue = this.httpErrorHandler(this.injector, err); - if (err.status === 401) { - confirmation$.subscribe(() => { - this.navigateToLogin(); - }); - } - } else { - switch (err.status) { - case 401: - this.canCreateCustomError(401) - ? this.show401Page() - : this.showError( - { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title, - }, - { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.details, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details, - }, - ).subscribe(() => this.navigateToLogin()); - break; - case 403: - this.createErrorComponent({ - title: { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title, - }, - details: { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.details, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details, - }, - status: 403, - }); - break; - case 404: - this.canCreateCustomError(404) - ? this.show404Page() - : this.showError( - { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.details, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details, - }, - { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title, - }, - ); - break; - case 500: - this.createErrorComponent({ - title: { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title, + return (returnValue instanceof Observable ? returnValue : of(null)).pipe( + catchError(err => { + this.handleError(err); + return of(null); + }), + ); + }; + + private handleError(err: any) { + const body = snq(() => err.error.error, { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, + }); + + if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { + const confirmation$ = this.showError(null, null, body); + + if (err.status === 401) { + confirmation$.subscribe(() => { + this.navigateToLogin(); + }); + } + } else { + switch (err.status) { + case 401: + this.canCreateCustomError(401) + ? this.show401Page() + : this.showError( + { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title, }, - details: { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.details, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details, + { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.details, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details, }, - status: 500, - }); - break; - case 0: - if (err.statusText === 'Unknown Error') { - this.createErrorComponent({ - title: { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, - }, - details: err.message, - isHomeShow: false, - }); - } - break; - default: - this.showError( + ).subscribe(() => this.navigateToLogin()); + break; + case 403: + this.createErrorComponent({ + title: { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title, + }, + details: { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.details, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details, + }, + status: 403, + }); + break; + case 404: + this.canCreateCustomError(404) + ? this.show404Page() + : this.showError( { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details, + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.details, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details, }, { - key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title, }, ); - break; + break; + case 500: + this.createErrorComponent({ + title: { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title, + }, + details: { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.details, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details, + }, + status: 500, + }); + break; + case 0: + if (err.statusText === 'Unknown Error') { + this.createErrorComponent({ + title: { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, + }, + details: err.message, + isHomeShow: false, + }); } - } - }); + break; + default: + this.showError( + { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details, + }, + { + key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title, + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, + }, + ); + break; + } + } } - private show401Page() { + protected show401Page() { this.createErrorComponent({ title: { key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title, @@ -217,7 +236,7 @@ export class ErrorHandler { }); } - private show404Page() { + protected show404Page() { this.createErrorComponent({ title: { key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title, @@ -227,7 +246,7 @@ export class ErrorHandler { }); } - private showError( + protected showError( message?: LocalizationParam, title?: LocalizationParam, body?: any, @@ -256,7 +275,7 @@ export class ErrorHandler { }); } - private navigateToLogin() { + protected navigateToLogin() { this.injector.get(AuthService).initLogin(); } @@ -304,13 +323,13 @@ export class ErrorHandler { ); } - private filterRestErrors = ({ status }: HttpErrorResponse): boolean => { + protected filterRestErrors = ({ status }: HttpErrorResponse): boolean => { if (typeof status !== 'number') return false; return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === status) < 0; }; - private filterRouteErrors = (navigationError: NavigationError): boolean => { + protected filterRouteErrors = (navigationError: NavigationError): boolean => { return ( snq(() => navigationError.error.message.indexOf('Cannot match') > -1) && this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0 From 442144e9f0ccaa4f207bab84139f3772d9fcebe8 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 5 Mar 2021 12:55:48 +0300 Subject: [PATCH 5/5] fix a lint error --- .../packages/theme-shared/src/lib/handlers/error.handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index cad4567285..1001c98085 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -117,8 +117,8 @@ export class ErrorHandler { .subscribe(); } - private executeErrorHandler = err => { - const returnValue = this.httpErrorHandler(this.injector, err); + private executeErrorHandler = error => { + const returnValue = this.httpErrorHandler(this.injector, error); return (returnValue instanceof Observable ? returnValue : of(null)).pipe( catchError(err => {