我想渲染一个视觉倒数计时器。我正在使用这个组件https://github.com/crisbeto/angular-svg-round-progressbar,它依赖于SimpleChange
传递changes.current.previousValue
& changes.current.currentValue
。
这是模板代码
<ion-card class="timer"
*ngFor="let snapshot of timers | snapshot"
>
<ion-card-content>
<round-progress
[current]="snapshot.remaining"
[max]="snapshot.duration"
[rounded]="true"
[responsive]="true"
[duration]="800"
>
</round-progress>
</ion-card>
我正在使用此代码来触发angular2
更改检测
this._tickIntervalHandler = setInterval( ()=>{
// run change detection
return;
}
// interval = 1000ms
, interval
)
更新 (经过大量测试,我发现问题不是我渲染时间的精度,这个问题已经改变以反映这一点。)
问题是ngFor
在 1 个变化检测循环内被多次调用。无论我的刻度间隔或精度snapshot.remaining
(即秒或十分之一秒)如果在更改检测期间snapshot.remaining
的后续调用中ngFor
发生更改,我都会收到异常:
Expression has changed after it was checked
如果我只渲染一个计时器而不使用,ngFor
那么更改检测工作正常——即使间隔为10ms
.
如何在页面上呈现多个计时器,大概使用ngFor
,而不触发此异常?
解决方案
经过一番测试,似乎问题在于使用SnapshotPipe
withngFor
来捕获 Timer 数据的快照。最终起作用的是snapshot
在 View Component 中获取 Timer 数据。正如下面的答案中提到的,这使用一种pull
方法来获取更改,而不是一种push
方法。
// timers.ts
export class TimerPage {
// use with ngFor
snapshots: Array<any> = [];
constructor(timerSvc: TimerSvc){
let self = this;
timerSvc.setIntervalCallback = function(){
self.snapshots = self.timers.map( (timer)=>timer.getSnapshot() );
}
}
}
// timer.html
<ion-card class="timer" *ngFor="let snapshot of snapshots">
<ion-card-content>
<round-progress
[current]="snapshot.remaining"
[max]="snapshot.duration"
[rounded]="true"
[responsive]="true"
[duration]="800"
>
</round-progress>
</ion-card>
// TimerSvc can start the tickInterval
export class TimerSvc {
_tickIntervalCallback: ()=>void;
_tickIntervalHandler: number;
setIntervalCallback( cb: ()=>void) {
this._tickIntervalCallback = cb;
}
startTicking(interval:number=100){
this._tickIntervalHandler = setInterval(
this._tickIntervalCallback
, interval
);
}
}