Angular 2 - 我的应用程序中有很多页面,每个页面中我都在调用后端服务。在这里,我的查询是如何创建一个常见的错误弹出组件,它将收集错误消息并在需要我的应用程序时显示弹出窗口。能帮忙找到解决方案吗?谢谢。
这就是我在Angular 5中的表现,你可以在Angular2中做到类似,因为它并没有那么不同。我希望这能帮到您。在我的app.component.html
中,我补充说:
<div class="mesaages">
<div *ngIf="errorMessage" class="alert alert-danger alert-dismissible fade show" role="alert">
<button type="button" class="close" (click)="errorMessage=''">
<span aria-hidden="true">×</span>
</button>
<i class="fa fa-exclamation-circle fa-1x" aria-hidden="true"></i> {{ errorMessage}}
</div>
<div *ngIf="busyinfoMessage" class="alert alert-success alert-dismissible fade show" role="alert">
<button type="button" class="close" (click)="busyinfoMessage=''">
<span aria-hidden="true">×</span>
</button>
<i class="fa fa-spinner fa-pulse fa-1x fa-fw" aria-hidden="true" placement="right"></i> {{ busyinfoMessage}}
</div>
<div *ngIf="infoMessage" class="alert alert-info alert-dismissible fade show" (mouseover)="stopTimeout('w')" (mouseout)="_actionService.infoMessage(infoMessage,3)" role="alert">
<button type="button" class="close" (click)="infoMessage=''">
<span aria-hidden="true">×</span>
</button>
<i class="fa fa-info-circle fa-1x" aria-hidden="true" placement="right"></i> {{ infoMessage}}
</div>
<div *ngIf="warningMessage" class="alert alert-warning alert-dismissible fade show" (mouseover)="stopTimeout('w')" (mouseout)="_actionService.warningMessage(warningMessage,3)" role="alert">
<button type="button" class="close" (click)="warningMessage=''">
<span aria-hidden="true">×</span>
</button>
<i class="fa fa-bell fa-1x" aria-hidden="true"></i> {{ warningMessage}}
</div>
在我的CSS
文件中,我添加了这个:
.messages {
float: left;
top: 10px;
right: 10px;
width: 100;
height: 20;
padding: 6px;
position: fixed;
border-radius: 8px;
z-index: 9999;
}
这个css代码会在页面右上角放置这个类似toast的消息。然后我创建了action.service.ts
,用于显示此消息并切换我的loader-spinner:
import { Injectable, EventEmitter } from '@angular/core';
@Injectable()
export class ActionService {
public autoloader = true;
public _toggleLoader: EventEmitter<any>;
public _errorMessage: EventEmitter<any>;
public _busyinfoMessage: EventEmitter<any>;
public _warningMessage: EventEmitter<any>;
public _infoMessage: EventEmitter<any>;
public timeoutInfo: any;
public timeoutWarning: any;
constructor() {
this._toggleLoader = new EventEmitter<any>();
this._errorMessage = new EventEmitter<any>();
this._busyinfoMessage = new EventEmitter<any>();
this._warningMessage = new EventEmitter<any>();
this._infoMessage = new EventEmitter<any>();
}
toggleLoader(toggle: boolean) {
this._toggleLoader.emit(toggle);
}
errorMessage(errorMessage: string) {
this._errorMessage.emit(errorMessage);
}
busyinfoMessage(busyinfoMessage: string) {
this._busyinfoMessage.emit(busyinfoMessage);
}
warningMessage(warningMessage: string, timeout: number) {
if (timeout === 0) {
this._warningMessage.emit(warningMessage);
return;
}
this.timeoutWarning = setTimeout(() => {
this._warningMessage.emit('');
}, 1000 * timeout);
this._warningMessage.emit(warningMessage);
}
infoMessage(infoMessage: string, timeout: number) {
if (timeout === 0) {
this._infoMessage.emit(infoMessage);
return;
}
this.timeoutInfo = setTimeout(() => {
this._infoMessage.emit('');
}, 1000 * timeout);
this._infoMessage.emit(infoMessage);
}
stopTimeout(tip: string) {
if (tip === 'w') {
clearTimeout(this.timeoutWarning);
} else {
clearTimeout(this.timeoutInfo);
}
}
}
}
我的app.component.ts
文件我添加了这行代码:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { ActionService } from './action.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit, OnDestroy {
private ngUnsubscribe: Subject<any> = new Subject();
public loader = false;
public errorMessage = '';
public warningMessage = '';
public busyinfoMessage = '';
public infoMessage = '';
constructor(
private _router: Router,
private _actionService: ActionService
) {
}
ngOnInit() {
this._actionService._toggleLoader
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
setTimeout(() => this.loader = res, 0);
});
this._actionService._errorMessage
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
this.errorMessage = res;
});
this._actionService._warningMessage
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
this.warningMessage = res;
});
this._actionService._busyinfoMessage
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
this.busyinfoMessage = res;
});
this._actionService._infoMessage
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
this.infoMessage = res;
});
}
stopTimeout(tip: string) {
this._actionService.stopTimeout(tip);
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
因为我正在使用Angular 5,所以我创建了这个错误拦截器,用于在每次调用后显示错误消息:
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import { ActionService } from './action.service';
import { Router } from '@angular/router';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(
private _actionService: ActionService,
private _router: Router) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request)
.catch((err: HttpErrorResponse, caught) => {
if (err.status === 0) {
this._actionService.errorMessage('Check you connection to interent!');
return Observable.empty<HttpEvent<any>>();
}
if (err.status === 500) {
this._actionService.errorMessage('Server error : ' + err.error.ExceptionMessage);
return Observable.empty<HttpEvent<any>>();
}
if (err.status === 401 || err.status === 403) {
this._router.navigateByUrl('prijava');
return Observable.empty<HttpEvent<any>>();
}
this._actionService.errorMessage('Unknown error. Error message: ' + (err.error.ExceptionMessage || err.error.Message));
return Observable.empty<HttpEvent<any>>();
})
}
}
export const ErrorInterceptorProvider = {
provide: HTTP_INTERCEPTORS,
useClass: ErrorInterceptor,
multi: true
};
由于您使用的是Angular 2,因此我建议您创建HTTP.Service并实现对该服务中的错误的调用。像这样的东西:
import { Injectable, ReflectiveInjector } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '@angular/http';
import { LocatorService } from './locator.service';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { ActionService } from './action.service';
import { Url } from './global';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
@Injectable()
export class HttpService extends Http {
private currentRequests: number;
private _router: Router;
private _actionService: ActionService;
constructor(backend: XHRBackend, options: RequestOptions, router: Router) {
let token = localStorage.getItem('token'); // your custom token getter function here
options.url = Url + (options.url == null ? '' : options.url);
options.headers.set('Authorization', `Bearer ${token}`);
super(backend, options);
this._actionService = LocatorService.injector.get(ActionService);
this._router = router;
this.currentRequests = 0;
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem('token');
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
// let's make option object
options = { headers: new Headers() };
}
options.headers.set('Authorization', `Bearer ${localStorage.getItem('token')}`);
options.url = Url + url;
} else {
// we have to add the token to the url object
if (!options) {
// let's make option object
options = { headers: new Headers() };
}
options.headers.set('Authorization', `Bearer ${localStorage.getItem('token')}`);
url.url = Url + url.url;
}
if (this._actionService.autoloader) { this._actionService.toggleLoader(true); }
return super.request(url, options)
.catch(
this.catchError(this)
)
.finally(() => {
setTimeout(() => {
if (this._actionService.autoloader) { this._actionService.toggleLoader(false); }
}, 100);
}
);
}
private catchError(self: HttpService) {
// we have to pass HttpService's own instance here as `self`
return (res: Response) => {
console.log(res);
switch (res.status) {
case 0:
this._actionService.errorMessage('Check your internet connection!');
return Observable.throw(null);
case 500:
this._actionService.errorMessage('Server error : ' + res.json()['ExceptionMessage']);
return Observable.throw(null);
case 401:
case 403:
this._router.navigateByUrl('prijava');
return Observable.throw(null);
default:
this._actionService.errorMessage('Unknown error. Error message: ' + (res.json()['ExceptionMessage'] || res.json()['Message']));
return Observable.throw(null);
}
};
}
}
我希望就是这样。如果您需要任何澄清,请询问。我希望这能帮到您。
对于错误的用户通知,我使用Angular Material。在运行http查询时。我使用Observable结果中的error =>箭头函数处理来自http observables的错误。例如,这是对我的restful API的身份验证登录查询。
...
constructor(private _dialogService: TdDialogService,
private _viewContainerRef: ViewContainerRef,
private authenticationService: AuthenticationService){}
login() {
this.authenticationService.login(this.formLogin.value.email, this.formLogin.value.password)
.subscribe(
data => {
// Handle any 200 result
},
error => {
// Handle any http errors, 401 UnAuthorized or 500 or any other
this.openAlert('Invalid username or password'); // You can pass in your error message
});
}
openAlert(message: string) {
this._dialogService.openAlert({
message,
disableClose: true,
viewContainerRef: this._viewContainerRef,
title: 'Error',
closeButton: 'Ok'
});
}
}
结果