web-dev-qa-db-fra.com

Angular: Puis-je utiliser un Observable à la place EventEmitter comme propriété @Output ()?

[angulaire 2.4.5]

J'ai essayé et cela semble fonctionner comme un EventEmitter:

  • Ma composante de l'extérieur:

    <split (visibleTransitionEnd)="log($event)"></split>
    
  • A l'intérieur du composant:

    @Output() visibleTransitionEnd: Observable<string>
    observer: Observer;
    
    constructor() {
      const myObs = new Observable(observer => this.observer = observer);
    
      this.visibleTransitionEnd = myObs
        .map(x => '> ' + x + ' <')
        .debounceTime(20)
        .do(() => console.log('here we are!'));
    }
    
  • Ensuite, je peux appeler à l'intérieur du composant:

    // needed condition because if nobody subscribe 'visibleTransitionEnd' > no observer!
    if(this.observer) this.observer.next('test');
    

Voir ce plongeur

J'aime ça parce qu'il n'y a pas d'abonnement à l'intérieur de mon composant.

Mais est-ce un mauvais moyen d'y parvenir? Quel est le risque/le mal?

Est-il préférable d'utiliser un Subject?

18
bertrandg

Eh bien, dans votre situation, vous pouvez utiliser EventEmitter ou Subject. Vous pouvez voir qu'un EventEmitter est exactement comme Subject (bien qu'il soit recommandé d'utiliser EventEmitter si vous le pouvez). https://github.com/angular/angular/blob/master/modules/%40angular/facade/src/async.ts

La fonction Observable.create (Ou new Observable()) n'est pas destinée à être utilisée de cette façon. La fonction interne doit émettre des valeurs à l'observateur et retourner une fonction de démontage (pour libérer des ressources ou autre). Ne pas conserver en tant que propriété.
Cependant, je ne sais pas quelles conséquences cela pourrait avoir (fuites de mémoire?).

Utilisez plutôt Subject à la place:

export class SplitComponent implements OnDestroy {
  @Output() visibleTransitionEnd: Observable<string>
  visibleTransitionEndObserver: Subject;

  constructor() {
    const subject = new Subject();

    this.visibleTransitionEnd = subject.asObservable()
      .map(x => '> ' + x + ' <')
      .debounceTime(20)
      .do(() => console.log('here we are!'));
  }

  // ...
}
7
martin

EventEmitter étend simplement Subject, ce n'est donc pas une surprise (et j'ai également vu cela déjà dans Dart).

Ils utilisent leur propre classe pour pouvoir modifier l'implémentation ultérieurement sans casser le code existant.

Ce n'est donc peut-être pas la meilleure idée de contourner cette abstraction. Si vous êtes conscient de l'inconvénient et que vous êtes prêt à l'accepter, vous pouvez bien sûr le faire.

10
Günter Zöchbauer

2 raisons de choisir EventEmitter

  1. Angular EventEmitter peut assurer l'événement de façon asynchrone si nécessaire. C'est bon pour une expérience utilisateur réactive.
  2. Encapsulez la mise en œuvre du soulignement. Si un jour, la prochaine version de Angular mettrait à jour la liaison d'événement qui dépend de quelque chose de nouveau de EventEmitter. Ce serait désastreux pour votre projet si Subject est largement utilisé. Je n'en suis pas sûr, mais cela devrait être évité.

Angular EventEmitter étend RxJS Subject à ce jour avec seulement 3 méthodes: 1) constructor(), 2) subscribe(next, error, complete) et 3) nouvelle méthode emit(value) {super.next(value);}

Si vous new EventEmitter(true), il délivrera des événements de manière asynchrone

    constructor(isAsync = false) {
        super();
        this.__isAsync = isAsync;
    }

EventEmitter.subscribe() fait quelque chose pour async événement de livraison selon this._isAsync.

0
xuemind