Angular Диалог материалов не закрывается - PullRequest
0 голосов
/ 17 января 2020

В моем приложении 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);
    });
  }
}

Здесь у меня есть logi c, чтобы проверить, является ли ошибка на стороне сервера или на стороне клиента , Затем я нажимаю соответствующие методы обработки ошибок.

Issue Реальная проблема, с которой я сталкиваюсь, связана с диалоговым окном. Как видите, я открываю диалоговое окно и отображаю компонент ошибки. Этот компонент имеет удобное представление для конечного пользователя. Вот мой компонент диалога ошибки ..

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 для целей тестирования. Это не было в моем исходном коде.

Я добавил две кнопки к моему представлению, чтобы проверить лог ошибок c ...

// 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, открывается диалоговое окно, console.log в ngoninit не запускается ... а когда я нажимаю кнопку закрытия, оно запускается, но afterClosed не открывается и диалоговое окно не закрывается.

Так что мне интересно, в чем проблема ... зоны? не подписаны должным образом на наблюдаемое?

1 Ответ

0 голосов
/ 17 января 2020

Я выяснил, как ее решить ... не уверен в точной проблеме, но смог заставить мой код работать. Вот мой исправленный код ...

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);
    });
  }
}

GlobalErrorHandler

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);
    });
  }
}

Все остальное осталось одни и те же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...