How to reuse the elements of ngFor even if the list reference changes?
Asked Answered
A

2

10

I have an Angular 2 component that uses *ngFor to render a nested array of numbers.

@Component({
  selector: 'app',
  template: `
    <div *ngFor="let row in data">
      <div *ngFor="let curve in row">
        <chart [data]="curve">
      </div>
    </div>
  `,
  directives: [Chart],
})
export default class App {
  data: number[][][];
}

When I change data, Angular replaces the <chart> elements, even if the new array has the same dimensions. I'd like it only to update the properties of the charts but keep the elements (so that I can animate the data changes).

It's understandable that Angular replaces the elements since the new array is a new object reference. But how can I circumvent this?

Anacreontic answered 2/7, 2016 at 23:59 Comment(3)
Could you use ngForTrackBy?Gammon
@Gammon That's exactly what I was looking for: trackByIndex(index: number, data: any) { return index; }. Could you make this an answer, please?Anacreontic
+1 This question has a disturbingly view amounts of views and upvotes. ReactJS, for example, throws a hissy if you forget to give your list items a 'key' property so that the list can be economically re-rendered.Midlands
G
7

Using ngForTrackBy should help you here.

The following function should update the element properties whilst keeping the elements in the DOM.

trackByIndex(index: number, data: any) { return index; }
Gammon answered 3/7, 2016 at 12:35 Comment(0)
B
2

Working Plunker

Flat Data Structure

You can separate the metadata about your charts (title, id, etc) from the actual data points that will be changing and animated.

The *ngFor loop would use the metadata array and each chart component would have an @Input() that would pull from a separate object of data points.

// Metadata
this.charts = [
  {
    id: 1,
    title: 'Chart Title 1',
  },
  {
    id: 2,
    title: 'Chart Title 2',
  }
];

// Data Points
this.chartData = {
  1: [87, 95, 121, 20, 60, 131, 10, 139, 128, 99],
  2: [56, 107, 107, 144, 43, 7, 67, 35, 141, 62]
}

Template

<div *ngFor="let chart of charts">
  <app-chart [inputMeta]="chart" [inputData]="chartData[chart.id]"></app-chart>
</div>

Then in your chart component you can use the ngOnChanges() lifecycle hook to update the chart when you update your data points.

Baugh answered 3/7, 2016 at 4:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.