Angular 2 EventEmitter - 从服务函数广播next( ... )

4
根据我的理解,.toRx().subscribe( ... )函数用于接收消息,而.next()函数用于广播消息。
在这个plnkr ( http://plnkr.co/edit/MT3xOB?p=info ) 中,您从模板中定义/派生的数据对象中调用了.toRx().subscribe( ... )函数。
@Component({
  selector : 'child-cmp',
  template : '',
  inputs : ['data']
})
class ChildCmp {
  afterViewInit() {
    this.data.toRx().subscribe((data) => {
      console.log('New data has arrived!', data);
    });
  }
}

在这个plnkr(http://plnkr.co/edit/rNdInA?p=preview)中,您从一个evt对象和其发射器函数(来自注入到组件构造函数中的服务)调用.toRx().subscribe(...)函数。请保留HTML标签。
@Component({
  selector : 'parent-cmp',
  template : ''
})
class ParentCmp {
  constructor(evt: EventService) {
    evt.emitter.subscribe((data) => 
      console.log("I'm the parent cmp and I got this data", data));
  }
}

在Service函数内部进行BROADCAST是否可行?同时,组件是否可以接收消息而不依赖返回的Service对象或Template数据对象来链式调用.toRX().subscribe( ... )函数?

import {Injectable, EventEmitter} from 'angular2/angular2';
@Injectable()
export class DataService {
    items:Array<any>;
    dispatcher: EventEmitter = new EventEmitter();
    constructor() {
        this.items = [
            { name: 'AAAA' },
            { name: 'BBBB' },
            { name: 'CCCC' }
        ];
    }
    getItems() {
        return this.items;
    }
    sendItems() {
        this.dispatcher.next( this.items );
    } 
}
export var DATA_BINDINGS: Array<any> = [
    DataService
];


@Component({
    selector: 'rabble'
})
@View({
    ...
})
export class Rabble {

    items       : Array<any>;

    constructor( public dataService  : DataService) { 

        console.log('this.routeParam', this.dataService.getItems());
    }

    afterViewInit() {
        this.???.toRx().subscribe((data) => {
            console.log('New item data has arrived!', data);
        });
    }

    handleClick() {
        this.dataService.sendItems();
    }
}
2个回答

11

已更新至2.0版本: EventEmitter现在仅用于组件通信。这是Subjects和ReplaySubjects的更好用法。我已将示例代码更新为2.0版本。

已更新至Beta 1版本: 您不再需要在发射器上调用.toRx(),因此我正在更新代码以匹配,并添加了一个取消订阅的示例。

目前(Alpha 45),EventEmitter具有toRx()方法,该方法返回RxJS的SUBJECT

您可以搜索一下它是什么以及可以对其执行哪些操作,但实际上这就是您所要处理的内容。当您调用toRx()时,它只返回事件发射器内部的subject,因此您可以在服务构造函数中执行此操作。

然后我添加了您想要的函数来广播事件服务。

class EventService {
  //could be regular Subject but I like how ReplaySubject will send the last item when a new subscriber joins
  emitter: ReplaySubject<any> = new ReplaySubject(1);
  constructor() {

  }
  doSomething(data){
    this.emitter.next(data);
  }
}

然后在您的组件中订阅该发射器

class ParentCmp {
  myData: any;
  constructor(private evt: EventService) {
    //rx emitter
    this.evt.emitter.subscribe((data) => {
      this.myData = data;
      console.log("I'm the parent cmp and I got this data", data));
    }
  }
}

这里是一个具有内置取消订阅(dispose)的扩展类

export class ParentCmp implements OnDestroy {
  myData: any;
  subscription: any;
  constructor(evt: EventService) {
    //rx emitter
    this.subscription = evt.emitter.subscribe((data) => {
      this.myData = data;
      console.log("I'm the parent cmp and I got this data", data));
    }
  }
  ngOnDestroy() {
    this.subscription.dispose();
  }
}

我有点困惑你上一个问题的意思,但是想到词语“接收信息”。你必须要监听某些东西,这就是 subscribe 方法所做的并且是必需的。

很酷的一件事情是现在你可以在各个地方调用那个可观察对象(甚至在其他服务中),在我看来这是组件之间通信的最佳方式。它们不需要知道自己在树中的位置,也不需要关心其他组件是否存在或者是否在监听。

我用我的方法在 Plunker 上进行了 Fork,并使其正常工作 HERE (仍然是 Alpha45 版本)

RxJs 的源代码和有关 subject 的信息

Angular2 中 EventEmitter 内部的 subject 的源代码和信息


谢谢Dennis。我仍然对一些相关/悬而未决的功能感到好奇。在正确的EventEmitter语法中,如何订阅特定的“频道”,就像我们在angular 1 $Broadcast和$on中所做的那样?为了实现“频道”,我只需创建第二个新的EventEmitter变量或绑定到现有_emitter变量的新/第二个闭包变量吗?... = this._emitter.toRx();$scope.$broadcast('myCustomEvent', { someProp: 'Sending you an Object!' // send whatever you want }); $scope.$on('myCustomEvent', function (event, data) { console.log(data); // 'Data to send' }); - Benjamin McFerren
说实话,在我的使用中,我跳过了EventEmitter,直接创建一个新的observable(目前整个.toRx()的东西很痛苦),然后将其放入一个持有对象中。我觉得EventEmitter更适合组件之间的通信而不是服务。(在我看来)你需要为每个“通道”创建一个新的observable,否则每次流更新时都需要过滤逻辑。然后我只需调用:myObserverService.observers.myCustomEvent.subscribe(...) 或者你可以在你的服务中创建一个帮助程序,像这样:myObserverService.listen('myCustomEvent',(data)=>{},(error)=>{}) - Dennis Smolek
我在周末考虑了一下,发现我错过了你想要的重点。你应该肯定使用EventEmitter来实现你计划中的发布/订阅机制。这样你就可以轻松地从其他函数中执行.next()。 - Dennis Smolek
旁边的问题:是否可以在HTML中订阅组件公开的EventEmitter(而不是注入的服务)。我的意思是,例如,如果您在HTML中有一个按钮,该按钮具有定义的“click”事件发射器。您是否可以直接订阅它,而不是将(通常所做的)onClick()实例方法/函数关联为处理程序? - superjos
谢谢。我知道在HTML中直接调用subject.next()的方法。关于回调函数,当然,如果你最终只是订阅来调用回调函数,那么整个意义就被忽略了。当你真正充分利用可观察对象时,在订阅之前组合不同的流就会有所不同。 - superjos
显示剩余6条评论

5

在 Beta 版本中,您不再需要通过 toRx() 将其转换为 RxJs 对象。

var evtEmitter = new EventEmitter();

evtEmitter.emit(args);
evtEmitter.subscribe((args)=>{console.log('new event')});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接