Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 713
danijar Avatar asked Jul 02 '16 23:07

danijar


People also ask

How do you repeat HTML element multiple times using ngFor based on a number?

We can print repeated lines of content based on a number using the javascript/typescript function Array() which will generate a list of number from 0 to n-1. We traverse this list to produce n repeated lines of content.

Can we use two ngFor?

We use the NgFor directive to loop over an array of items and create multiple elements dynamically from a template element. The template element is the element the directive is attached to. We can nest muliple NgFor directives together.

Can we use ngIf and ngFor together?

Use ngFor and ngIf on same element It's very common scenario where we want to repeat a block of HTML using ngFor only when a particular condition is true. i.e., if ngIf is true.So in this case to use *ngIf and *ngFor on same element, place the *ngIf on a parent element that wraps the *ngFor element.


2 Answers

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; }
like image 181
Michael Avatar answered Oct 13 '22 21:10

Michael


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.

like image 39
adriancarriger Avatar answered Oct 13 '22 20:10

adriancarriger