I\'m trying to create dynamically a chart using ng2-chart, I get information from an angular 2 service, when I change only labels of chart it works and when I change data on
Like Deyd pointed out before, this is caused by a combination of Angular 2+'s change detection and a bug in ng2-charts.
According to my own observations (correct me if I'm wrong), Angular merges several changes within a very short timeframe into a single collection (changes: SimpleChanges) when ngOnChanges is called.
Unfortunately, ng2-charts only checks if the dataset has been changed with this collection and updates it. Otherwise it completely rebuilds the entire chart. However, because of the way the change detection works, more than one property might have been changed. Then, only the dataset gets updated even if the labels and possibly other properties have been updated as well. See ngOnChanges in ng2-charts:
valor-software/ng2-charts/src/charts/charts.ts
And if you don't want to have a separate copy of ng2-charts in your app and fix the problem yourself, a possible workaround for this problem is to set the dataset with a short delay using JavaScript's built-in function setTimeout(callback: () => void, delay: number).
Before:
@Component({
selector: 'app-root',
template: `
`
})
export class AppComponent implements OnInit {
chartData: string[];
chartLabels: string[];
chartColors: string[];
onChange(id: string) {
getFromApiById(id)
.then(result => this._setChart(result.data, result.labels, result.colors));
}
private _setChart(data: string[], labels: string[], colors: string[]) {
this.chartData = data;
this.chartLabels = labels;
this.chartColors = colors;
}
}
After:
@Component({
selector: 'app-root',
template: `
`
})
export class AppComponent implements OnInit {
chartData: string[];
chartLabels: string[];
chartColors: string[];
onChange(id: string) {
getFromApiById(id)
.then(result => this._setChart(result.data, result.labels, result.colors));
}
private _setChart(data: string[], labels: string[], colors: string[]) {
this.chartLabels = labels;
this.chartColors = colors;
setTimeout(() => {
this.chartData = data;
}, 50);
}
}