2016-06-13 40 views
3

我正試圖在Angular 2應用程序中實現自定義ExceptionHandler,該應用程序向未定義的AlertsService提交未被捕獲的錯誤。目標是允許主要App組件訂閱AlertsService提供的警報,以便它可以在UI中顯示錯誤。Angular 2:自定義ExceptionHandler更改檢測延遲

我看到的問題是,直到遇到其他錯誤時,自定義ExceptionHandler提交給AlertsService的錯誤纔會反映在UI中。這會導致UI永遠只是AlertsService實際提供的內容之一。

我的猜測是,這種行爲與變化檢測和ExceptionHandler的特殊情況有關,但我不確定從哪裏去。期待Angular2專家的幫助!下面

示例代碼,普拉克在這裏:https://plnkr.co/edit/xPoWCELA9IHqeLBS4wXs?p=preview

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

回答

7

更新ExceptionHandler更名爲ErrorHandlerhttps://stackoverflow.com/a/35239028/217408

orgiginal

變化檢測是不是在年底運行的0處理程序拋出時發生的事件。

您可以手動調用變化檢測,而是因爲你需要一個ApplicationRef參考,並ApplicationRef取決於ExceptionHandler這使得一個整潔的週期和DI無法解決循環依賴,這變得有點複雜。

一種解決方法是代替ApplicationRef注入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

+0

感謝您的快速響應。因此,如果我正確理解這一點,則更新異常處理程序以手動觸發更改檢測以處理因異常而未觸發更改檢測的情況?不完全直觀,但它的作品。 – WayneC

+0

我想在異常之後做一個額外的更改檢測週期是安全的。它不應該太頻繁;-)可能有更好的方法。我不是自定義異常處理程序實現方面的專家。 –

+0

在我接受此標記之前,請遵循一個問題。另外,在按鈕點擊處理程序中,錯誤被推送到ChildComponent的錯誤[]。即使我們現在在ExceptionHandler中手動運行更改檢測,該值也不會在UI中更新。任何想法爲什麼? – WayneC