จะสมัครเข้าร่วมกิจกรรมกับบริการใน Angular2 ได้อย่างไร?


112

ฉันรู้วิธีเพิ่มเหตุการณ์ด้วย EventEmitter ฉันยังสามารถแนบเมธอดที่จะเรียกได้หากฉันมีส่วนประกอบดังนี้:

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

เมื่อฉันมีส่วนประกอบเช่นนี้ทุกอย่างก็ทำงานได้ดี ฉันย้ายตรรกะบางอย่างไปเป็นบริการและฉันจำเป็นต้องยกเหตุการณ์จากภายในบริการ สิ่งที่ฉันทำคือ:

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

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

ฉันมีส่วนประกอบที่ต้องอัปเดตค่าบางอย่างตามเหตุการณ์นี้ แต่ดูเหมือนจะไม่สามารถใช้งานได้ สิ่งที่ฉันลองคือ:

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

ฉันจะทำให้ MyComponent สมัครเข้าร่วมกิจกรรมได้อย่างไรเมื่อบริการที่ยกมานั้นไม่ใช่ส่วนประกอบ

ฉันใช้ On 2.0.0-alpha.28

แก้ไข: แก้ไข "ตัวอย่างการทำงาน" ของฉันให้ใช้งานได้จริงดังนั้นจึงสามารถโฟกัสไปที่ส่วนที่ไม่ทำงานได้)

ตัวอย่างโค้ด: http://plnkr.co/edit/m1x62WoCHpKtx0uLNsIv


1
อาจเป็นปัญหาในการออกแบบมากกว่าเนื่องจากบริการไม่ควรปล่อยเหตุการณ์ในนามของส่วนประกอบเนื่องจากการเชื่อมโยงบริการกับส่วนประกอบนั้นแน่นหนา ตัวอย่างเช่นจะเกิดอะไรขึ้นหากมีหลายอินสแตนซ์ขององค์ประกอบพวกเขาทั้งหมดควรปล่อยเหตุการณ์ในกรณีนั้นหรือไม่
Angular University

@jhadesdev ฉันอ่านคุณ ฉันได้ออกแบบโซลูชันใหม่เพื่อให้บริการไม่จำเป็นต้องแสดงผลลัพธ์อีกต่อไป ฉันยังคิดว่าการออกแบบบางอย่างจะไม่เหมาะกับความสามารถในการยกระดับเหตุการณ์ - ขึ้นอยู่กับ "บริการ" ประเภทใด ...
Per Hornshøj-Schierbeck

วิธีหนึ่งก็คือให้คอมโพเนนต์สร้างตัวปล่อยเหตุการณ์แทนบริการจากนั้นส่งผ่านอีซีแอลอีซีแอลเป็นอาร์กิวเมนต์ไปยังบริการ
Angular University

คำตอบ:


135

อัปเดต : ฉันพบวิธีที่ดีกว่า / เหมาะสมในการแก้ปัญหานี้โดยใช้ BehaviorSubject หรือ Observable แทนที่จะเป็น EventEmitter โปรดดูคำตอบนี้: https://stackoverflow.com/a/35568924/215945

นอกจากนี้เอกสารเชิงมุมตอนนี้มีตัวอย่างเช่นตำราที่ใช้เรื่อง


ต้นฉบับ / ล้าสมัย / คำตอบที่ผิด:อีกครั้งไม่ได้ใช้ EventEmitter ในบริการ นั่นคือการต่อต้านรูปแบบ

การใช้ beta.1 ... NavService มี EventEmiter การนำทางคอมโพเนนต์ปล่อยเหตุการณ์ผ่านทางบริการและส่วนประกอบ ObservationComponent สมัครรับข้อมูลเหตุการณ์

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


ฉันทำตามสิ่งนี้แล้ว แต่ใช้ได้กับชั้นเรียนเท่านั้น มันใช้ไม่ได้กับคลาสอื่น (จากไฟล์อื่น) ดูเหมือนว่าปัญหาอยู่ในอินสแตนซ์คลาสบริการ มีการทำให้คลาสบริการคงที่หรือไม่?
asubanovsky

