[英]Angular Material Dialog Not Closing
在我的 Angular 應用程序中,我使用“材質”對話框來顯示最終用戶出現的任何錯誤消息。 我構建了一個錯誤服務,它可以有與服務器端 (http) 錯誤和客戶端錯誤交互的方法。
import { Injectable } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ErrorService {
getClientMessage(error: Error): string {
if (!navigator.onLine) {
return 'No Internet Connection';
}
return error.message ? error.message : error.toString();
}
getClientStack(error: Error): string {
return error.stack;
}
getServerMessage(error: HttpErrorResponse): string {
console.log(error.statusText);
return error.statusText;
}
getServerStack(error: HttpErrorResponse): string {
// handle stack trace
return 'stack';
}
}
我正在使用 http 攔截器來獲取 http 錯誤。
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor() {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retry(1),
catchError((error: HttpErrorResponse) => {
return throwError(error);
})
);
}
}
如您所見,我重試一次端點命中,然后捕獲任何錯誤。 然后,我通過擴展 Angular ErrorHandler 的全局錯誤處理程序運行所有錯誤。
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import {
HttpErrorResponse,
HttpHeaders,
HttpClient
} from '@angular/common/http';
import { PathLocationStrategy } from '@angular/common';
import { throwError, Observable } from 'rxjs';
import * as StackTrace from 'stacktrace-js';
import { LoggerService } from '../core/logger.service';
import { ErrorService } from '../core/error.service';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';
@Injectable({
providedIn: 'root'
})
export class GlobalErrorHandler implements ErrorHandler {
// Error handling is important and needs to be loaded first.
// Because of this we should manually inject the services with Injector.
constructor(
private injector: Injector,
public dialog: MatDialog,
private http: HttpClient
) {}
// Function to handle errors
handleError(error: Error | HttpErrorResponse) {
const errorService = this.injector.get(ErrorService);
const logger = this.injector.get(LoggerService);
console.log('error: ', error);
// Header options for http post
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
// Message variable to hold error message
let message;
// Variable to hold stacktrace
let stacktrace;
// Variable to hold url location of error
const url = location instanceof PathLocationStrategy ? location.path() : '';
if (error instanceof HttpErrorResponse) {
// Server error
message = errorService.getServerMessage(error);
stacktrace = errorService.getServerStack(error);
} else {
// Client Error
message = errorService.getClientMessage(error);
stacktrace = errorService.getClientStack(error);
}
// log errors
logger.logError(message, stacktrace);
console.log('message: ', message);
this.openDialog(message);
return throwError(error);
}
openDialog(data): void {
const dialogRef = this.dialog.open(ErrorDialogComponent, {
width: '60%',
data: data
});
dialogRef.afterClosed().subscribe((result) => {
// Redirect back to home (dashboard)?
console.log('in afterClosed: ' + result);
});
}
}
這是我有邏輯來檢查錯誤是服務器端還是客戶端的地方。 然后我點擊了相應的錯誤服務方法。
發出我有真正的問題是該對話框。 如您所見,我正在打開一個對話框並顯示一個錯誤組件。 該組件為最終用戶提供了用戶友好的視圖。 這是我的錯誤對話框組件..
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'app-error-dialog',
templateUrl: './error-dialog.component.html'
})
export class ErrorDialogComponent implements OnInit {
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
private dialogRef: MatDialogRef<ErrorDialogComponent>
) {}
ngOnInit() {
console.log('data in oninit: ', this.data);
}
/**
* onCancelClick method
* Closes the Material Dialog
*
* @returns :void
*
*/
onCloseClick(): void {
console.log('data in onCloseClick: ', this.data);
this.dialogRef.close('Eureka!');
}
}
注意:我添加了 oninit 用於測試目的。 它不在我的原始代碼中。
我在視圖中添加了兩個按鈕來測試錯誤邏輯...
// html
<button (click)="throwError()">Error</button>
<button (click)="throwHttpError()">HTTP</button>
// component
throwError() {
throw new Error('My Error');
}
throwHttpError() {
this.http.get('someUrl').subscribe();
}
當我單擊客戶端錯誤時,一切都按照設計進行。 當我單擊 http 錯誤按鈕時,它會打開對話框,ngoninit 中的 console.log 不會觸發……當我單擊關閉按鈕時,它會觸發,但 afterClosed 不會並且對話框不會關閉。
所以我想知道問題可能是什么......區域? 沒有正確訂閱可觀察對象?
我想出了如何解決它......不確定確切的問題,但能夠讓我的代碼工作。 這是我修改后的代碼...
HttpErrorInterceptor
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpErrorResponse,
HttpHeaders
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';
import { PathLocationStrategy } from '@angular/common';
import { ErrorService } from './error.service';
import { LoggerService } from './logger.service';
@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
constructor(
public dialog: MatDialog,
private errorService: ErrorService,
private logger: LoggerService
) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retry(1),
catchError((error: HttpErrorResponse) => {
// Message variable to hold error message
let errorMessage = '';
// Variable to hold stacktrace
let stacktrace;
// Variable to hold url location of error
const url =
location instanceof PathLocationStrategy ? location.path() : '';
// Header options for http post
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
// server-side error
errorMessage = this.errorService.getServerMessage(error);
stacktrace = this.errorService.getServerStack(error);
// log errors
this.logger.logError(errorMessage, stacktrace);
if (typeof errorMessage !== 'undefined') {
this.openDialog(errorMessage);
} else {
this.openDialog('undefined');
}
return throwError(errorMessage);
})
);
}
openDialog(data): void {
const dialogRef = this.dialog.open(ErrorDialogComponent, {
width: '60%',
data: data
});
dialogRef.afterClosed().subscribe(result => {
// Redirect back to home (dashboard)?
console.log('in afterClosed http: ' + result);
});
}
}
全局錯誤處理程序
import { ErrorHandler, Injectable, Injector } from '@angular/core';
import {
HttpErrorResponse,
HttpHeaders,
HttpClient
} from '@angular/common/http';
import { PathLocationStrategy } from '@angular/common';
import { throwError, Observable } from 'rxjs';
import * as StackTrace from 'stacktrace-js';
import { LoggerService } from '../core/logger.service';
import { ErrorService } from '../core/error.service';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';
@Injectable({
providedIn: 'root'
})
export class GlobalErrorHandler implements ErrorHandler {
// Error handling is important and needs to be loaded first.
// Because of this we should manually inject the services with Injector.
constructor(
private injector: Injector,
public dialog: MatDialog,
private http: HttpClient
) {}
// Function to handle errors
handleError(error: Error) {
const errorService = this.injector.get(ErrorService);
const logger = this.injector.get(LoggerService);
// Header options for http post
const options = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
// Message variable to hold error message
let errorMessage;
// Variable to hold stacktrace
let stacktrace;
// Variable to hold url location of error
const url = location instanceof PathLocationStrategy ? location.path() : '';
if (error instanceof Error) {
// Client Error
errorMessage = errorService.getClientMessage(error);
stacktrace = errorService.getClientStack(error);
this.openDialog(errorMessage);
}
// log errors
logger.logError(errorMessage, stacktrace);
return throwError(error);
}
openDialog(data): void {
const dialogRef = this.dialog.open(ErrorDialogComponent, {
width: '60%',
data: data
});
dialogRef.afterClosed().subscribe(result => {
// Redirect back to home (dashboard)?
console.log('in afterClosed error: ' + result);
});
}
}
其他一切都保持不變。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.