Angular2 Update ng2-charts with labels

ben picture ben · Apr 4, 2017 · Viewed 8k times · Source

I am starting to work these days with Angular2, and have a question with the framework ng2-charts.

Here is my component.ts code :

import { Component } from '@angular/core';
import { ChartsModule } from 'ng2-charts';
import { PredictionService } from './prediction.service'

@Component({
  selector: 'prediction-result-chart',
  templateUrl: './predictionResultChart.component.html'
})

export class PredictionResultChartComponent{

  public pieChartLabels:string[] = [];
  public pieChartData:number[] = [];
  public pieChartType:string = 'pie';
  public JSONobject = {}

  constructor(private predictionService: PredictionService){
    this.getPredictions();
  }

  public getPredictions() {
    this.predictionService.getPredictions('hello').do(result => this.populateChart(result)).subscribe();
  }

  public populateChart(obj): void{
    let labels:string[] = [];
    let data:number[] = [];
    for (var i = 0; i < obj.predictions.length; i++)
    {
      labels.push(String(obj.predictions[i].class));
      data.push(obj.predictions[i].percentage);
    };
    this.pieChartData = data;
    this.pieChartLabels = labels;
  }

  public chartClicked(e:any):void {}
  public chartHovered(e:any):void {}

}

The component.html code :

<div style="display: block">
  <canvas baseChart
      [data]="pieChartData"
      [labels]="pieChartLabels"
      [chartType]="pieChartType"
      (chartHover)="chartHovered($event)"
      (chartClick)="chartClicked($event)"></canvas>
</div>

The service code :

import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';

import { Observable }     from 'rxjs/Observable';
import 'rxjs/add/operator/map';


@Injectable()
export class PredictionService {

  private baseUrl: string = 'http://localhost:8080/predict/';
  constructor(private http : Http){
  }

  getPredictions(text :string) {
    return this.http.get(this.baseUrl + text).map(res => res.json());
  }

}

With the codes above, here is what I have, a chart without any colors : enter image description here

In fact when I looked deeply into my code, the HTML component took the variables at the beginning and update them then. So when the labels are empty, even if I add some labels, they will be added as undefined. So I have a chart with the right values but not the right labels. Everything marked as undefined.

And if I initiate the labels at the beginning, I will have a good coloured chart with the right values

So my questions are :

How to load the data, then render the HTML component ?

Is there anyway to render the chart.js component with no data and update it with right labels and data ?

Any help is needed, thanks.

Answer

jordanwillis picture jordanwillis · Apr 4, 2017

In standard chart.js you can use the .update() prototype method to re-render a chart after you have modified its data (including labels).

However, it appears that ng2-charts doesn't provide a mechanism to trigger the update (as per this github issue). I'm not very experienced in Angular2 at all, but perhaps this will work for you? The approach was taken from a comment made by zbagley in the github issue posted 17 days ago (unfortunately I could not find a way to generate a url referencing this specific comment).

The approach is to basically not render your chart until the data is available. Here is the change to your component.ts code.

import { Component } from '@angular/core';
import { ChartsModule } from 'ng2-charts';
import { PredictionService } from './prediction.service'

@Component({
  selector: 'prediction-result-chart',
  templateUrl: './predictionResultChart.component.html'
})

export class PredictionResultChartComponent {    
  public pieChartLabels:string[] = [];
  public pieChartData:number[] = [];
  public pieChartType:string = 'pie';
  public JSONobject = {};
  public isDataAvailable:boolean = false;

  constructor(private predictionService: PredictionService){
    this.getPredictions();
  }

  public getPredictions() {
    this.predictionService.getPredictions('hello').do(result => this.populateChart(result)).subscribe();
  }

  public populateChart(obj): void {        
    let labels:string[] = [];
    let data:number[] = [];
    for (var i = 0; i < obj.predictions.length; i++)
    {
      labels.push(String(obj.predictions[i].class));
      data.push(obj.predictions[i].percentage);
    };
    this.pieChartData = data;
    this.pieChartLabels = labels;
    this.isDataAvailable = true;
  }

  public chartClicked(e:any):void {}
  public chartHovered(e:any):void {}    
}

And then you would use ngIf in your component.html code.

<div style="display: block" *ngIf="isDataAvailable">
  <canvas baseChart
      [data]="pieChartData"
      [labels]="pieChartLabels"
      [chartType]="pieChartType"
      (chartHover)="chartHovered($event)"
      (chartClick)="chartClicked($event)"></canvas>
</div>