2017-08-10 53 views
0

我想爲錯誤處理程序創建一種攔截器。這就是爲什麼我創建的文件:Angular沒有看到注入的服務

ErrorService:

import { Injectable } from '@angular/core'; 

    @Injectable() 
    export class ErrorService { 
     name : any; 

     constructor() { 
     } 

     setName(message:string){ 
      this.name = message; 
     } 

     getName(){ 
      return this.name; 
     } 

     error(detail: string, summary?: string): void { 
      this.name = detail; 
     } 
    } 

AppErrorHandler:

import { ErrorService } from './error-service'; 
import { ErrorHandler, Inject } from '@angular/core'; 


export class AppErrorHandler implements ErrorHandler { 

    constructor(@Inject(ErrorService) private errorService: ErrorService){ 

    } 

    handleError(error : any){ 
     this.errorService.setName(error.status); 
     console.log('getter', this.errorService.getName()); 
     console.log('test error ', error);   
    }  
} 

到這一點一切都相當不錯。當我在handleError中打印錯誤時,它會正確打印。

但是當我想通過ErrorService對象到ErrorComponent突然Angulas看不到它。

ErrorComponent:

import { ErrorService } from './../common/error-service'; 
import { Component, OnInit } from '@angular/core'; 

@Component({ 
    selector: 'error', 
    templateUrl: './error.component.html', 
    styleUrls: ['./error.component.css'] 
}) 
export class ErrorComponent implements OnInit { 

    constructor(private errorService: ErrorService) { 
    console.log('from ErrorComponent, ', this.errorService); 
    } 

    message = this.errorService.getName(); 


    ngOnInit() { 
    } 

} 

而且ErrorComponent.html

<div class="alert alert-danger"> 
    Error!!! {{message}} 
</div> 

當然,我已經在app.module增加了一些進口:

import { ErrorComponent } from './error/error.component'; 

@NgModule({ 
    declarations: [ 
... 
    ErrorComponent 
    ], 
    imports: [ 
    BrowserModule, 
    FormsModule, 
    ReactiveFormsModule, 
    HttpModule 
    ], 
    providers: [ 
    PostService, 
    ErrorService, 
    {provide: ErrorHandler, useClass: AppErrorHandler} 

    ], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

的問題是,在AppErrorHandler我將錯誤傳遞給ErrorService和我想在ErrorComponentErrorComponent顯示它並沒有看到傳遞的數據

UPDATE: 我也跟着下面的解決方案,並得到一個錯誤。我errorComponent樣子:

import { ErrorService } from './../common/error-service'; 
import { Component, OnInit } from '@angular/core'; 

@Component({ 
    selector: 'error', 
    templateUrl: './error.component.html', 
    styleUrls: ['./error.component.css'] 
}) 
export class ErrorComponent implements OnInit { 
    errorService: ErrorService; 
    message: string; 

    constructor(errorService: ErrorService) { 
    this.errorService = errorService; 
    console.log('------ from error component ', errorService.name, this.errorService); 
    } 

    ngOnInit() { 
    } 

} 

而且html文件:

<div class="alert alert-danger"> 
    Error!!! {{errorService.name}} 
</div> 

而問題是,我實際上不能在瀏覽器打印的name屬性。在Chrome控制檯我: enter image description here

所以你可以看到,我可以easliy得到整個對象ErrorService但無法得到的屬性名稱這在控制檯undefined - 爲什麼?正因爲如此,我無法正確顯示它。

+0

問題在哪裏?你得到了什麼樣的錯誤? –

+1

將'ErrorService'注入'AppErrorHandler'時,不要使用'@Inject'。 @Inject用於原始值/類型。只要執行'constructor(private errorService:ErrorService){}'。看看這是否有所作爲。 –

+0

問題是在'AppErrorHandler'中,我將錯誤傳遞給'ErrorService',我想將它顯示在'ErrorComponent'中,但是'ErrorComponent'沒有看到傳遞的數據 – bielas

回答

0

您可能需要使用forwardRef()

import { Inject, Injectable, forwardRef } from "@angular/core"; 

export class AppErrorHandler implements ErrorHandler { 

    constructor(@Inject(forwardRef(() => ErrorService)) private errorService: ErrorService){ 

    } 

    ... 
} 
1

這裏是如何解決問題:

1)爲了能夠有效地注入ErrorServiceAppErrorHandler,你會想裝飾AppErrorHandlerInjectable()。有了這個,你可以刪除@Inject(ErrorService),並簡單地以標準方式注入服務。

import { ErrorService } from './error-service'; 
import { ErrorHandler, Injectable } from '@angular/core'; 

@Injectable() 
export class AppErrorHandler implements ErrorHandler { 

    constructor(private errorService: ErrorService){} 
} 

2)在AppErrorHandler您所定位的誤差對象的屬性status。請記住,標準錯誤對象具有諸如message,name,descriptionnumber之類的屬性,具體取決於瀏覽器。在嘗試獲取值之前,您可能需要檢查status屬性是否存在,否則,對於非HTTP錯誤,您可能會獲得undefined

更新:請確保調用super(true);super.handleError(error);throw error;,以確保錯誤重新拋出您的自定義錯誤處理後,會出現默認的錯誤處理。否則,錯誤將被自定義錯誤處理程序吞噬。

