2017-08-10 1 views
0

Je souhaite créer un type d'intercepteur pour le gestionnaire d'erreurs. Voilà pourquoi je crée les fichiers:Angular ne voit pas le service injecté

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

Pour que tout point GOES assez bon. Lorsque j'imprime une erreur dans handleError, il s'imprime correctement.

Mais quand je veux passer l'objet ErrorService dans le ErrorComponent soudainement Angulas ne peut pas le voir.

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() { 
    } 

} 

Et ErrorComponent.html

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

Bien sûr, j'ai ajouté quelques importations 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 { } 

Le problème est que dans AppErrorHandler je suis passer l'erreur à ErrorService et je veux afficher dans ErrorComponent mais ErrorComponent ne voit pas les données transmises

MISE À JOUR: J'ai suivi la solution ci-dessous et obtenir une erreur. Mon errorComponent ressemble:

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() { 
    } 

} 

Et le fichier html:

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

Et le problème est que je ne peux pas réellement imprimer la propriété de nom dans le navigateur. Dans la console chrome je: enter image description here

de sorte que vous pouvez voir que je peux easliy obtenir tout l'objet ErrorService mais n'a pas pu obtenir le nom de la propriété qui console est undefined - pourquoi? Et à cause de cela, je ne peux pas l'afficher correctement.

+0

où est le problème ?? quel genre d'erreur obtenez-vous? –

+1

N'utilisez pas @ Inject lors de l'injection de ErrorService dans AppErrorHandler. @Inject est pour les valeurs/types primitifs. Faites juste 'constructor (private errorService: ErrorService) {}'. Voyez si cela fait une différence. –

+0

Le problème est que dans 'AppErrorHandler' je passe l'erreur à' ErrorService' et je veux l'afficher dans 'ErrorComponent' mais' ErrorComponent' ne voit pas les données passées – bielas

Répondre

0

Vous devrez peut-être utiliser forwardRef()

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

export class AppErrorHandler implements ErrorHandler { 

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

    } 

    ... 
} 
1

Voici comment résoudre votre problème:

1) Pour être en mesure d'injecter efficacement ErrorService dans AppErrorHandler, vous voudrez décorer AppErrorHandler avec Injectable(). Avec cela, vous pouvez supprimer le @Inject(ErrorService) et simplement injecter le service de la manière standard.

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

@Injectable() 
export class AppErrorHandler implements ErrorHandler { 

    constructor(private errorService: ErrorService){} 
} 

2) En AppErrorHandler vous ciblez une propriété status de l'objet d'erreur. Gardez à l'esprit que les objets d'erreur standard ont des propriétés telles que message, name, description et number selon le navigateur.Vous pouvez vérifier si la propriété status existe avant d'essayer d'obtenir sa valeur, sinon vous pouvez obtenir undefined pour les erreurs non HTTP.

Mise à jour: assurez-vous d'appeler super(true); et super.handleError(error); ou throw error; pour assurer que les erreurs sont relancées et la gestion des erreurs par défaut se produit après votre traitement d'erreur personnalisée. Sinon, les erreurs seront avalées par le gestionnaire d'erreur personnalisé.

classe export AppErrorHandler implémente 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) Dans votre composant d'erreur, voir activement les modifications apportées à la propriété name du ErrorService, au minimum que vous voudriez faire la propriété name est une propriété publique. Ensuite, dans ErrorComponent, vous ciblez la propriété name du service injecté à afficher. Une approche plus évolutive utiliserait RxJS Subject par exemple pour émettre des modifications auxquelles le ErrorComponent peut s'abonner. L'exécution de message = this.errorService.getName(); ne réinitialisera pas/ne réagira pas automatiquement aux modifications de la propriété name lorsque des erreurs se produisent. Vous devez soit attacher à la propriété publique et/ou utiliser des observables ou similaires pour émettre des modifications aux composants auxquels vous vous abonnez. Voir Mise à jour 2 ci-dessous par exemple de l'utilisation de RxJS Objet de la mise à jour message.

Service:

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> 

Voici une démonstration plunker la fonctionnalité. Cliquez sur le bouton pour déclencher une erreur, en appelant dans ce cas une méthode qui n'existe pas.

Mise à jour:console.log('------ from error component ', errorService.name, this.errorService); dans le constructeur est l'exploitation forestière undefined, car au moment où les constructor() pistes, la propriété publique name n'a pas de valeur par défaut. Si vous voulez une valeur par défaut, vous pouvez définir cela dans ErrorService en faisant public name: string = 'foobar';. Le plunker a été mis à jour pour afficher la journalisation avant et après name de ErrorService en cours de définition. Si vous ajoutez une valeur par défaut dans ErrorService, vous verrez votre journal, imprime la valeur de la propriété name.

Mise à jour 2: Si vous devez absolument utiliser message sur ErrorComponent plutôt que toute autre propriété pour afficher la valeur, y compris publique propriété name de la ErrorService, vous pouvez utiliser le sujet et Observable pour vous abonner à des changements émis à jour la propriété name similaire à Parent/Child Interaction. Cela impliquerait d'activer un nouveau sujet sur ErrorService, exposant la propriété Observable publique et s'abonnant à ces modifications. Cela montre comment utiliser spécifiquement message propriété de ErrorComponent obtenir des valeurs de ErrorService et sa propriété name. Vous n'avez peut-être pas vraiment besoin de la propriété name si le seul but est d'afficher l'erreur dans ErrorComponent. En outre dans le plunker, il affiche le code d'état d'erreur HTTP dans la propriété message de ErrorComponent.

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

Voici une mise à jour plunker.

Espérons que cela aide!

+0

S'il vous plaît jeter un oeil à ma mise à jour. J'ai suivi vos instructions mais je suis tombé sur une erreur qui est cruciale. Es-tu capable de m'aider? – bielas

+0

Au moment où le 'constructor()' dans 'ErrorComponent' s'exécute, il n'y a pas d'erreur affectée à la propriété' name' dans 'ErrorService' car elle n'a pas de valeur par défaut. C'est pourquoi 'nom 'est indéfini quand vous voulez l'enregistrer. J'ai mis à jour le [plunker] (https://plnkr.co/edit/ep2aHZlApeVVt8FNATd5?p=preview) pour montrer avant et après la journalisation 'errorService.name'. Si vous voulez une valeur par défaut pour 'name', dans' ErrorService' vous pouvez faire quelque chose comme 'public name: string = 'foobar'', sinon ce sera' undefined' au moment de 'constructor()'. 'ErrorService' est effectivement singleton lorsqu'il est importé dans le module principal. –

+0

Ceci n'est pas une réponse à ma question. La raison pour laquelle je mentionne mon nom de errorService n'est pas définie ce n'est pas que je voudrais lui assigner du texte comme "foobar". La raison en est que je voudrais attribuer à l'erreur errorService http le statut de l'erreur - par exemple. 500, 403, 404. Et j'ai un exemple que j'appelle erreur intentionnelle et je le vois dans la console comme ma mise à jour ressemble. Mais le think est que je ne peux pas assigner à la variable 'message' (qui est dans la partie' error component') variable de 'errorService.name'. Ce que vous m'avez montré est d'assigner un texte aléatoire à 'errorService.name', ce qui n'est pas mon but. – bielas