Search code examples
angularangular2-formsng2-chartsangular4-forms

How to Render ng2Chart (Barchart ) dynamically using angular 4


I used ng2charts module to render charts. If i try with below dummy data, bar chart rendering properly.

Typescript

  public barChartOptions: any = {
    scaleShowVerticalLines: false,
    responsive: true
  };
  public barChartLabels: string[] = ['Label1', 'Label2', 'Label3'];
  public barChartType: string = 'bar';
  public barChartLegend: boolean = true;

  public barChartData: any[] = [
    { data: [65, 59, 80], label: 'Data1' },
    { data: [28, 48, 40], label: 'Data2' },
    { data: [30, 28, 80], label: 'Data3' }
  ];

Component Html :

<canvas style="height:230px" baseChart [datasets]="barChartData" [labels]="barChartLabels" [options]="barChartOptions" [legend]="barChartLegend" [chartType]="barChartType" (chartHover)="chartHovered($event)" (chartClick)="chartClicked($event)"></canvas>

But If i tried to get data from server and set data dynamically not working as expected.

I'm Getting below error

HomeComponent.html:73 ERROR TypeError: Cannot read property 'data' of undefined

Please refer my below code.

export class HomeComponent implements OnInit {

  serverData: any;

  public barChartOptions: any = {
    scaleShowVerticalLines: false,
    responsive: true
  };


  public barChartLabels: string[];
  public barChartType: string = 'bar';
  public barChartLegend: boolean = true;

  public barChartData: any[];


  constructor(private fb: FormBuilder, private Service: Service,
    private route: ActivatedRoute, private router: Router, private _configService: ConfigService) {
    this.getApis();
  }

  ngOnInit() {
    const loggedInUser = new LoggedInUser();
    const user = loggedInUser.getLoggedUser();
    if (user != null) {
      this.loggedInUserId = loggedInUser.getLoggedUser().UserId;
    }

  }

  getApis() {
    this._configService.get()
      .subscribe(c => {
        this.apiEndpoints = c;
        this.loadDashBoardDetails();
      },
      error => { this.msg = <any>error; });
  }

  loadDashBoardDetails() {
    this.indLoading = true;
    this.Service.get("APIENDPOINT")
      .subscribe(c => {
        this.serverData = c[0];
        this.loadserverData();
        this.indLoading = false;
      },
      error => {
        this.msg = <any>error;
      }

      );
  }
  loadserverData() {
    let chartData: any[];
    let data1 = '';
    let data2 = '';
    let data3 = '';
    this.barChartLabels = new Array<string>();
    chartData = new Array<any>();
    for (let _i = 0; _i < this.serverData.length; _i++) {
      this.barChartLabels.push(this.serverData[_i].Code);
      if (data1 === '') {
        data1 = this.serverData[_i].Target;
      } else {
        data1 = data1 + ',' + this.serverData[_i].data1;
      }

      if (data2 === '') {
        data2 = this.serverData[_i].data2;
      } else {
        data2 = data2 + ',' + this.serverData[_i].data2;
      }

      if (data3 === '') {
        data3 = this.serverData[_i].data3;
      } else {
        data3 = data3 + ',' + this.serverData[_i].data3;
      }
    }

    chartData.push({
      data: data1,
      label: 'data1 label'

    });

    chartData.push({
      data: data2,
      label: 'data2 label'

    });

    chartData.push({
      data: data3,
      label: 'data3 label'

    });

    this.barChartData = chartData;
  }
 }

Solution

  • You're getting that error because the data is undefined when the chart is rendered. You can avoid this by using *ngIf on your chart

    <canvas
        *ngIf="barChartData"
        baseChart
        style="height:230px" 
        [datasets]="barChartData" 
        [labels]="barChartLabels" 
        [options]="barChartOptions" 
        [legend]="barChartLegend" 
        [chartType]="barChartType" 
        (chartHover)="chartHovered($event)" 
        (chartClick)="chartClicked($event)">
    </canvas>
    

    The above HTML will not be rendered until the data is resolved. Once the data is resovled and barChartData is no longer undefined, the chart will be rendered.


    EDIT:

    The chart won't rerender if you keep adding data to the barChartData array. When you get your data, instead of pushing it to the barChartData array, create a local array to build the data. Then assign the local array to barChartData when all the data is populated in the local array. Ng2Charts doesn't rerender until the reference to the array changes or you manually call for it to rerender.


    EDIT2

    Your data also should be of type number. You have data1 = '';