My requirement is to load some data by calling Two Rest Api's before app component loads.If API gives any error display the message in Toaster (angular2-toaster).
Before loading app component the below AppLoadService executes
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/toPromise';
import { APP_SETTINGS } from 'app/app-settings/settings';
@Injectable()
export class AppLoadService {
constructor(private httpClient: HttpClient) { }
loadLabs(): Promise<any> {
return new Promise((resolve, reject) => {
this.httpClient.get(`/api/v1/api/lab`)
.toPromise()
.then((res: any) => {
APP_SETTINGS.labs = res;
resolve();
})
.catch((err: any) => {
reject(err);
});
});
}
/////////////////******************////////////////////////////
getSettings(): Promise<any> {
return new Promise((resolve, reject) => {
this.httpClient.get(`assets/settings/config.json`)
.toPromise()
.then((config: any) => {
APP_SETTINGS.loginURL = config["login"];
console.log(`config.json loaded:: `, APP_SETTINGS);
resolve();
})
.catch((err: any) => {
reject(err);
});
});
}
My App module file is like below
export function createTranslateLoader(http: Http) {
return new TranslateStaticLoader(http, './assets/i18n', '.json');
}
@NgModule({
declarations: [
AppComponent, CustomDateRangePickerComponent
],
imports: [
// coreModules: //
BrowserModule,
BrowserAnimationsModule,
ToasterModule,
HttpClientModule,
FormsModule,
CommonModule, //<====added
//thirdPartyModules:
// ToastyModule,
BootstrapModalModule,
//appModules: //
AppRoutingModule,
FooterModule,
ErrorModule,
AccessDeniedModule,
NotFoundModule,
AppLoadModule, //Startupdata before APP loaded
RouterModule.forRoot([]),
TranslateModule.forRoot({ provide: TranslateLoader, useFactory: (createTranslateLoader), deps: [Http] })
],
providers: [
ToasterService,
StartupService,
ResponseStatusesService,
LocalStorageService,
ApplicationSettingsService,
LabSelectionService,
AccountService,
AuthService,
AlertService,
AuthGuard,
RolesGuard,
FeaturebasedGuard,
ErrorLogService,
{
provide: ErrorHandler,
useClass: GlobalErrorsHandler
},
{
provide: HTTP_INTERCEPTORS,
useClass: AppHttpInterceptor,
multi: true
},
{
provide: LocationStrategy,
useClass: HashLocationStrategy
},
],
exports: [TranslateModule],
bootstrap: [AppComponent]
})
export class AppModule { }
GlobalErrorHandler.ts
@Injectable()
export class GlobalErrorsHandler extends ErrorHandler {
constructor(
private injector: Injector,
private errorLogService: ErrorLogService
) {
super();
alert('GlobalErrorsHandler');
}
handleError(error: Error | HttpErrorResponse) {
debugger;
let toaster = this.injector.get(ToasterService);
toaster.pop("head", "body");
}
}
AppComponent.html
<toaster-container [toasterconfig]="ang2toasterconfig"></toaster-container>
<router-outlet></router-outlet>
Same issue with interceptors as well
import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { ToasterService } from 'angular2-toaster';
import { AuthService } from 'app/blocks/auth/auth.service';
import { TranslateService } from 'ng2-translate';
import { AlertService } from '../../core/services/common';
@Injectable()
export class AppHttpInterceptor implements HttpInterceptor {
constructor(private injector: Injector) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
debugger;
console.log(req);
if (!window.navigator.onLine) { // check to see if there's internet
// if there is no internet, throw a HttpErrorResponse error
// since an error is thrown, the function will terminate here
return Observable.throw(new HttpErrorResponse({ error: 'NO_INTERNET' }));
} else {
// else return the normal request
return this.handleResponse(next, req);
}
}
handleResponse(next, req) {
return next.handle(req)
.do((ev: HttpEvent<any>) => {
if (ev instanceof HttpResponse) {
}
})
.catch((response: any) => {
if (response instanceof HttpErrorResponse) {
console.log('response in the catch: ', response);
this.handleReponseExceptions(response);
}
return Observable.throw(response);
});
}
handleReponseExceptions(exception) {
let toaster = this.injector.get(ToasterService);
let translate = this.injector.get(TranslateService);
// TOASTER NOT WORKING AND TRANSLATE NOT WORKING
toaster.pop("test","test");
this.translate.get(["test", "test"]).subscribe(res => {
//NOT FETCHING FROM en.json
});
}
}
As per my knowledge, the toaster.pop('','') method is called before toaster-container loaded. How to solve this issue. Root component is the App component, where I placed the toaster container. Please suggest me the architecture to solve this issue.
One more, where I need to handle different errors... In Local Errorhandler (component level) or in Global error handler or in Interceptor?
Example errors: 400,404,500+ ...etc
Update1: As per the David comment changed code like below, but still No Container ..... message is coming in console and no toaster is visible
Using "angular2-toaster": "^6.1.0"
These are the API calls which will be fired before app component
This happens because
handleError()
method is executed outside of the Angular zone. This causes toasts not to behave correctly since change detection doesn't run on it. Turn ononActivateTick
in the error handler to ensure that the toast is running inside Angular's zone:Working Example
Git Issue