0

I have an *ngFor property in my Ionic-angular template which is printing all objects of an array property. The thing is that this array can change, having more elements or even updating some attributes for the already present objects. Because of that, I'm requesting to my server the array each 1 seconds using rxjs, subscribing it and reassigning the server response to the array property again.

Above mentioned has as result that the view is re rendered each second which causes that the data is appearing and dissapearing constantly on screen.

How is the best way to deal with that? I know that the way of updating the array is pushing the elements. However, as the old objects can change their properties values I don't know how to continue working.

I will show you some simplified code snnipets:

Interval subscription

import { interval } from 'rxjs';
private subscription;
simulationsResponse;
//data is the property for *ngFor
data;
public intervallTimer = interval(1000);

ionViewWillEnter() {
    this.subscription = this.intervallTimer.subscribe(x => {

        this.dm.getAllSimulations().then(res => {
          this.simulationsResponse = res;
              this.data = this.simulationsResponse.simulators;

        });
    });
}

Template

<div class="listSimulations" *ngFor="let simulation of data">
    .
    .
    .
    .
</div>
Ray
  • 113
  • 1
  • 15

2 Answers2

1

In order to avoid angualar tearing down and recreating the whole DOM whenever you set a new array, you need to track the entries in the array using trackBy:

interface Simulation {
  public _id: string;
  ...
}

interface SimulationResponse {
  public simulators: Simulation[];
  ...
}

import {TrackByFn} from '@angular/core';
import {interval, from} from 'rxjs';
import {mergeMap} from 'rxjs/operators';

private subscription;
simulationsResponse: SimulationResponse;
data: Simulation[];

ionViewWillEnter() {
    this.subscription = interval(1000)
                    .pipe(mergeMap(_=>from(this.dm.getAllSimulations()))
                   .subscribe(res => {
                       this.simulationsResponse = res;
                       this.data = res.simulators;
                   });

 trackSimulation: TrackByFn<Simulation> = simulation => simulation._id;
}

<div class="listSimulations" *ngFor="let simulation of data; trackBy: trackSimulation">
    .
    .
    .
    .
</div>
Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
  • I'm having problems with your code. The function getAllSimulations() returns Promise so the variable res of subscribe method is undefined – Ray Aug 14 '19 at 16:22
  • Updated, please check – Jota.Toledo Aug 14 '19 at 16:42
  • It's almost working fine. The new element is showing in the view, but one of the old elements is not rendering. Something strange is happening, I've inspected the element with dev tools and the html and the data is there, but the result is a blank element. Do you have any idea of what can be this? – Ray Aug 14 '19 at 17:08
  • If you provide a small reproduction of your problem in stackblitz, then I might be able to look into it. – Jota.Toledo Aug 14 '19 at 17:28
  • I'm unable to reproduce the behaviour in a small example. I don't know what is happening in my project but it's unbelievable. I could give some images, the data properties are in the dom but is not showing, it only shows an empty div – Ray Aug 14 '19 at 18:39
  • Ok, finally I found the bug, I had a conditional value for class attribute, deleting that works super nice, thank you so much! – Ray Aug 14 '19 at 19:08
-2

You'll need to write a your custom ngFor Pipe for this. In the pipe, you have stop the execution for 1 second.

Please refer to this answer to write your custom pipe. - https://stackoverflow.com/a/34165371/11928048

  • 1
    I don't understand how can filtering the array's elements can help me with my task. I need to display all elements – Ray Aug 14 '19 at 15:39