我试图在Angular中实现类似委托模式的东西 . 当用户点击 nav-item
时,我想调用一个函数然后发出一个事件,而该事件又由一些其他组件监听事件来处理 .
这是场景:我有一个 Navigation
组件:
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!');
}
}
关键问题是,如何让观察组件观察相关事件?
6 回答
Update 2016-06-27: 而不是使用Observables,使用其中之一
一个BehaviorSubject,由@Abdulrahman在评论中推荐,或者
一个ReplaySubject,由@Jason Goemaat在评论中推荐
Subject既是一个Observable(所以我们可以
subscribe()
)和一个Observer(所以我们可以在它上面调用next()
来发出一个新值) . 我们利用此功能 . Subject允许将值多播到许多观察者 . 我们没有利用这个功能(我们只有一个Observer) .BehaviorSubject是Subject的变体 . 它有"the current value"的概念 . 我们利用这个:每当我们创建ObservingComponent时,它会自动从BehaviorSubject获取当前导航项值 .
下面的代码和plunker使用BehaviorSubject .
ReplaySubject是Subject的另一种变体 . 如果要等到实际生成值,请使用
ReplaySubject(1)
. 虽然BehaviorSubject需要一个初始值(将立即提供),但ReplaySubject却没有 . ReplaySubject将始终提供最新值,但由于它没有所需的初始值,因此服务可以在返回其第一个值之前执行一些异步操作 . 它仍将在具有最新值的后续呼叫中立即触发 . 如果您只想要一个值,请在订阅上使用first()
. 如果您使用first()
,则无需取消订阅 .Plunker
Original answer that uses an Observable: (它需要比使用BehaviorSubject更多的代码和逻辑,所以我不推荐它,但它可能是有益的)
所以,这是一个使用Observable instead of an EventEmitter的实现 . 与我的EventEmitter实现不同,此实现还将当前选定的
navItem
存储在服务中,以便在创建观察组件时,它可以通过API调用navItem()
检索当前值,然后通过navChange$
Observable通知更改 .Plunker
另请参阅Component Interaction Cookbook example,除了observable之外还使用
Subject
. 虽然该示例是"parent and children communication,",但相同的技术适用于不相关的组件 .Breaking news: 我添加了使用Observable而不是EventEmitter的another answer . 我建议回答这个问题 . 实际上,在服务中使用EventEmitter是bad practice .
原答案:(不要这样做)
将EventEmitter放入一个服务,它允许ObservingComponent直接订阅(和取消订阅)事件:
如果您尝试使用Plunker,我可能会对此方法不满意:
ObservingComponent需要在销毁时取消订阅
我们必须将组件传递给
subscribe()
,以便在调用回调时设置正确的this
更新:解决第二个问题的替代方法是让ObservingComponent直接订阅
navchange
EventEmitter属性:如果我们直接订阅,那么我们就不需要NavService上的
subscribe()
方法了 .为了使NavService更加封装,您可以添加
getNavChangeEmitter()
方法并使用它:如果想要遵循更加反应式的编程风格,那么“Everything is a stream”的概念肯定会出现,因此,使用Observables尽可能频繁地处理这些流 .
你可以使用如上所述的BehaviourSubject或 there is one more way:
你可以像这样处理EventEmitter: first add a selector
Now you can handle this event like let us suppose observer.component.html is the view of Observer component
then in the ObservingComponent.ts
您需要在ObservingComponent的模板中使用Navigation组件(不要忘记向导航组件添加 selector ..导航组件为ex)
并在ObservingComponent中实现onNavGhange()
最后一件事..你不需要 @Componennt 中的events属性
我在没有使用Reactivex这两种服务的情况下找到了另一种解决方案 . 我实际上喜欢rxjx API,但我认为在解析异步和/或复杂函数时它是最好的 . 以这种方式使用它,它对我来说太过分了 .
我认为你在寻找广播 . 只是 . 我发现了这个解决方案:
这是一个完整的工作示例:https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE