我正在尝试在Angular 2应用程序中实现自定义ExceptionHandler,该应用程序将未捕获的错误提交给自定义AlertsService。目的是允许主要App组件订阅AlertsService提供的警报,以便它可以在UI中显示错误。

我看到的问题是,在遇到另一个错误之前,自定义AlertsService提交给ExceptionHandler的错误不会反射(reflect)在UI中。这导致UI始终是AlertsService实际提供的内容背后的一个警报。

我的猜测是,此行为与更改检测和ExceptionHandler的特殊情况有关,但是我不确定从这里开始。向Angular2专家寻求帮助!

下面的示例代码,plunk here:

import { Component, ExceptionHandler, Injectable, OnInit, provide } from '@angular/core';
import { bootstrap } from '@angular/platform-browser-dynamic';
import { Subject } from 'rxjs/Subject'

export interface Alert {
  message: string;
}

@Injectable()
export class AlertsService {

  private alertTriggeredSubject = new Subject<Alert>();

  alertTriggered = this.alertTriggeredSubject.asObservable();

  triggerAlert(message: string) {
    this.alertTriggeredSubject.next(<Alert>{ message: message });
  }

}

@Injectable()
export class CustomExceptionHander {

  constructor(private alertsService: AlertsService) { }

  call(exception, stackTrace = null, reason = null) {
    this.alertsService.triggerAlert(exception.originalException);
    console.error('EXCEPTION:', exception);
  }
}

@Component({
  selector: 'child-component',
  template : `
  <h3>Child</h3>
  <div id="child">
    <button (click)="breakMe()">Break Me!</button>
    <div>Alerts Sent:</div>
    <ul><li *ngFor="let error of errors">{{error}}</li></ul>
  </div>`
})
export class ChildComponent {

  errors: string[] = [];
  numErrors = 0

  breakMe() {
    this.numErrors++;
    let error = `I broke it (${this.numErrors})`;

    // The error added to the array below is never reflected in the
    // "Alerts Sent:" <ul>...not sure why
    this.errors.push(error);
    console.info('ChildComponent.errors', this.errors);

    // Simulate unhandled exception
    throw new Error(error);
  }
}

@Component({
  selector: 'my-app',
  template : `
  <h3>Parent</h3>
  <div id="parent">
    <div>Alerts Received:</div>
    <ul><li *ngFor="let alert of alerts">{{alert.message}}</li></ul>
    <child-component></child-component>
  </div>`
  directives: [ChildComponent]
})
export class App implements OnInit {

  constructor(private alertsService: AlertsService) { }

  alerts: Alert[] = [];

  ngOnInit() {
    this.alertsService.alertTriggered.subscribe(alert => {
      this.alerts.push(alert);

      // Alert gets received, but is not reflected in the UI
      // until the next alert is received, even thought the
      // alerts[] is up-to-date.
      console.info('App alert received:', alert);
      console.info('App.alerts:', this.alerts);
    });
  }
}

bootstrap(App, [
    AlertsService,
    provide(ExceptionHandler, { useClass: CustomExceptionHander })
]).catch(err => console.error(err));

最佳答案

更新 ExceptionHandler重命名为ErrorHandler https://stackoverflow.com/a/35239028/217408

原始

处理程序引发时,更改检测不会在click事件的末尾运行。

您可以手动调用更改检测,但这会变得有些复杂,因为您需要ApplicationRef引用,并且ApplicationRef取决于ExceptionHandler,这使整个周期整齐,并且DI无法解决循环依赖性。

一种解决方法是代替ApplicationRef注入(inject)Injector并强制性地获取AplicationRef,例如

constructor(private alertsService: AlertsService, injector:Injector) {
  setTimeout(() => this.appRef = injector.get(ApplicationRef));
}

然后在call中调用更改检测,例如

call(exception, stackTrace = null, reason = null) {
  this.alertsService.triggerAlert(exception.originalException);
  this.appRef.tick();
  console.error('EXCEPTION:', exception);
}

Plunker example

关于angular - 自定义ExceptionHandler更改检测滞后,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37793276/

10-16 15:51