ng2-charts: Chart doesn't redraw / update non data/dataset related settings

Looking at the code I realized that dynamic changes to the data/datasets is indeed supported and will cause the chart to update.

BUT, no other change to a chart is being supported, eg. labels (amount or text), changes to the settings etc. this would require a complete chart redraw (chartJS dependency?) as far as I can tell.

In your code, I see that getChartBuilder() does that, triggered by refresh() which only happens on 2 occasions: ngOnInit() & ngOnChanges() IF not changes.hasOwnProperty('data') || ...

That’s quite a bit of limitation right there.

I recommend to add public method to call a complete refresh or better yet, adapt the ngOnChanges() routine to look for new changes to other chart settings and if outside of data/dataset changes call refresh() instead of just an update().

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 20
  • Comments: 30 (1 by maintainers)

Most upvoted comments

I needed a quick solution and couldn’t really wait for an update so I programmed a quick workaround:

First we need a reference to the baseChart element

<canvas baseChart #baseChart="base-chart" width="400" height="250"
	            [datasets]="chartData"
	            [labels]="chartLabels"
	            [options]="chartOptions"
	            [legend]="chartLegend"
	            [chartType]="chartType"></canvas>

Then we can access and save the directive to a member of our component:

@ViewChild("baseChart")
    chart: BaseChartDirective;

And whenever we change something in the labels or other non updating options, we trigger this bit:

if(this.chart !== undefined){
       this.chart.ngOnDestroy();
       this.chart.chart = this.chart.getChartBuilder(this.chart.ctx);
}

This just destroys the charts and recreates is (basically copied from the refresh function). I hope that helps until its fixed.

I have the problem that labels are not correctly refreshed. The solutions from @rightisleft and @Shadowlauch didn’t work for me.

That’s my workaround:

Accessing the directive via ViewChild:

<canvas baseChart #baseChart="base-chart" ...></canvas>
@ViewChild("baseChart") chart: BaseChartDirective;

And after setting the new data I run this function:

reloadChart() {
    if (this.chart !== undefined) {
       this.chart.chart.destroy();
       this.chart.chart = 0;

       this.chart.datasets = this.datasets;
       this.chart.labels = this.labels;
       this.chart.ngOnInit();
    }
}

this.datasets and this.labels hold my data.

Thanks for all the input in this channel 👍

Fixed in my fork along with some other things. https://github.com/donothingloop/ng2-charts-x

Addendum:

Here is my local fix that solves the problem:

public ngOnChanges(changes: SimpleChanges): void {
    if (this.initFlag) {
        // Check if the changes are in the data or datasets
        if (changes.hasOwnProperty('data') || changes.hasOwnProperty('datasets')) {
            // Oliver, May 19th 17
            if (changes.hasOwnProperty('legend') ||
                changes.hasOwnProperty('colors') ||
                changes.hasOwnProperty('labels') ||
                changes.hasOwnProperty('options')) {
                this.refresh();
            } else /* Oliver, May 19th 17 */ if (changes['data']) {
                this.updateChartData(changes['data'].currentValue);
            } else {
                this.updateChartData(changes['datasets'].currentValue);
            }

            this.chart.update();
        } else {
            // otherwise rebuild the chart
            this.refresh();
        }
    }
}

I have the problem that labels are not correctly refreshed. The solutions from @rightisleft and @Shadowlauch didn’t work for me.

That’s my workaround:

Accessing the directive via ViewChild:

<canvas baseChart #baseChart="base-chart" ...></canvas>
@ViewChild("baseChart") chart: BaseChartDirective;

And after setting the new data I run this function:

reloadChart() {
    if (this.chart !== undefined) {
       this.chart.chart.destroy();
       this.chart.chart = 0;

       this.chart.datasets = this.datasets;
       this.chart.labels = this.labels;
       this.chart.ngOnInit();
    }
}

this.datasets and this.labels hold my data.

Thanks for all the input in this channel

This is the only thing that worked. All the other solutions give some errors at some point!

Use ngIf for

Error: ng-charts configuration error, data or datasets field are required to render char line

<div style="display: block" *ngIf="chartData.datasets.length > 0" >
<canvas baseChart #baseChart="base-chart" width="400" height="250"
	            [datasets]="chartData"
	            [labels]="chartLabels"
	            [options]="chartOptions"
	            [legend]="chartLegend"
	            [chartType]="chartType"></canvas>
</div>

looking at all the open pull reqs, it seems though that the original author has lost interest in supporting this.

Is this going to get addressed in a fix? i am having the same issue

If there are two charts(Pie and Line) then only first rendered charts get refreshed.Can anyone please tell me how to refresh particular chart.

@Shadowlauch Regarding this https://github.com/valor-software/ng2-charts/issues/806#issuecomment-317352086.

I had to add line 3 for my labels to properly update, even though I had already set the ngModel value for the labels to the same value.

if (this.chart !== undefined) {
        this.chart.ngOnDestroy();
        this.chart.labels = lineSeriesLabels;
        this.chart.chart = this.chart.getChartBuilder(this.chart.ctx);
      }

+1 In my opinion an empty datasets array (no datasets) should be valid. Because adding datasets or / and data of datasets later. Chart.js supports that. http://www.chartjs.org/samples/latest/charts/line/basic.html

The workaround with destory and init works not really good. But the idea is good, Create the chart completely new instead of update.

But anyway, this issue should be fixed. The chart should update with every change. Also for ticks min, max, datasets and the other options.

Currently if you work on one dataset, you can update the chart with this.chart.chart.update(). If you added a dataset before and only updates the data of dataset. This feels so wrong 😄

@rightisleft I can’t reproduce that error.

One thing I noticed though while trying to figure out where the error occurs. My Chart does not correctly update, because when I trigger the chart redraw the changes to the labels have not yet been detected by the Angular change detection. So I had to injuect the ChangeDetectionRef and call .detectChanges() right before I call the ngOnDestroy.

@Shadowlauch - The above causes a null data error:

ModelSublabelComponent.html:59 ERROR TypeError: Cannot read property 'data' of undefined
    at charts.js:90
    at Array.forEach (<anonymous>)
    at BaseChartDirective.webpackJsonp.../../../../ng2-charts/charts/charts.js.BaseChartDirective.updateChartData (charts.js:89)
    at BaseChartDirective.webpackJsonp.../../../../ng2-charts/charts/charts.js.BaseChartDirective.ngOnChanges (charts.js:39)
    at checkAndUpdateDirectiveInline (core.es5.js:10891)
    at checkAndUpdateNodeInline (core.es5.js:12382)
    at checkAndUpdateNode (core.es5.js:12321)
    at debugCheckAndUpdateNode (core.es5.js:13180)
    at debugCheckDirectivesFn (core.es5.js:13121)

some update?