Angular 2: 如何监视服务变量?
Angular 2: 如何监视服务变量?
我正在尝试在Angular中实现类似委托模式的功能。
当用户点击一个nav-item
时,我想调用一个函数,该函数会触发一个事件,并由其他监听该事件的组件处理。
这是场景:我有一个Navigation
组件:
import {Component, Output, EventEmitter} from 'angular2/core';
@Component({
// 其他属性为了简洁起见省略
events : ['navchange'],
template:`
`
})
export class Navigation {
@Output() navchange: EventEmitter
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
这是观察组件:
export class ObservingComponent {
// 我如何观察这个事件?
// <----------观察/注册事件?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
关键问题是,我如何使观察组件观察到所讨论的事件?
Angular 2:如何监视服务变量?
问题的出现原因:
在Angular 2中,如果一个组件想要监视一个服务的变量,那么在服务中对变量的更新并不会自动触发组件的更新。这导致了一个问题,即如何在服务变量发生变化时通知组件进行更新。
解决方法:
有两种常见的解决方法:
1. 使用BehaviorSubject:
BehaviorSubject是一种特殊类型的Subject,Subject是一种特殊类型的Observable,可以作为Observable和Observer。可以像其他Observable一样订阅消息,并在订阅时返回源Observable发出的主题的最后一个值。
优点:不需要像父子组件之间传递数据那样的关系。
在NavService服务中使用BehaviorSubject来实现这个功能:
import {Injectable} from '/core' import {BehaviorSubject} from 'rxjs/BehaviorSubject'; @Injectable() export class NavService { private navSubject$ = new BehaviorSubject(0); constructor() { } // 当新项目被点击时触发事件 navItemClicked(navItem: number) { this.navSubject$.next(number); } // 允许Observer组件仅订阅发出的数据 getNavItemClicked$() { return this.navSubject$.asObservable(); } }
在Navigation组件中使用NavService来触发事件:
@Component({ selector: 'navbar-list', template:`}) export class Navigation { constructor(private navService:NavService) {} navItemClicked(item: number) { this.navService.navItemClicked(item); } }
在ObservingComponent组件中订阅NavService的变化并更新:
@Component({ selector: 'obs-comp', template: `obs component, item: {{item}}` }) export class ObservingComponent { item: number; itemClickedSubcription:any constructor(private navService:NavService) {} ngOnInit() { this.itemClickedSubcription = this.navService .getNavItemClicked$ .subscribe( item => this.selectedNavItem(item) ); } selectedNavItem(item: number) { this.item = item; } ngOnDestroy() { this.itemClickedSubcription.unsubscribe(); } }
2. 使用@Input和@Output装饰器:
另一种常见的方法是使用@Input和@Output装饰器,父组件将数据传递给子组件,子组件通过触发事件来通知父组件。
例如,Sharma提供的答案中给出了这种方法的示例代码。
问题的出现的原因是:在Angular 2中,当一个服务的变量发生变化时,如何实时监测这个变化。解决方法是使用EventEmitter或Observable来实现。
原文中给出了两种解决方法。第一种方法是将EventEmitter放入一个服务中,然后在需要监测变化的组件中直接订阅和取消订阅这个事件。但是这种方法有一些问题,比如需要在组件销毁时手动取消订阅,并且需要将组件作为参数传递给订阅方法,以便在回调时正确设置this。
第二种方法是直接让需要监测变化的组件订阅服务中的EventEmitter属性。这样就不需要手动取消订阅了,但是仍然需要将组件作为参数传递给订阅方法。
为了让服务更加封装,可以在服务中添加一个getNavChangeEmitter()方法,然后在组件中使用这个方法来订阅事件。
作者对这两种方法都不太满意,因为第一种方法需要手动取消订阅,第二种方法需要将组件作为参数传递给订阅方法。作者希望能有更加简洁的解决方法。对于第二种方法中的问题,作者提出了一个修复方法,即将回调函数传递给订阅方法时,直接使用箭头函数来避免出现this的问题。
问题的出现原因是如何实时监测服务变量的变化,解决方法是使用EventEmitter或Observable,并给出了两种具体的实现方法。
Angular 2: 如何监听服务变量?
在这个问题中,我们需要解决一个问题:如何在Angular 2中监听服务变量的变化?下面是一些解决方法:
1. 使用BehaviorSubject:
BehaviorSubject是Subject的一种变体,它有“当前值”的概念。我们可以利用这一点,每当我们创建一个ObservingComponent时,它会自动从BehaviorSubject获取当前的导航项值。
2. 使用ReplaySubject:
ReplaySubject是Subject的另一种变体。如果你想要等到一个值真正产生,可以使用ReplaySubject(1)。ReplaySubject始终提供最新的值,但不需要一个必需的初始值,因此服务可以在返回第一个值之前进行一些异步操作。对于只想要一个值的情况,可以在订阅上使用first()。如果使用first(),则不需要取消订阅。
下面是一个使用BehaviorSubject的示例代码:
import {Injectable} from '/core' import {BehaviorSubject} from 'rxjs/BehaviorSubject'; @Injectable() export class NavService { private _navItemSource = new BehaviorSubject(0); navItem$ = this._navItemSource.asObservable(); changeNav(number: number) { this._navItemSource.next(number); } }
下面是一个使用NavService的ObservingComponent示例代码:
import {Component} from '/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() { this.subscription.unsubscribe(); } }
下面是一个使用NavService的Navigation组件示例代码:
@Component({ selector: 'my-nav', template:`` }) export class Navigation { item = 1; constructor(private _navService: NavService) {} selectedNavItem(item: number) { console.log('selected nav item ' + item); this._navService.changeNav(item); } }
以上是解决问题的方法和示例代码。通过使用BehaviorSubject或ReplaySubject,我们可以监听服务变量的变化并作出相应的处理。这些方法可以帮助我们更好地管理和处理Angular 2中的服务变量。