2017-08-16 1 views
1

J'ai un composant de notification de toast appelé ToastComponent que je souhaite appeler depuis n'importe quel autre composant. Je mis en œuvre comme ceci:Angular 4 - Le composant @ViewChild est indéfini

ToastComponent:

export class ToastComponent implements OnInit { 

    constructor() {} 

    showToast() { 
    // some code 
    } 
} 

app.component.html:

<llqa-main-container> 
    <llqa-header></llqa-header> 
    <div class="content-container"> 
    <main class="content-area"> 
     <llqa-toast></llqa-toast> <!-- ToastComponent which I want to call --> 
     <router-outlet></router-outlet> 
    </main> 
    </div> 
</llqa-main-container> 

UserManagementComponent qui est à l'intérieur du <router-outlet>:

export class UserManagementComponent implements OnInit { 

    @ViewChild(ToastComponent) toast: ToastComponent; 

    constructor() {} 

    someSaveMethod() { 
    this.toast.showToast() // throws error below 
    } 
} 

En appelant la méthode someSaveMethod(), je Sera l'erreur que toast est indéfini.

Si je prends <llqa-toast></llqa-toast> sur le app.component.html et le mettre sur le user-management.component.html, cela fonctionne très bien, mais alors je dois le mettre dans chaque composant. Comment puis-je faire en sorte que cela fonctionne?

+2

Où est 'someSaveMethod' appelé? Essayez de vérifier avec les instructions 'console.log()' si le constructeur de 'ToastComponent' est appelé avant votre appel à' someSaveMethod'. –

Répondre

3

Puisque dans votre cas, le ToastComponent est utilisé dans le grand parent (AppComponent), c'est la raison pour laquelle vous obtenez cette erreur. Une façon d'éviter cette erreur consiste à utiliser Subject défini dans certains services partagés. J'utilise cette approche dans mon projet pour montrer les notifications toast. Voici comment vous pouvez le faire:


Gardez votre <llqa-toast></llqa-toast> dans app.component.html.

Définissez un service pour émettre un événement et vous abonner à cet événement dans votre ToastComponent. Par exemple,

UtilityService:

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

@Injectable() 
export class UtilityService { 

    public OnShowToast = new Subject<boolean>(); 

    public showToast(): void { 
     this.OnShowToast.next(true); 
    } 
} 

Vous devez injecter ce service dans vos AppModule fournisseurs. Maintenant subscribe à l'événement OnShowToast dans votre ToastComponent.

ToastComponent:

import { UtilityService } from './path/to/the/utility.service'; 
export class ToastComponent implements OnInit { 

    constructor(private readonly utilityService: UtilityService) { } 

    ngOnInit() { 
    this.utilityService.OnShowToast.subscribe(value => 
     { 
      this.showToast(); 
     }); 
    } 

    private showToast() { 
    // some code 
    } 
} 

Maintenant, vous pouvez appeler la méthode showToast() du UtilityService de tout composant que vous voulez. Par exemple,

UserManagementComponent

export class UserManagementComponent implements OnInit { 

    // You dont need this now 
    // @ViewChild(ToastComponent) toast: ToastComponent; 

    constructor(private readonly utilityService: UtilityService) {} 

    someSaveMethod() { 
    this.utilityService.showToast(); 
    } 
} 
+1

'EventEmitter' n'est pas censé être utilisé dans les services. Un 'Observable' ou' Subject' fait de même. 'EventEmitter' est supposé être utilisé ** seulement ** pour' @Output() 's. –

+0

@ GünterZöchbauer Je ne le savais pas, car il travaillait également sans problèmes dans mon service. Merci. Mettre à jour mon code ici aussi pour utiliser 'Subject' à la place. – Faisal

+1

Actuellement, ça marche parce que 'EventEmitter' étend simplement' Subject' (AFAIR), mais l'équipe Angular peut changer cela sans préavis à une implémentation personnalisée qui fonctionne encore pour '@Output()' mais pourrait casser d'autres utilisations, parce que '@ Output() 'est la seule chose pour laquelle' EventEmitter' est supposé être utilisé. –