Come iscriversi a un evento su un servizio in Angular2?


112

So come generare un evento con EventEmitter. Posso anche allegare un metodo da chiamare se ho un componente come questo:

<component-with-event (myevent)="mymethod($event)" />

Quando ho un componente come questo, tutto funziona alla grande. Ho spostato una logica in un servizio e ho bisogno di generare un evento dall'interno del servizio. Quello che ho fatto è stato questo:

export class MyService {
  myevent: EventEmitter = new EventEmitter();

  someMethodThatWillRaiseEvent() {
    this.myevent.next({data: 'fun'});
  }
}

Ho un componente che deve aggiornare un valore in base a questo evento ma non riesco a farlo funzionare. Quello che ho provato è stato questo:

//Annotations...
export class MyComponent {
  constructor(myService: MyService) {
    //myService is injected properly and i already use methods/shared data on this.
    myService.myevent.on(... // 'on' is not a method <-- not working
    myService.myevent.subscribe(.. // subscribe is not a method <-- not working
  }
}

Come faccio a far iscrivere MyComponent all'evento quando il servizio che lo genera non è un componente?

Sono su 2.0.0-alpha.28

EDIT: modificato il mio "esempio di lavoro" in modo che funzioni effettivamente, quindi è possibile concentrarsi sulla parte non funzionante;)

Codice di esempio: http://plnkr.co/edit/m1x62WoCHpKtx0uLNsIv


1
Potrebbe essere più una questione di progettazione come servizio che non dovrebbe emettere eventi per conto di un componente, poiché ciò accoppia strettamente il servizio al componente. ad esempio, cosa succede se ci sono più istanze del componente, dovrebbero tutte emettere eventi in quel caso?
Angular University

@jhadesdev ti ho letto. Ho ridisegnato la soluzione in modo che il servizio non debba più emettere il risultato. Penso ancora che alcuni progetti trarrebbero vantaggio dalla possibilità di sollevare eventi, a seconda del tipo di "servizio" che è ...
Per Hornshøj-Schierbeck

un modo quindi potrebbe essere quello di far creare al componente l'emettitore di eventi invece del servizio, quindi passare l'emettitore di eventi come argomento al servizio
Angular University

Risposte:


135

Aggiornamento : ho trovato un modo migliore / corretto per risolvere questo problema utilizzando un BehaviorSubject o un Observable piuttosto che un EventEmitter. Si prega di consultare questa risposta: https://stackoverflow.com/a/35568924/215945

Inoltre, i documenti Angular ora hanno un file esempio di libro di cucina che utilizza un oggetto .


Risposta originale / obsoleta / sbagliata: di nuovo, non utilizzare un EventEmitter in un servizio . Questo è un anti-pattern.

Utilizzando beta.1 ... NavService contiene EventEmiter. Component Navigation emette eventi tramite il servizio e il componente ObservingComponent si iscrive agli eventi.

nav.service.ts

import {EventEmitter} from 'angular2/core';
export class NavService {
  navchange: EventEmitter<number> = new EventEmitter();
  constructor() {}
  emitNavChangeEvent(number) {
    this.navchange.emit(number);
  }
  getNavChangeEmitter() {
    return this.navchange;
  }
}

components.ts

import {Component} from 'angular2/core';
import {NavService} from '../services/NavService';

@Component({
  selector: 'obs-comp',
  template: `obs component, item: {{item}}`
})
export class ObservingComponent {
  item: number = 0;
  subscription: any;
  constructor(private navService:NavService) {}
  ngOnInit() {
    this.subscription = this.navService.getNavChangeEmitter()
      .subscribe(item => this.selectedNavItem(item));
  }
  selectedNavItem(item: number) {
    this.item = item;
  }
  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

@Component({
  selector: 'my-nav',
  template:`
    <div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
    <div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
  `,
})
export class Navigation {
  item = 1;
  constructor(private navService:NavService) {}
  selectedNavItem(item: number) {
    console.log('selected nav item ' + item);
    this.navService.emitNavChangeEvent(item);
  }
}

Plunker


L'ho seguito, ma funziona solo per la classe stessa. Non funziona per un'altra classe (da un altro file). Sembra che il problema sia nell'istanza della classe di servizio. Esiste comunque per rendere statica la classe del servizio?
asubanovsky

5
@asubanovsky, nel plunker inietto NavService solo a livello di bootstrap (ovvero, componente root), quindi dovrebbe esserci solo un'istanza del servizio per l'intera app. Lo stai iniettando altrove providers: [NavService]? In tal caso, otterrai più istanze del servizio.
Mark Rajcok

Grazie mille. Ora funziona secondo le mie aspettative. Ora capisco la differenza tra l'iniezione dei provider a livello di bootstrap e a livello di componente.
asubanovsky

Questo post è stato seriamente modificato in uno stato in cui non lo "capisco" più. Perché chiamare un mehtod sul servizio .getNavChangeEmitter () che restituisce EventEmitter è diverso dall'abbonamento diretto a navChange?
Per Hornshøj-Schierbeck

@ PerHornshøj-Schierbeck, ho utilizzato il metodo getNavChangeEmitter () per nascondere il fatto che un EventEmitter veniva utilizzato all'interno del servizio. Gli utenti del metodo potrebbero presumere che l'oggetto restituito abbia un subscribe()metodo. Utilizzando un metodo, possiamo facilmente cambiare l'EventEmitter in un Subject o un Observable, il che è molto meglio, poiché ora abbiamo appreso che EventEmitter dovrebbe essere utilizzato solo per le proprietà di output. Il modo corretto è usare un Subject, BehaviorSubject o Observable, e normalmente ci iscriviamo direttamente a questi, quindi non abbiamo più bisogno di un metodo getNavChangeEmitter ().
Mark Rajcok

6

Utilizzando alpha 28, ho realizzato la sottoscrizione programmatica agli emettitori di eventi tramite il eventEmitter.toRx().subscribe(..)metodo. Poiché non è intuitivo, potrebbe forse cambiare in una versione futura.


1
forse fornire un semplice esempio per le persone da utilizzare se si imbattono in questo post? Non sono stato io a votare meno;)
Per Hornshøj-Schierbeck

2
Non so perché è stato votato negativamente, certamente funziona. In poche parole, per iscriverti a un "clic" che click.toRx().subscribe(your_callback_function)
emette

Penso che potrebbe essere stato sottovalutato perché manca un esempio funzionante? So che varrebbe un voto positivo e forse una risposta accettata se avesse un collegamento a un violino pluncker / jsfiddle o anche alcune righe di codice per visualizzare meglio la sintassi;)
Per Hornshøj-Schierbeck

Ricevo ECCEZIONE: ReferenceError: il clic non è definito @Runeboy Puoi fornire un plnkr per la tua soluzione?
Benjamin McFerren

Devi definire un EventEmitter chiamato click affinché funzioni
Mazen Elkashef
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.