Я хочу визуализировать визуальный таймер обратного отсчета. Я использую этот компонент, https://github.com/crisbeto/angular-svg-round-progressbar, который полагается на SimpleChange
для доставки changes.current.previousValue
& changes.current.currentValue
.angular2 как визуализировать таймер Компонент внутри `ngFor`
Вот код шаблона
<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
с ngFor
, чтобы захватить снимок данных таймера. Что в конечном итоге работало, так это взять snapshot
данных таймера в компоненте «Просмотр». Как упоминалось в ответе ниже, для получения изменений используется метод 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
);
}
}
'toJSON' может быть переименован легко' snapshot', он возвращает простой объект с 'snapshot.remaining' в секундах с разным уровнем точности. Я добавил «trackByFn», но это не решило проблему. 'pure: true' не помогает, потому что' SimpleChange' нуждается в ссылке на объект, чтобы оставаться ** SAME **, чтобы записать 'changes.current.previousValue', что равно' snapshot.remaining'. Проблема в том, что таймер находится в 'MS' во время цикла' ngFor'.Когда я печатаю это, я думаю, что взлом может состоять в том, чтобы отбросить «snaphshot» ... – michael
Я имею в виду «throttle», и я пробовал «дроссель» с разными значениями, но не повезло. Кроме того, не имеет значения, насколько быстро существует цикл 'ngFor', поскольку, как вы уже упоминали, цикл обнаружения изменений, по-видимому, несколько раз вызывает' ngFor'. если значение синхронизации изменяется, ошибка возникает. Это верно, даже если точность составляет 1 секунду. – michael
Если я возьму таймер из 'ngFor', я смогу отображать таймер каждые 10MS без ошибок. Обновление вопроса, чтобы отразить этот факт – michael