微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

委托:在Angular2中的EventEmitter或Observable

我试图在Angular2中实现像一个委托模式。
用户点击导航项时,我想调用一个函数,然后发出一个事件,该事件应该由侦听事件的其他组件处理。

这里是场景:我有一个导航组件:

import {Component,Output,EventEmitter} from 'angular2/core';

@Component({
    // other properties left out for brevity
    events : ['navchange'],template:`
      <div class="nav-item" (click)="selectednavItem(1)"></div>
    `
})

export class Navigation {

    @Output() navchange: EventEmitter<number> = new EventEmitter();

    selectednavItem(item: number) {
        console.log('selected nav item ' + item);
        this.navchange.emit(item)
    }

}

这里是观察组件:

export class ObservingComponent {

  // How do I observe the event ? 
  // <----------Observe/Register Event ?-------->

  public selectednavItem(item: number) {
    console.log('item index changed!');
  }

}

关键问题是,如何使观察组件观察到有问题的事件?

更新2016-06-27:而不是使用Observables,使用

>一个BehaviorSubject,由@Abdulrahman在注释中推荐,或
> a ReplaySubject,由@Jason Goemaat在评论中推荐

A Subject既是一个Observable(因此我们可以订阅它)和一个Observer(所以我们可以调用next()来发出一个新的值)。我们利用这个功能主题允许值被多播到多个观察者。我们不利用这个特性(我们只有一个Observer)。

BehaviorSubject主题的变种。它有“当前价值”的概念。我们利用这一点:每当我们创建一个ObservingComponent,它自动从BehaviorSubject获取当前导航项值。

下面的代码plunker使用BehaviorSubject。

ReplaySubject是主体的另一个变体。如果要等到实际生成值,请使用ReplaySubject(1)。而BehaviorSubject需要一个初始值(将立即提供),而ReplaySubject则不需要。 ReplaySubject将始终提供最近的值,但由于它没有必需的初始值,所以服务可以在返回其第一个值之前执行一些异步操作。它仍将立即触发具有最近值的后续呼叫。如果你只想要一个值,在订阅上使用first()。如果您使用first(),您不必取消订阅

import {Injectable}      from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable()
export class NavService {
  // Observable navItem source
  private _navItemSource = new BehaviorSubject<number>(0);
  // Observable navItem stream
  navItem$ = this._navItemSource.asObservable();
  // service command
  changeNav(number) {
    this._navItemSource.next(number);
  }
}
import {Component}    from '@angular/core';
import {NavService}   from './nav.service';
import {Subscription} from 'rxjs/Subscription';

@Component({
  selector: 'obs-comp',template: `obs component,item: {{item}}`
})
export class ObservingComponent {
  item: number;
  subscription:Subscription;
  constructor(private _navService:NavService) {}
  ngOnInit() {
    this.subscription = this._navService.navItem$
       .subscribe(item => this.item = item)
  }
  ngOnDestroy() {
    // prevent memory leak when component is destroyed
    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.changeNav(item);
  }
}

Plunker

原始答案使用一个Observable:(它需要更多的代码和逻辑比使用BehaviorSubject,所以我不推荐它,但它可能是有启发性的)

因此,这里是一个使用Observable instead of an EventEmitter的实现。与我的EventEmitter实现不同,此实现还将当前选择的navItem存储在服务中,以便在创建观察组件时,它可以通过API调用navItem()检索当前值,然后通过navChange $ Observable通知更改。

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import {Observer} from 'rxjs/Observer';

export class NavService {
  private _navItem = 0;
  navChange$: Observable<number>;
  private _observer: Observer;
  constructor() {
    this.navChange$ = new Observable(observer =>
      this._observer = observer).share();
    // share() allows multiple subscribers
  }
  changeNav(number) {
    this._navItem = number;
    this._observer.next(number);
  }
  navItem() {
    return this._navItem;
  }
}

@Component({
  selector: 'obs-comp',item: {{item}}`
})
export class ObservingComponent {
  item: number;
  subscription: any;
  constructor(private _navService:NavService) {}
  ngOnInit() {
    this.item = this._navService.navItem();
    this.subscription = this._navService.navChange$.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:number;
  constructor(private _navService:NavService) {}
  selectednavItem(item: number) {
    console.log('selected nav item ' + item);
    this._navService.changeNav(item);
  }
}

Plunker

另见Component Interaction Cookbook example,除了观察者之外,它还使用主语。尽管示例是“父和子通信”,但是相同的技术适用于不相关的组件。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