Bagaimana cara berlangganan acara pada layanan di Angular2?


112

Saya tahu cara meningkatkan acara dengan EventEmitter. Saya juga dapat melampirkan metode untuk dipanggil jika saya memiliki komponen seperti ini:

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

Ketika saya memiliki komponen seperti ini, semuanya bekerja dengan baik. Saya memindahkan beberapa logika ke dalam sebuah layanan dan saya perlu memunculkan sebuah acara dari dalam Layanan. Apa yang saya lakukan adalah ini:

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

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

Saya memiliki komponen yang perlu memperbarui beberapa nilai berdasarkan acara ini tetapi sepertinya saya tidak dapat membuatnya berfungsi. Yang saya coba adalah ini:

//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
  }
}

Bagaimana cara membuat MyComponent berlangganan ke acara jika layanan yang memunculkannya bukan merupakan komponen?

Saya menggunakan On 2.0.0-alpha.28

EDIT: Modifikasi "contoh kerja" saya menjadi benar-benar berfungsi, sehingga fokus dapat diletakkan pada bagian yang tidak berfungsi;)

Kode contoh: http://plnkr.co/edit/m1x62WoCHpKtx0uLNsIv


1
Ini bisa jadi lebih merupakan masalah desain karena layanan tidak boleh memancarkan peristiwa atas nama komponen, karena itu secara erat memasangkan layanan ke komponen. misalnya bagaimana jika ada beberapa contoh komponen, haruskah mereka semua mengeluarkan kejadian dalam kasus itu?
Universitas Angular

@jhadesdev Saya membaca Anda. Saya mendesain ulang solusinya sehingga layanan tidak lagi perlu memberikan hasil. Saya masih berpikir beberapa desain akan mendapat keuntungan dari dapat mengadakan acara - tergantung jenis "layanan" itu ...
Per Hornshøj-Schierbeck

salah satu caranya adalah dengan membuat komponen membuat event emitter alih-alih layanan, dan kemudian meneruskan event emitter sebagai argumen ke layanan
Angular University

Jawaban:


135

Pembaruan : Saya telah menemukan cara yang lebih baik / tepat untuk memecahkan masalah ini menggunakan BehaviorSubject atau Observable daripada EventEmitter. Silakan lihat jawaban ini: https://stackoverflow.com/a/35568924/215945

Juga, dokumen Angular sekarang memiliki contoh buku masak yang menggunakan Subjek .


Jawaban asli / ketinggalan zaman / salah: sekali lagi, jangan gunakan EventEmitter dalam layanan . Itu adalah anti pola.

Menggunakan beta.1 ... NavService berisi EventEmiter. Komponen Navigasi memancarkan peristiwa melalui layanan, dan komponen ObservingComponent berlangganan peristiwa tersebut.

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;
  }
}

komponen

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


Saya telah mengikuti ini, tetapi ini hanya berfungsi untuk kelas itu sendiri. Ini tidak berfungsi untuk kelas lain (dari file lain). Tampaknya masalahnya ada pada contoh kelas layanan. Apakah ada cara untuk membuat kelas layanan menjadi statis?
asubanovsky

5
@asubanovsky, di plunker saya hanya menyuntikkan NavService di level bootstrap (yaitu, komponen root), jadi seharusnya hanya ada satu instance layanan untuk seluruh aplikasi. Apakah Anda menyuntikkannya ke tempat lain providers: [NavService]? Jika demikian, Anda akan mendapatkan beberapa contoh layanan.
Mark Rajcok

Terima kasih banyak. Sekarang bekerja sesuai harapan saya. Sekarang saya memahami perbedaan antara menyuntikkan penyedia di level bootstrap dan di level komponen.
asubanovsky

Posting ini secara serius diubah ke keadaan di mana saya tidak lagi 'mengerti'. Mengapa memanggil mehtod pada layanan .getNavChangeEmitter () yang mengembalikan EventEmitter berbeda dari langsung berlangganan navChange?
Per Hornshøj-Schierbeck

@ PerHornshøj-Schierbeck, saya menggunakan metode getNavChangeEmitter () untuk menyembunyikan fakta bahwa EventEmitter sedang digunakan di dalam layanan. Pengguna metode dapat berasumsi bahwa objek yang dikembalikan memiliki subscribe()metode. Dengan menggunakan metode, kita dapat dengan mudah mengubah EventEmitter menjadi Subjek atau Observable, yang jauh lebih baik, karena sekarang kita telah mempelajari bahwa EventEmitters hanya boleh digunakan untuk properti Output. Cara yang tepat adalah menggunakan Subject, BehaviorSubject, atau Observable, dan biasanya kita langsung berlangganan ini, maka kita tidak memerlukan metode getNavChangeEmitter () lagi.
Mark Rajcok

6

Menggunakan alfa 28, saya berhasil berlangganan pemancar acara melalui eventEmitter.toRx().subscribe(..)metode ini. Karena tidak intuitif, mungkin berubah dalam rilis mendatang.


1
mungkin memberikan contoh sederhana untuk digunakan orang jika mereka menemukan posting ini? Itu bukan saya downvoting btw;)
Per Hornshøj-Schierbeck

2
Tidak tahu mengapa itu dipilih-turun, itu pasti berhasil. Sederhananya, untuk berlangganan acara emitor "klik", gunakan click.toRx().subscribe(your_callback_function)
Runeboy

Saya pikir itu mungkin telah diturunkan karena kurang contoh yang berfungsi? Saya tahu itu akan bernilai upvote dan mungkin jawaban yang diterima jika itu memiliki tautan ke pluncker / jsfiddle fiddle atau bahkan beberapa baris kode untuk menampilkan sintaks lebih baik;)
Per Hornshøj-Schierbeck

Saya mendapatkan PENGECUALIAN: ReferenceError: klik tidak ditentukan @Runeboy Bisakah Anda memberikan plnkr untuk solusi Anda?
Benjamin McFerren

Anda perlu mendefinisikan EventEmitter yang disebut klik agar berfungsi
Mazen Elkashef
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.