2017-08-10 88 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