アプリケーションの状態のほとんどが、Observable を介して状態を公開する @Injectable サービスに存在する Angular 2 アプリケーション。ある時点で、アプリケーションが Angular Zone から脱落し、変更検出が機能しなくなります。私のサブスクライブではChangeDetectorRef.detectChanges()
、これが発生したときに呼び出す必要があります。アプリケーションが Angular Zone から脱落しないようにするにはどうすればよいですか? それとも原因を突き止めますか?
これが私のサービスです:
@Injectable()
export class CalendarFilterStore {
private currentState: CalendarFilter;
private state$ = new ReplaySubject<CalendarFilter>(1);
constructor() {
this.currentState = {
startDate: new Date(2016, 10, 14, 2)
};
this.state$.next(this.currentState);
}
get state(): Observable<CalendarFilter> {
console.log('calendar filter state, zone: ' + Zone.current.name);
return this.state$.asObservable();
}
このサービスを使用しているコンポーネントの ngOnInit 関数は次のとおりです。
ngOnInit() {
console.log('ng init zone: ' + Zone.current.name);
this.calendarFilterStore.state
.filter(state => {
console.log('got filter state, zone: ' + Zone.current.name);
return (state.areaIDs !== undefined && state.worksiteID !== undefined && state.startDate !== undefined && state.numberOfShifts !== undefined);
})
.switchMap(state => this.getCalendar(state))
.subscribe(res => {
console.log('got calendar, dashboard-table, zone: ' + Zone.current.name);
this.loadCalendar(res);
}, error => {
console.log(error);
});
これは、Angular Zone からドロップアウトしたときに表示されるコンソール出力です。カレンダー フィルターが 2 番目の値を発行するときに発生するようです。
calendar filter state, zone: angular
calendar-filter - store.ts:21 calendar filter state, zone: angular
calendar-store.ts:22 get calendar state, zone: angular
dashboard-table.component.ts:60 ng init zone: angular
calendar-filter - store.ts:21 calendar filter state, zone: angular
dashboard-table.component.ts:63 got filter state, zone: angular
dashboard-table.component.ts:63 got filter state, zone: <root>
dashboard-table.component.ts:63 got filter state, zone: <root>
calendar.service.ts:25 get calendar, zone: <root>
calendar.service.ts:31 got calendar, zone: <root>
dashboard-table.component.ts:68 got calendar, dashboard-table, zone: <root>
calendar-store.ts:27 segments returned, zone: <root>
コンポーネント ツリーのいくつかのレベルにあるコンポーネントに絞り込みました。コンストラクターで Zone.current.name を確認すると、それらはroot
ゾーンではなくangular
ゾーンにあります。それらが発行するイベントはroot
、親 -> サービス -> サブスクライバーに伝播する場合でも、ゾーンに残ります。
以下は、Angular ゾーンで機能して実行されるコンポーネント テンプレートですが、出力からわかるように、その子である sb-worksite-selector はルート ゾーンで実行されます。
<div class="dashboard-navigation" *ngIf="optionsLoaded">
<button type="button" class="btn btn-secondary" (click)="previousDay()"><i class="fa fa-backward" aria-hidden="true"></i> Previous Day</button>
<div class="inline-block">
<sb-worksite-selector [worksiteOptions]="worksiteOptions"
(onWorksiteChanged)="worksiteChanged($event)">
</sb-worksite-selector>
</div>
sb-worksite-selector
@Component({
selector: 'sb-worksite-selector',
templateUrl: 'worksite-selector.component.html',
styleUrls: ['worksite-selector.component.scss']
})
export class WorksiteSelectorComponent implements OnInit {
@Input() worksiteOptions: Array<any>;
@Output() onWorksiteChanged = new EventEmitter<number>();
constructor() {
console.log('create worksite selector, zone: ' + Zone.current.name);
}
ngOnInit() {
console.log('init worksite selector, zone: ' + Zone.current.name);
}
}
Worksite セレクターのロギング:
calendar filter state, zone: angular
dashboard - table.component.ts:63 got filter state, zone: angular
calendar.service.ts:25 get calendar, zone: angular
dashboard - navigation.component.ts:63 dashboard navigation got areas and worksites, zone: angular
worksite - selector.component.ts:14 create worksite selector, zone: <root>
worksite - selector.component.ts:18 init worksite selector, zone: <root>