66 votes

Comment retourner une valeur à partir d'une fonction EventEmitter ?

J'ai obtenu cette fonction dans mon core composant :

 isValid(value: any) {

   // Do some stuff and return something based on the result

   return false;
 }

Que je passe à la other-component comme ça :

<other-component (onBeforeAdding)="isValid($event)"></other-component>

Et dans other-component J'ai obtenu ceci EventEmitter qui doit s'exécuter avant les autres choses et renvoyer une valeur indiquant qu'une valeur est valide ou non :

 @Output() onBeforeAdding: EventEmitter<any> = new EventEmitter();

 let isValid = this.onBeforeAdding.emit(value) || true;

 if (isValid) {

   // Do stuff
 }

Le problème ici est qu'un EventEmitter ne peut pas retourner une valeur puisqu'elle est asynchrone (bien que, d'après la rc2, il semble que cela soit optionnel en passant true à la fonction new EventEmitter fonction ? Même en le faisant, cela ne résoudra pas le problème). Ainsi, isValid sera toujours vrai, quel que soit le résultat de la fonction.

Comment puis-je renvoyer une valeur à partir du EventEmitter fonction ?

102voto

Isaac Points 1423

La réponse courte est que vous ne pouvez pas faire ça avec @Output mais vous pouvez faire quelque chose de très similaire avec @Input .

Même fonction dans core composant :

isValid(value: any): boolean {
  // Do some stuff and return something based on the result
  return false;
}

Passez la définition de la fonction dans other-component comme un @Input :

<other-component [onBeforeAddingProcessor]="isValid"></other-component>

Sur other-component :

@Input() onBeforeAddingProcessor: (value: any) => boolean;

ngOnInit() {
  // onBeforeAddingProcessor won't be defined in the constructor
  let isValid = this.onBeforeAddingProcessor(value);

  if (isValid) {
    // Do stuff
  }
}

Méthodes d'accès this

Si vous devez accéder this dans la fonction que vous fournissez, alors il est nécessaire de passer une méthode qui a déjà le this-context lié :

isValid = (value: any) => {
  return this.myService.checkValue(value);
}

Sinon, Angular appelle la méthode avec this du composant, et non le consommateur du composant. Petit conseil concernant les performances (bien qu'il n'ait pas été testé) : si cette méthode est volumineuse et que le nombre d'instances du composant est élevé, vous devez factoriser les parties les plus importantes du code dans une fonction membre privée et appeler cette fonction à partir de l'endroit où elle a été factorisée. Motif : Le code ci-dessus ne crée pas une fonction sur le prototype de la classe, mais imprime une copie de cette fonction pour chaque instance du composant. Cela peut consommer beaucoup de mémoire, ce qui peut être évité facilement.

7 votes

J'adore quand les premières phrases d'une réponse de stack overflow fonctionnent pour moi, et quand un problème sans rapport survient, la même réponse anticipe et répond même à ce problème ; merci à @hgoebl pour "Si vous devez accéder à ceci dans la fonction que vous fournissez". Je le fais ! this a le service que j'appelle !

2 votes

... et en lisant la réponse à la question, j'ai appris quelque chose de nouveau (bien sûr implicite dans l'édition de hgoebl) ; que les lambdas sont des "grosses flèches"... lieront this donc il ne peut pas être changé.

0 votes

C'est aussi un bon moyen d'utiliser @Input au lieu de @Output lorsque vous avez besoin de la valeur retournée sur le composant enfant.

4voto

thierry templier Points 998

Vous devez vous abonner à l'émetteur d'événements pour obtenir la valeur :

this.onBeforeAdding.emit(value || true);

this.onBeforeAdding.subscribe(isValid => {
  if (isValid) {
    // Do stuff
  }
});

0 votes

0 votes

Je dois exécuter la fonction qui appelle le onBeforeAdding deux fois avant que la méthode d'abonnement ne s'exécute. Savez-vous pourquoi ?

0 votes

Oui d'accord, c'est seulement pour les sorties composantes. Il semble que ce soit le cas ici ;-)

2voto

imal365 Points 39

Cela est possible sans grand effort

  1. Créez un EventEmitter dans votre composant enfant

    @Output('request_data') requestData : EventEmitter = new EventEmitter() ;

  2. créer une méthode pour demander des données dans votre composant enfant, l'astuce ici est de passer un objet avec une fonction anonyme

    click() { this.requestData.emit({ données : "quelques-données", func : (data_from_parent => { //faites ce que vous voulez }) }) ; }

  3. Depuis votre composant parent, faites ce que vous voulez et appelez la fonction

    callFromChild(obj) { //obj.data //obj.func() ; }

0voto

Le site émettent envoie un signal de diffusion à tous auditeurs en passant la valeur que vous avez déterminée. Je pense que le isValid doit émettre l'événement, parce que l'élément responsabilité de Émetteur d'événements est d'émettre des événements et non de valider des choses. Comment voulez-vous exactement écrire ce flux isValid ?

0voto

maxisam Points 8843

Je vous suggère de construire un petit exemple.

Mais voici comment je comprends votre question.

Je pense que vous devriez utiliser une autre propriété avec EventEmitter parce que vous essayez d'obtenir le retour de isValid() du composant principal et EventEmitter est seulement une rue à sens unique.

Je vais donc créer une variable observable et l'assigner à l'autre composant pour qu'il puisse s'y abonner. Lorsque isValid() est exécuté, utiliser next pour publier une nouvelle valeur.

Un exemple simple est que vous pouvez vous abonner à valueChanges à partir d'un contrôle de formulaire.

La réponse de @Isaac utilise @input mais si vous voulez utiliser des observables pour cela, ma solution sera plus adaptée.

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