5
@asubanovsky ในplunkerฉันฉีด NavService ที่ระดับ bootstrap (เช่นองค์ประกอบรูท) เท่านั้นดังนั้นควรมีบริการเพียงอินสแตนซ์เดียวสำหรับทั้งแอป คุณฉีดที่อื่นด้วยproviders: [NavService]หรือไม่? ในกรณีนี้คุณจะได้รับบริการหลายอินสแตนซ์
Mark Rajcok

ขอบคุณมาก. ตอนนี้กำลังทำงานตามความคาดหวังของฉัน ตอนนี้ฉันเข้าใจความแตกต่างระหว่างการฉีดผู้ให้บริการในระดับ bootstrap และในระดับส่วนประกอบ
asubanovsky

โพสต์นี้ถูกเปลี่ยนเป็นสถานะที่ฉันไม่ได้ 'เข้าใจ' อีกต่อไป เหตุใดการเรียก mehtod บนบริการ. getNavChangeEmitter () ที่ส่งคืน EventEmitter แตกต่างจากการสมัครใช้งาน navChange โดยตรง
Per Hornshøj-Schierbeck

@ PerHornshøj-Schierbeck ฉันใช้เมธอด getNavChangeEmitter () เพื่อซ่อนความจริงที่ว่ามีการใช้ EventEmitter ภายในบริการ ผู้ใช้เมธอดสามารถสันนิษฐานได้ว่าอ็อบเจ็กต์ที่ส่งคืนมีsubscribe()เมธอด ด้วยวิธีการใช้เราสามารถเปลี่ยน EventEmitter เป็น Subject หรือ Observable ได้อย่างง่ายดายซึ่งดีกว่ามากเนื่องจากตอนนี้เราได้เรียนรู้แล้วว่าควรใช้ EventEmitters สำหรับคุณสมบัติเอาต์พุตเท่านั้น วิธีที่เหมาะสมคือใช้ Subject, BehaviorSubject หรือ Observable และโดยปกติแล้วเราจะสมัครสมาชิกโดยตรงดังนั้นเราจึงไม่จำเป็นต้องใช้เมธอด getNavChangeEmitter () อีกต่อไป
Mark Rajcok

6

การใช้อัลฟา 28 ผมเขียนโปรแกรมเพื่อสมัครรับ emitters เหตุการณ์โดยวิธีการeventEmitter.toRx().subscribe(..)วิธีการ เนื่องจากไม่ได้ใช้งานง่ายจึงอาจเปลี่ยนแปลงได้ในอนาคต


1
อาจจะยกตัวอย่างง่ายๆให้คนใช้ถ้าสะดุดกับโพสต์นี้? ไม่ใช่ฉันลงคะแนน btw;)
Per Hornshøj-Schierbeck

2
ไม่รู้ว่าทำไมมันถึงถูกโหวตลงมันได้ผลอย่างแน่นอน ใส่เพียงเพื่อสมัครรับเหตุการณ์ "คลิก" ใช้ click.toRx().subscribe(your_callback_function)
Runeboy

ฉันคิดว่าอาจถูกลดคะแนนลงเพราะไม่มีตัวอย่างการทำงานใช่หรือไม่? ฉันรู้ว่ามันจะคุ้มค่ากับการโหวตเพิ่มและอาจเป็นคำตอบที่ยอมรับได้หากมีลิงก์ไปยังซอฟดเดิล pluncker / jsfiddle หรือแม้แต่โค้ดบางบรรทัดเพื่อให้แสดงไวยากรณ์ได้ดีขึ้น)
Per Hornshøj-Schierbeck

ฉันได้รับ EXCEPTION: ReferenceError: click is not defined @Runeboy คุณช่วยกรุณาระบุ plnkr สำหรับวิธีแก้ปัญหาของคุณได้หรือไม่?
Benjamin McFerren

คุณต้องกำหนด EventEmitter ที่เรียกว่า click เพื่อให้ทำงานได้
Mazen Elkashef
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.