94 votes

L'enfant écoute l'événement du parent dans Angular 2

Dans la documentation d'Angular, il y a un sujet sur l'écoute des événements des parents pour les enfants. C'est très bien. Mais mon objectif est quelque chose d'inverse. Dans mon application, il y a un 'admin.component' qui contient la vue de la page d'administration (menu latéral, barre de tâches, statut etc ). Dans ce composant parent, j'ai configuré un système de routeur pour changer la vue principale entre les autres pages de l'administrateur. Le problème est que pour sauvegarder les choses après le changement, l'utilisateur clique sur le bouton de sauvegarde dans la barre des tâches (qui est placée dans admin.component) et le composant enfant doit écouter cet événement de clic pour faire la sauvegarde du personnel.

2 votes

Il semble que la meilleure pratique pour faire cela soit d'utiliser un service et un observable qui distribue l'événement.

0 votes

Votre question n'est pas très éloignée de celle-ci : stackoverflow.com/questions/35560860/

0 votes

@freethebees La solution est peut-être la même, mais la forme du problème est différente et mon intention est de trouver la meilleure approche pour cette situation.

129voto

Steve Paul Points 135

Pour la postérité, j'ai juste pensé à mentionner la solution la plus conventionnelle à ce problème : Il suffit d'obtenir une référence au ViewChild et d'appeler directement l'une de ses méthodes.

@Component({
  selector: 'app-child'
})
export class ChildComponent {

  notifyMe() {
    console.log('Event Fired');
  }
}

@Component({
  selector: 'app-parent',
  template: `<app-child #child></app-child>`
})
export class ParentComponent {

  @ViewChild('child')
  private child: ChildComponent;

  ngOnInit() {
    this.child.notifyMe();
  }
}

3 votes

Il se bloque dès que j'entre dans le composant parent... Cannot read property 'notifyMe' of undefined .

0 votes

Apparemment, votre composant enfant n'est pas défini par Angular. Assurez-vous que ChildComponent a le bon sélecteur.

0 votes

Génial, contrairement à la réponse acceptée, cette solution ne nécessite aucune librairie supplémentaire (même si RxJS est standard pour Angular2 =))

113voto

thierry templier Points 998

Je pense que ce document pourrait vous être utile :

En fait, vous pourriez tirer parti d'un observable / sujet que le parent fournit à ses enfants. Quelque chose comme ça :

@Component({
  (...)
  template: `
    <child [parentSubject]="parentSubject"></child>
  `,
  directives: [ ChildComponent ]
})
export class ParentComponent {
  parentSubject:Subject<any> = new Subject();

  notifyChildren() {
    this.parentSubject.next('some value');
  }
}

La composante enfant peut simplement souscrire à ce sujet :

@Component({
  (...)
})
export class ChildComponent {
  @Input()
  parentSubject:Subject<any>;

  ngOnInit() {
    this.parentSubject.subscribe(event => {
      // called when the notifyChildren method is
      // called in the parent component
    });
  }

  ngOnDestroy() {
    // needed if child gets re-created (eg on some model changes)
    // note that subsequent subscriptions on the same subject will fail
    // so the parent has to re-create parentSubject on changes
    this.parentSubject.unsubscribe();
  }

}

Sinon, vous pourriez tirer parti d'un service partagé contenant un tel sujet de la même manière...

0 votes

Le callback dans mon composant enfant ne s'exécutera pas si le composant parent ne diffuse pas la valeur suivante à partir de ngInit. Pourquoi est-ce le cas ?

5 votes

Y a-t-il des avantages à utiliser cette méthode plutôt que ViewChild ?

0 votes

Bien qu'il ait l'air plus professionnel, après quelques heures d'expérimentation dans ma situation, je n'ai pas pu éviter les UnsubscribeErrors lors de l'ajout/la suppression d'éléments enfants (et donc le désabonnement du sujet). J'ai donc opté pour la réponse beaucoup plus simple de @StephenPaul au moyen de TimeBoxing. En tout cas, merci pour la réponse et probablement que je ne maîtrise pas assez bien la bibliothèque rxjs pour la comprendre pleinement et faire les bons ajustements (supplémentaires) à votre exemple pour qu'il fonctionne parfaitement.

16voto

charsi Points 1058

Si je comprends bien la question, il serait possible d'adopter une approche plus simple. Hypothèses --

  • L'OP dispose d'un bouton d'enregistrement dans le composant parent
  • Les données qui doivent être sauvegardées se trouvent dans les composants enfants
  • Toutes les autres données dont le composant enfant pourrait avoir besoin sont accessibles à partir des services

Dans le composant parent

<button type="button" (click)="prop1=!prop1">Save Button</button>
<app-child-component [setProp]='prop1'></app-child-component>

Et dans l'enfant

prop1:boolean;
  @Input()
  set setProp(p: boolean) {
    // -- perform save function here
}

Cela permet simplement d'envoyer le clic sur le bouton au composant enfant. À partir de là, le composant enfant peut enregistrer les données de manière indépendante.

EDIT : si les données du modèle parent doivent également être transmises avec le clic sur le bouton, cela est également possible avec cette approche. Faites-moi savoir si c'est le cas et je mettrai à jour les exemples de code.

0voto

Bazidoa Points 24

Pour ceux qui obtiennent Cannot read property 'notifyMe' of undefined

Essayez d'appeler la méthode à l'intérieur de ngAfterViewInit() au lieu de ngOnInit()

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X