alim
alim

Reputation: 747

Angular 6 delay the loop

I have a question about angular loops. I would like to delay the rendering process on a ng-for. For example,

<div *ngFor="let data of items | delay">
  <app-my-component [data]="data"></app-my-component>
</div>

Delay 10ms for each render. The "items" array comes from another component that I can't change it. Also, the "items" array size can be increased and decreased. Maybe, I can redirect it with observable struct. I have tried observable with async but I can't achieve. Can someone show me an example ?

Upvotes: 4

Views: 2351

Answers (2)

Fan Cheung
Fan Cheung

Reputation: 11345

You can make use of async pipe to load an observable

//define your delay observable
this.delayItems=of(items).pipe(delay(1000))

in your template

<div *ngFor="let data of delayItems | async">
  <app-my-component [data]="data"></app-my-component>
</div>

Update

import { Component } from '@angular/core';
import { from, timer, Observable } from 'rxjs';
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  arr = [1, 2, 3, 4, 5]
  arr$:Observable<any[]>
  constructor() {
    this.arr$=from(this.arr).pipe(
    concatMap(item=>timer(1000).pipe(mapTo(item))),
    scan((acc,curr:number)=>acc.concat(curr),[])
  )

  }
}

html

<div *ngFor="let i of arr$ | async">
    <b>{{ i }}</b>
</div>

Upvotes: 1

Goga Koreli
Goga Koreli

Reputation: 2947

Actually this is interesting question and couldn't found exact question on the SO.

This is my solution, I wrote helper methods for easier understanding and future code reuse:

My solution on Live StackBlitz editor Link

import { from, timer, Observable } from 'rxjs';
import {
  scan,
  map,
  concatMap,
  share,
} from 'rxjs/operators';

const timeOf = (interval: number) => <T>(val: T) =>
  timer(interval).pipe(map(x => val));

const timed = (interval: number) => <T>(source: Observable<T>) =>
  source.pipe(
    concatMap(timeOf(1000)),
    map(x => [x]),
    scan((acc, val) => [...acc, ...val]),
  )

And the usage is:

  arr = [1, 2, 3, 4, 5]

  arr$ = from(this.arr)
    .pipe(
      timed(1000),
    )

As for HTML will be:

<div *ngFor="let i of arr$ | async">
    <b>{{ i }}</b>
</div>

As for explanation:

from(this.arr) will emit each of the array items separately and then I am using concatMap() for each emitted item to the timer(1000), which is essentialy delaying each emitted item for 1 second. Finally, I am using scan() operator to combine each emitted item back in the final accumulated array.

Upvotes: 2

Related Questions