ChartJs does not render chart when binding canvas id in Angular

Viewed 226

I am building an Angular app and I want to show a list of charts using Chart.js by looping through the following array:

  data = [
    {
      id: 'chartOne',
      title: 'Chart One',
      type: 'bar',
      lables: ['Villas By Taru', 'Watch Tower'],
      data: [18, 12],
    },
    {
      id: 'chartTwo',
      title: 'Chart Two',
      type: 'bar',
      lables: ['Tea Avenue', 'The Grill Bar'],
      data: [18, 12, 2, 7],
    },
  ];
  1. I am using *ngFor to render the list of charts on the view.
  2. I am looping through the above-mentioned array to create a new Chart object and configure the chart.

HTML

<div *ngFor="let data of data">
  <canvas [id]="data.id"></canvas>
</div> 

TS

import { Component, OnInit, VERSION } from '@angular/core';
import { Chart, registerables } from 'chart.js';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  data = [
    {
      id: 'chartOne',
      title: 'Chart One',
      type: 'bar',
      lables: ['Villas By Taru', 'Watch Tower'],
      data: [18, 12],
    },
    {
      id: 'chartTwo',
      title: 'Chart Two',
      type: 'bar',
      lables: ['Tea Avenue', 'The Grill Bar'],
      data: [18, 12, 2, 7],
    },
  ];

  ngOnInit() {
    this.data.forEach((element) => {
      this.generateType(element);
    });
  }

  generateType(data: any) {
    const myChart = new Chart(data.id, {
      type: 'bar',
      data: {
        labels: data.labels,
        datasets: [
          {
            label: '# of Votes',
            data: data.data,
            backgroundColor: [
              'rgba(255, 99, 132, 0.2)',
              'rgba(54, 162, 235, 0.2)',
              'rgba(255, 206, 86, 0.2)',
              'rgba(75, 192, 192, 0.2)',
              'rgba(153, 102, 255, 0.2)',
              'rgba(255, 159, 64, 0.2)',
            ],
            borderColor: [
              'rgba(255, 99, 132, 1)',
              'rgba(54, 162, 235, 1)',
              'rgba(255, 206, 86, 1)',
              'rgba(75, 192, 192, 1)',
              'rgba(153, 102, 255, 1)',
              'rgba(255, 159, 64, 1)',
            ],
            borderWidth: 1,
          },
        ],
      },
      options: {
        scales: {
          y: {
            beginAtZero: true,
          },
        },
      },
    });
  }
}

This approach does not work and throws below error:

chart.esm.js:5343 Failed to create chart: can't acquire context from the given item

You can find the codebase here: StackBlizEditorURL

What am I doing wrong here? Please help me out.

1 Answers

I think you are using the wrong lifecycle hook to create your charts.

In ngOnInit the components view isn't initialized yet. Therefore there are no DOM-elements with data.id in the DOM and Chart.js throws an error.

The correct lifecycle hook to use would be ngAfterViewInit.

So you have to replace

  ngOnInit() {
    this.data.forEach((element) => {
      this.generateType(element);
    });
  }

with

  ngAfterViewInit() {
    this.data.forEach((element) => {
      this.generateType(element);
    });
  }

and update the imports accordingly.

You can read more about Angulars lifecycle hooks here.

Related