[英]angular2 how do you render a timer Component inside `ngFor`
I want to render a visual countdown timer. 我想渲染一个视觉倒数计时器。 I'm using this component, https://github.com/crisbeto/angular-svg-round-progressbar , which relies on SimpleChange
to deliver changes.current.previousValue
& changes.current.currentValue
. 我正在使用这个组件, https://github.com/crisbeto/angular-svg-round-progressbar ,它依赖于SimpleChange
来提供changes.current.previousValue
和changes.current.currentValue
。
Here is the template code 这是模板代码
<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>
I'm using this code to trigger angular2
change detection 我正在使用此代码来触发angular2
变化检测
this._tickIntervalHandler = setInterval( ()=>{
// run change detection
return;
}
// interval = 1000ms
, interval
)
updated (After much testing, I've discovered that the problem isn't the precision of the time I am rendering, and this question has been changed to reflect that.) 更新 (经过大量测试,我发现问题不是我渲染时的精确度,而且这个问题已经改变以反映出来。)
The problem is that ngFor
is called multiple times inside 1 change detection loop. 问题是在1个变化检测循环内多次调用ngFor
。 Regardless of my tick interval or the precision of snapshot.remaining
(ie seconds or tenths of seconds) if snapshot.remaining
happens to change on a subsequent call to ngFor
during change detection, I get an exception: 无论我的tick时间间隔或snapshot.remaining
(即秒或十分之一秒)的精度如果在更改检测期间后续调用ngFor
时, snapshot.remaining
发生更改,我都会收到异常:
Expression has changed after it was checked
If I render only a single timer without using ngFor
then change detection works fine--even for intervals of 10ms
. 如果我只渲染一个计时器而不使用ngFor
那么更改检测工作正常 - 即使是10ms
间隔。
How can I render multiple timers on a page, presumably using ngFor
, without triggering this exception? 如何在页面上渲染多个计时器,大概使用ngFor
,而不会触发此异常?
Solution 解
After a bit of testing, it seems the problem is using a SnapshotPipe
with ngFor
to capture the snapshot of the Timer data. 经过一些测试后,似乎问题是使用带有ngFor
的SnapshotPipe
来捕获Timer数据的快照。 What finally worked is to take the snapshot
of the Timer data in the View Component. 最终工作的是在View Component中获取Timer数据的snapshot
。 As mentioned in the answer below, this uses a pull
method to get changes, instead of a push
method. 如下面的答案所述,这使用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
);
}
}
The first suspicious thing is toJSON
(it has wrong name or returns string
or converts string to array), which objects are contained in timers
array? 第一个可疑的东西是toJSON
(它有错误的名字或返回string
或将字符串转换为数组),哪些对象包含在timers
数组中?
During change detection for loop might be evaluated multiple times so it should not generate new objects. 在更改期间,可能会多次评估循环,因此不应生成新对象。 Also toJSON
pipe should be marked as pure
(see Pipe decorator options). 另外toJSON
管道应该标记为pure
(参见Pipe decorator选项)。 Also it is better to provide trackBy
function for ngFor
. 此外,它是更好地提供trackBy
的功能ngFor
。 In general it is better in this case to update class field instead of using pipe. 通常,在这种情况下更好的是更新类字段而不是使用管道。
public snapshots:any[] = [];
private timers:any[] = [];
setInterval(()=>{
this.snapshots = this.updateSnapshots(this.timers);
}, 100);
<ion-card class="timer"
*ngFor="let snapshot of snapshots"
>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.