如何在 Angular2-Meteor 中使注入的服务具有反应性
How to make injected service reactive in Angular2-Meteor
我是 Angular2 的新手,我正在尝试让自定义组件使用管理 Mongo.Collection objects 注册表的服务。我的问题是,当 Collection 已加载时,我似乎无法让 Angular 刷新 UI。
如果您查看下面的代码,您会发现有一个组件注入了 DatasetService。此服务管理 Collection 的注册表。我猜这个问题与 Meteor.autorun() 方法将处理从 Angular 'zone' 中取出的事实有关,我需要以某种方式 re-inject 处理Angular zone/digest?
客户端和服务器:
export const Meetings = new Mongo.Collection<any>('meetings');
仅限服务器
Meteor.publish('meetings', function(options: any) {
return Meetings.find({});
});
仅限客户
class Dataset {
cursor: Mongo.Cursor<any>;
loading: boolean = true;
constructor( public collection: Mongo.Collection<any> ) {
Tracker.autorun(() => {
this.loading = true;
Meteor.subscribe('meetings', {}, () => {
this.cursor = this.collection.find({});
this.loading = false;
});
});
}
}
@Injectable()
class DatasetService {
datasets: Dataset[] = [];
register( id: string, collection: Mongo.Collection<any> ) : Dataset {
return this.datasets[id] = new Dataset( collection, options );
}
}
@Component({
selector: 'meetings-list',
template: `<ul><li *ngFor="let meeting of meetings.cursor">{{meeting.name}}</li></ul>`,
viewProviders: [DatasetService]
})
class MeetingsListComponent extends MeteorComponent implements OnInit {
meetings: Dataset;
constructor(private datasetService: DatasetService) {
super();
}
ngOnInit() {
this.meetings = this.datasetService.register( 'meetings', Meetings );
}
checkState() {
console.log(this.loading);
}
}
如果我加载页面,则不会显示会议列表。但是,如果我通过单击按钮手动调用 'checkState()',它会刷新 UI 并呈现会议。
任何帮助、清晰或替代方法来实现我正在尝试做的事情都将不胜感激!
你是对的。触发更改的代码来自 Angular2 区域外部,因此您需要将其推送到区域中以执行更改。为此,您需要将 NgZone 注入到您的服务中。然后您可能需要将它传递给 Dataset 实例,因为那是应该触发更新的代码所在的位置。例如,这可能有效:
import { Injectable, NgZone, Inject } from '@angular/core';
class Dataset {
cursor: Mongo.Cursor<any>;
loading: boolean = true;
constructor( public collection: Mongo.Collection<any>, zone: NgZone ) {
Tracker.autorun(() => {
this.loading = true;
Meteor.subscribe('meetings', {}, () => {
zone.run(() => { //<-- new line
this.cursor = this.collection.find({});
this.loading = false;
}); //<-- end of new line
});
});
}
}
@Injectable()
class DatasetService {
datasets: Dataset[] = [];
private zone: NgZone;
// Inject Here
constructor(@Inject(NgZone)zone: NgZone) { this.zone = zone; }
register( id: string, collection: Mongo.Collection<any> ) : Dataset {
//Add zone to Dataset constructor,
// not sure before or after options (not sure where options comes from or goes
return this.datasets[id] = new Dataset( collection, this.zone, options );
}
}
我是 Angular2 的新手,我正在尝试让自定义组件使用管理 Mongo.Collection objects 注册表的服务。我的问题是,当 Collection 已加载时,我似乎无法让 Angular 刷新 UI。
如果您查看下面的代码,您会发现有一个组件注入了 DatasetService。此服务管理 Collection 的注册表。我猜这个问题与 Meteor.autorun() 方法将处理从 Angular 'zone' 中取出的事实有关,我需要以某种方式 re-inject 处理Angular zone/digest?
客户端和服务器:
export const Meetings = new Mongo.Collection<any>('meetings');
仅限服务器
Meteor.publish('meetings', function(options: any) {
return Meetings.find({});
});
仅限客户
class Dataset {
cursor: Mongo.Cursor<any>;
loading: boolean = true;
constructor( public collection: Mongo.Collection<any> ) {
Tracker.autorun(() => {
this.loading = true;
Meteor.subscribe('meetings', {}, () => {
this.cursor = this.collection.find({});
this.loading = false;
});
});
}
}
@Injectable()
class DatasetService {
datasets: Dataset[] = [];
register( id: string, collection: Mongo.Collection<any> ) : Dataset {
return this.datasets[id] = new Dataset( collection, options );
}
}
@Component({
selector: 'meetings-list',
template: `<ul><li *ngFor="let meeting of meetings.cursor">{{meeting.name}}</li></ul>`,
viewProviders: [DatasetService]
})
class MeetingsListComponent extends MeteorComponent implements OnInit {
meetings: Dataset;
constructor(private datasetService: DatasetService) {
super();
}
ngOnInit() {
this.meetings = this.datasetService.register( 'meetings', Meetings );
}
checkState() {
console.log(this.loading);
}
}
如果我加载页面,则不会显示会议列表。但是,如果我通过单击按钮手动调用 'checkState()',它会刷新 UI 并呈现会议。
任何帮助、清晰或替代方法来实现我正在尝试做的事情都将不胜感激!
你是对的。触发更改的代码来自 Angular2 区域外部,因此您需要将其推送到区域中以执行更改。为此,您需要将 NgZone 注入到您的服务中。然后您可能需要将它传递给 Dataset 实例,因为那是应该触发更新的代码所在的位置。例如,这可能有效:
import { Injectable, NgZone, Inject } from '@angular/core';
class Dataset {
cursor: Mongo.Cursor<any>;
loading: boolean = true;
constructor( public collection: Mongo.Collection<any>, zone: NgZone ) {
Tracker.autorun(() => {
this.loading = true;
Meteor.subscribe('meetings', {}, () => {
zone.run(() => { //<-- new line
this.cursor = this.collection.find({});
this.loading = false;
}); //<-- end of new line
});
});
}
}
@Injectable()
class DatasetService {
datasets: Dataset[] = [];
private zone: NgZone;
// Inject Here
constructor(@Inject(NgZone)zone: NgZone) { this.zone = zone; }
register( id: string, collection: Mongo.Collection<any> ) : Dataset {
//Add zone to Dataset constructor,
// not sure before or after options (not sure where options comes from or goes
return this.datasets[id] = new Dataset( collection, this.zone, options );
}
}