出口類AppErrorHandler實現的ErrorHandler {

// ... 

handleError(error : any) { 
    // rethrow exceptions 
    super(true); 

    if(error.status) { 
     console.log(error.status); 
     this.errorService.setName(error.status); 
    } 
    else { 
     console.log('Message: ', error.message); 
     console.log('Description: ', error.description); 
     this.errorService.setName(error.message); 
    } 

    console.log('Getter: ', this.errorService.getName()); 

    // trigger default error handling after custom error handling 
    super.handleError(error); 
}  

}

3)在你的誤差分量,積極看到更改ErrorServicename財產,您至少要想讓name屬性公共屬性。然後在ErrorComponent中,您將定位要注入的服務的name屬性以顯示。更具擴展性的方法是使用RxJS Subject來發出ErrorComponent可以訂閱的更改。在發生錯誤時,執行message = this.errorService.getName();將不會自動重置/響應name屬性的更改。您需要附加到公共屬性和/或使用observables或類似的命令來發布對要訂閱的組件的更改。有關如何利用RxJS更新message的示例,請參見更新2

服務:

import { Injectable } from '@angular/core'; 

@Injectable() 
export class ErrorService { 
    public name : any; 

    constructor() {} 

ErrorComponent HTML

<div class="alert alert-danger"> 
    <!-- Angular will detect changes to the services' --> 
    Error!!! {{errorService.name}} 
</div> 

這裏是一個plunker演示功能。點擊按鈕觸發一個錯誤,在這種情況下調用一個不存在的方法。

更新:console.log('------ from error component ', errorService.name, this.errorService);在構造函數中,因爲在constructor()運行,公共財產name沒有默認值的時間被記錄undefined。如果你想要一個默認值,你可以在ErrorService中設置public name: string = 'foobar';plunker已被更新,以顯示 正在設置之前和之後的日誌記錄。如果您在ErrorService中添加默認值,則會看到您的日誌,並輸出name屬性值。

更新2:如果你絕對需要在ErrorComponent使用message而不是任何其他屬性顯示的值,包括ErrorService的公共name屬性,你可以使用主題和可觀察到訂閱發射的變化進行更新該名稱屬性類似於Parent/Child Interaction。這將涉及在ErrorService上立即啓動一個新主題,公開Observable屬性並訂閱這些更改。這將顯示如何使用的message屬性獲取ErrorService及其name屬性的值。如果唯一目標是在ErrorComponent中顯示錯誤,則您可能不需要name屬性。此外,在plunker中,它正在的ErrorComponent屬性中顯示HTTP錯誤狀態代碼。

@Injectable() 
export class ErrorService { 
    public name: string; 

    // create new Subject 
    private nameSource = new Subject<any>(); 

    // expose Observable property 
    error$ = this.nameSource.asObservable(); 

    setName(message: string){ 
    this.name = message; 
    // emit error 
    this.nameSource.next(this.name); 
    } 

    // ... 
} 

@Component({ // ... }) 
export class ErrorComponent { 
    message: string = ''; 

    constructor(private errorService: ErrorService) { 
    // same stuff as before 

    // subscribe to Observable from ErrorService and update name property on changes 
    this.errorService.error$.subscribe(name => { 
     this.message = name; 
    }); 
    } 
} 

@Injectable() 
export class AppErrorHandler extends ErrorHandler { 
    private errorService: ErrorService; 

    constructor(errorService: ErrorService) { 
     super(true); 
     this.errorService = errorService; 
     console.log(this.errorService); 
    } 

    handleError(error : any) { 
     if(error.status) { 
      console.log(error.status); 
      this.errorService.setName(error.status); 
     } 
     else { 
      console.log('Message: ', error.message); 
      console.log('Description: ', error.description); 
      this.errorService.setName(error.message); 
     } 
    }  
} 

這是更新的plunker

希望有幫助!

+0

請看看我的更新。我遵循了你的指示,但我遇到了一個至關重要的錯誤。你能幫助我嗎? – bielas

+0

當'ErrorComponent'內的'constructor()'運行時,'ErrorService'中的屬性'name'沒有錯誤,因爲它沒有默認值。這就是爲什麼當名稱記錄時'name'不確定的原因。我更新了[plunker](https://plnkr.co/edit/ep2aHZlApeVVt8FNATd5?p=preview),以便在記錄'errorService.name'之前和之後顯示。如果你想爲'name'設置一個默認值,在'ErrorService'中你可以做一些類似'public name:string ='foobar''的操作,否則''constructor()'時會是'undefined'。在主模塊中導入時,'ErrorService'實際上是單例。 –

+0

這不是我的問題的答案。之所以我提到我的errorService名稱沒有被定義,它不是我想給它分配一些文本,比如「foobar」。原因是我想分配給變量errorService http錯誤狀態 - 例如500,403,404。我有一個例子,我打電話的目的錯誤,我看到它在控制檯中,像我的更新看起來像。但是我認爲我無法將其分配給'errorService.name'中的變量'message'(它位於'error component')變量中。你向我展示的是將隨機文本分配給'errorService.name',這不是我的目標。 – bielas

相關問題