Làm thế nào để đăng ký một sự kiện trên một dịch vụ trong Angular2?


112

Tôi biết cách nâng cao sự kiện bằng EventEmitter. Tôi cũng có thể đính kèm một phương thức được gọi nếu tôi có một thành phần như sau:

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

Khi tôi có một thành phần như thế này, mọi thứ hoạt động tuyệt vời. Tôi đã chuyển một số logic vào một dịch vụ và tôi cần nêu ra một sự kiện từ bên trong Dịch vụ. Những gì tôi đã làm là:

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

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

Tôi có một thành phần cần cập nhật một số giá trị dựa trên sự kiện này nhưng dường như tôi không thể làm cho nó hoạt động. Những gì tôi đã thử là:

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

Làm cách nào để đặt MyComponent đăng ký sự kiện khi dịch vụ nâng cao nó không phải là một thành phần?

Tôi đang sử dụng Trên 2.0.0-alpha.28

CHỈNH SỬA: Đã sửa đổi "ví dụ làm việc" của tôi để thực sự hoạt động, vì vậy có thể tập trung vào phần không hoạt động;)

Mã ví dụ: http://plnkr.co/edit/m1x62WoCHpKtx0uLNsIv


1
Nó có thể là một vấn đề thiết kế hơn vì một dịch vụ không nên phát ra các sự kiện thay mặt cho một thành phần, vì nó kết hợp chặt chẽ dịch vụ với thành phần đó. Ví dụ: điều gì xảy ra nếu có nhiều trường hợp của thành phần, tất cả chúng có nên phát ra các sự kiện trong trường hợp đó không?
Đại học Angular

@jhadesdev Tôi đã đọc bạn. Tôi đã thiết kế lại giải pháp để dịch vụ không cần phát ra kết quả nữa. Tôi vẫn nghĩ rằng một số thiết kế sẽ bennefit từ việc có thể để sự kiện tăng lương - tùy thuộc loại "dịch vụ" đó là ...
mỗi Hornshøj-Schierbeck

một trong những cách sau đó có thể có các thành phần tạo ra các phát sự kiện thay vì các dịch vụ, và sau đó vượt qua trong phát sự kiện như một cuộc tranh cãi với dịch vụ
Đại học Góc

Câu trả lời:


135

Cập nhật : Tôi đã tìm thấy một cách tốt hơn / thích hợp để giải quyết vấn đề này bằng cách sử dụng BehaviorSubject hoặc Observable thay vì EventEmitter. Vui lòng xem câu trả lời này: https://stackoverflow.com/a/35568924/215945

Ngoài ra, các tài liệu Angular hiện có một ví dụ về sách nấu ăn sử dụng Chủ đề .


Câu trả lời gốc / lỗi thời / sai: một lần nữa, không sử dụng EventEmitter trong một dịch vụ . Đó là một mô hình chống.

Sử dụng phiên bản beta.1 ... NavService chứa EventEmiter. Thành phần Điều hướng phát ra các sự kiện thông qua dịch vụ và thành phần ObservingComponent đăng ký các sự kiện.

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

thành phần.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


Tôi đã làm theo điều này, nhưng nó chỉ hoạt động cho chính lớp học. Nó không hoạt động cho một lớp khác (từ một tệp khác). Có vẻ như vấn đề là trong trường hợp lớp dịch vụ. Có cách nào để làm cho lớp dịch vụ trở nên tĩnh không?
asubanovsky,

5
@asubanovsky, trong plunker, tôi chỉ chèn NavService ở cấp bootstrap (tức là thành phần gốc), vì vậy chỉ nên có một phiên bản của dịch vụ cho toàn bộ ứng dụng. Bạn đang tiêm nó ở nơi khác với providers: [NavService]? Nếu vậy, bạn sẽ nhận được nhiều phiên bản của dịch vụ.
Mark Rajcok

Cảm ơn rât nhiều. Nó hiện đang hoạt động như mong đợi của tôi. Bây giờ tôi hiểu sự khác biệt giữa việc tiêm các nhà cung cấp ở cấp bootstrap và ở cấp thành phần.
asubanovsky

Bài đăng này đã bị thay đổi nghiêm trọng thành trạng thái mà tôi không còn 'lấy nó' nữa. Tại sao việc gọi mehtod trên dịch vụ .getNavChangeEmitter () trả về EventEmitter khác với việc đăng ký trực tiếp vào navChange?
Per Hornshøj-Schierbeck

@ PerHornshøj-Schierbeck, tôi đã sử dụng phương thức getNavChangeEmitter () để ẩn sự thật rằng EventEmitter đang được sử dụng bên trong dịch vụ. Người dùng phương thức có thể cho rằng đối tượng trả về có một subscribe()phương thức. Bằng cách sử dụng một phương thức, chúng ta có thể dễ dàng thay đổi EventEmitter thành Chủ thể hoặc Quan sát được, điều này tốt hơn nhiều, vì bây giờ chúng ta đã biết rằng EventEmitter chỉ nên được sử dụng cho các thuộc tính Đầu ra. Cách thích hợp là sử dụng Chủ đề, BehaviorSubject hoặc Observable, và chúng tôi thường đăng ký trực tiếp các đối tượng này, do đó chúng tôi không cần phương thức getNavChangeEmitter () nữa.
Mark Rajcok

6

Sử dụng alpha 28, tôi đã hoàn thành việc đăng ký theo chương trình với các trình phát sự kiện bằng eventEmitter.toRx().subscribe(..)phương pháp này. Vì nó không trực quan, nó có thể thay đổi trong một bản phát hành trong tương lai.


1
có lẽ cung cấp một ví dụ đơn giản để mọi người sử dụng nếu họ tình cờ gặp bài đăng này? Nó không được tôi downvoting btw;)
mỗi Hornshøj-Schierbeck

2
Không biết tại sao nó bị bỏ phiếu, nó chắc chắn hoạt động. Đơn giản chỉ cần đặt, để đăng ký vào một emitter sự kiện "click", sử dụng click.toRx().subscribe(your_callback_function)
Runeboy

Tôi nghĩ rằng nó có thể đã bị từ chối vì nó thiếu một ví dụ hoạt động? Tôi biết nó sẽ có giá trị một phiếu bầu tán thành và có lẽ một câu trả lời được chấp nhận nếu nó có hoặc là một liên kết đến một pluncker / fiddle jsfiddle hoặc thậm chí một số dòng mã để hiển thị cú pháp tốt hơn;)
mỗi Hornshøj-Schierbeck

Tôi nhận được NGOẠI LỆ: ReferenceError: click không được xác định @Runeboy Bạn có thể vui lòng cung cấp một plnkr cho giải pháp của bạn không?
Benjamin McFerren

Bạn cần xác định EventEmitter được gọi là nhấp chuột để nó hoạt động
Mazen Elkashef
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.