简体   繁体   English

angular2如何在`ngFor`中渲染一个计时器组件

[英]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.previousValuechanges.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. 经过一些测试后,似乎问题是使用带有ngForSnapshotPipe来捕获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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM