1

I have a component where I'm showing some charts and a table beside it that shows that latest value of each chart.

I'm doing this for each object in an array, like this:

<div class="patient-box level-2" *ngFor="let bed of patientService.bedsLevel2" draggable="true" (dragstart)="onDrag($event, bed)">
...
<table class="vsTable">
    <tr>
      <th [matTooltip]="translations?.Tooltip.Type">Type</th>
      <th [matTooltip]="translations?.Tooltip.AverageReading1624">16-24t</th>
      <th [matTooltip]="translations?.Tooltip.Chart" translate>Chart</th>
      <th [matTooltip]="translations?.Tooltip.AverageReading01">0-1t</th>
    </tr>
    <tr *ngFor="let vitalSign of vitalSigns; let i = index">
      <td [matTooltip]="getTooltip(vitalSign)">{{vitalSign}}</td>
      <td>{{getVitalSign(bed.timeWindows[5], vitalSign)}}</td>
      <td>
        <chart [options]="lineChartOptions" (load)="saveLineChart($event.context, vitalSign, bed)" draggable="true"></chart>
      </td>
      <td>{{getVitalSign(bed.timeWindows[0], vitalSign)}}</td>
    </tr>
  </table>

Every now and then, I'm making a call to a server to update the patientService.bedsLevel2 array:

updateBeds() {
this.patientService.bedsLevel2.forEach(bed => {
  this.patientService.getBedDetails(bed.cetreaName).subscribe(
    (result: BedDetails) => {
      this.updateChartData(result);
      bed = result;
    },
    err => {
      console.log(err);
    }
  );
});
this.updateBedsTimeout = setTimeout(() => this.updateBeds(), BED_UPDATE_INTERVAL);

}

As you can see in the code, I am using the result to update the chart data, and then I'm assigning it as a new value to the bed object. When this method completes, the view of the chart has been updated, but the data in the table next to it has not.

I've read that Angular doesn't detect changes unless the reference to the array changes, so I've tried adding each of the following to the end of the updateBeds() method:

this.patientService.bedsLevel2 = [...this.patientService.bedsLevel2];
this.patientService.bedsLevel2 = this.patientService.bedsLevel2.slice();

None of them fixed the problem though. What could be causing this problem, why doesn't my attempt to fix it work, and what will fix it? I've read something about manually making change detections with ChangeDetectorRef, so I might try that out.

3
  • Aren't you just changing the value of a local variable and not the value in the array?? bed = result is just changing the pointer for the bed local variable to point at your new result. That isn't changing the reference in your array. Commented Mar 28, 2018 at 18:28
  • @DanielWStrimpel I am doing a forEach of of the array where bed represents each object. Commented Mar 28, 2018 at 18:34
  • Yes, but bed is a variable that points to your object in memory. When you re-assign a value to that variable, you are simply changing what that local variable is pointing to... this has no impact on the value in the array. Commented Mar 28, 2018 at 18:37

1 Answer 1

2

You are incorrectly changing the value of the local bed variable. Please look over the code below and run to see that simply changing the local reference to point to a new object will not actually change the value in the array. You must change the reference in the original array by index if you wish to change the entire object reference (shown below).

let beds = [
  { cetreaName: 'Bed #1' },
  { cetreaName: 'Bed #2' },
  { cetreaName: 'Bed #3' }
];

console.log('before', JSON.stringify(beds));

beds.forEach(bed => {
  bed = { cetreaName: 'Updated ' + bed.cetreaName };
});

console.log('after (not updating)', JSON.stringify(beds));

beds.forEach((bed, index) => {
  beds[index] = { cetreaName: 'Updated ' + bed.cetreaName };
});

console.log('after (updating)', JSON.stringify(beds));

Sign up to request clarification or add additional context in comments.

2 Comments

I see, thanks. I thought the forEach would give me a reference to the actual objects in the array and make it possible to assign new values to them. What if I add all the results I get to a new array and then at the end write patientServive.bedsLevel2 = new array with objects from server call ?
The forEach does give you a reference to that actual objects. If you change a property on that object, it will be seen anywhere that uses that object. However, changing the object that a variable points to does nothing to the original object that it was pointing to. But, yeah, the best way to solve your problem is probably to batch process your requests and set your array to that new array to make sure that Angular reprocesses it in your template. RxJS has methods to wait until a collection of Observables have completed (e.g. Observable.forkJoin).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.