Search code examples
angularrxjsobservable

angular: get random element from observable array in template


I am trying to get a random element from an Observable array to use in the template. Currently I am using

@Select(SomeState.tiles) tiles$: Observable<Tile[]>;

and

getRandomTile$(): Observable<Tile> {
  return this.tiles$.pipe(
      map(tiles => {
        return tiles[Math.floor(Math.random() * tiles.length)];
      })
  );
}

and in the template

<ng-container *ngFor="let tile of othertiles; index as i">
    <div *ngIf="i % 8 == 0 && (tiles$ | async)?.length">
          <ng-container *ngIf="getRandomTile$() | async; let r">
              <img [src]="r.imgUrl" />
          </ng-container>
      </div>
</ng-container>

However on scroll the image changes since it seems to update continuously.

Adding take(1) in the get method also does not seem to help.

Does anybody have an idea how to get this working correctly? :)


Solution

  • The problem is due to change detection triggered in your application. When it happens, functions used in a template are evaluated once again, resulting in the random element changing.

    Rather than exposing the random logic as a function, expose it as a variable:

    randomTile$: Observable<Tile> = this.tiles$.pipe(
          map(tiles => {
            return tiles[Math.floor(Math.random() * tiles.length)];
          })
      );