8

This is really my first time using Chart.js and I am importing it into an Angular component. I am trying to at this point just create a simple bar chart. I am getting the following error in my console:

core.controller.js:118 Failed to create chart: can't acquire context from the given item

not sure what I am doing wrong here!

this is the TS file for my component:

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

@Component({
  selector: 'app-propel-factor',
  templateUrl: './propel-factor.component.html'
})
export class PropelFactorComponent implements OnInit {

    chart = [];
    labels: any = [];

    data: any = [];

    constructor() { }

    ngOnInit() {
        data.forEach(item => {
            this.labels.push(item.name);
            this.data.push(item.value);
        });

        this.chart = new Chart('canvas', {
            type: 'bar',
            labels: this.labels,
            data: {
                labels: this.labels,
                data: this.data
            },
            options: {
                responsive: true
            }
        });
    }

}

and then my template is simply:

<div *ngIf="chart">
    <canvas id="canvas">{{ chart }}</canvas>
</div>

I also wanted to go on record saying that i tried this fix chart.js Failed to create chart: can't acquire context from the given item and still go the same error!

3
  • 3
    This answer might help you get started with chart.js: stackoverflow.com/questions/46328575/… Commented Jan 1, 2018 at 0:35
  • 2
    @Z.Bagley thanks so much. Commented Jan 1, 2018 at 1:42
  • 1
    Are you able to fix this issue...? Please add you answer if you have fixed this issue. Commented May 30, 2018 at 10:22

5 Answers 5

8

If you look at the documentation for creating a chart in Chart.js, the first parameter is a context obtained from a DOM element, and not a string:

var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {

You can get a reference to the DOM element by using template variables and ElementRef:

HTML

<div *ngIf="chart">
    <canvas #canvas id="canvas">{{ chart }}</canvas>
</div>

Tyepscript:

import { Component, OnInit, AfterViewInit, ElementRef, ViewChild } from '@angular/core';
import { Chart } from 'chart.js';
import { data } from './data';

@Component({
  selector: 'app-propel-factor',
  templateUrl: './propel-factor.component.html'
})
export class PropelFactorComponent implements OnInit, AfterViewInit {
    @ViewChild('canvas') canvas: ElementRef;

    chart = [];
    labels: any = [];

    data: any = [];

    constructor() { }

    ngOnInit() {
        data.forEach(item => {
            this.labels.push(item.name);
            this.data.push(item.value);
        });

    }
    ngAfterViewInit() {
        this.chart = new Chart(this.canvas.nativeElement.getContext('2d'), {
            type: 'bar',
            labels: this.labels,
            data: {
                labels: this.labels,
                data: this.data
            },
            options: {
                responsive: true
            }
        });

    }

}
Sign up to request clarification or add additional context in comments.

5 Comments

TS complains ERROR in src/app/components/dashboard/propel-factor/propel-factor.component.ts(24,55): error TS2339: Property 'getContext' does not exist on type 'HTMLElement'.
check out the documentation on how to use chart.js: chartjs.org/docs/latest/getting-started. It looks like you might be missing a script?
It seems there is also a missing AfterViewInit
I think there is a hen-egg problem, at least when I tried to use your suggested answer. If you have *ngIf="chart" the chart is undefined and can't be used, because it would be defined only after onAfterViewInit, which is too late. Then the {{ chart }} part in the html leads to an exception, and the output of this [object object] would not be useful at all.
In the doc, the first parameter of string is also acceptable. see: chartjs.org/docs/latest/getting-started/…
4

I use Angular 6 and the answer that was there was not too helpful, even if it advanced me in solving the issue. There are several pitfalls to circumvent.

First the html of the part, important is the #chart so it can be referenced in the component.ts file. The other important is the class chart of the div with which the size can be managed via css:

<div class="chart">
  <canvas #chart ></canvas>
</div>

css:

div.chart {
  width: 600px;
  height: 300px;
}

component.ts:

import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';

import {Chart} from 'chart.js';

@Component({
  selector: 'app-report-quarterly',
  templateUrl: './report-quarterly.component.html',
  styleUrls: ['./report-quarterly.component.css']
})
export class ReportQuarterlyComponent implements OnInit {

  @ViewChild('chart') chartElementRef: ElementRef;

  chart : Chart;

  constructor() { }

  ngOnInit() {
    let context = this.chartElementRef.nativeElement;
    let data = { ... };  // data to be filled with meaningful data.
    this.chart = new Chart(context, data );
  }

}

Additionally in the package.json there where added things, for reference: For dependencies the line "chart.js": "^2.7.3", and for devDependencies the line "@types/chart.js": "^2.7.42", was added.

In this way the graph should be displayed properly.

2 Comments

Just to add to this, I suggest using the AfterViewInit hook, rather than OnInit.
Thanks for your comment. Will this make the chart refresh when the data changes?
3

I had the same problem and Finally I found the solution.

Insert this in the html file:

<div style="display: block">
<canvas #lineChart>{{ chart }}</canvas>
</div>

While your ts file has the following shape:

import { Component, OnInit, ViewChild } from '@angular/core';
import { Chart } from 'chart.js';
...
export class MyComponent implements OnInit {
  @ViewChild('lineChart', {static: true}) private chartRef;
  chart : any;
  month = [];
  price = [];

  constructor() { }

  ngOnInit() {

    this.month = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
    this.price = [10,20,30,40,50,40,10];
    this.chart = new Chart(this.chartRef.nativeElement,{
    type: 'line',
        data: {
          labels: this.month,
          datasets: [
            {
              data: this.price,
              borderColor: '#3cba9f',
              fill: false
            }
          ]
        },
        options: {
          legend: {
            display: false
          },
          scales: {
            xAxes: [{
              display: true
            }],
            yAxes: [{
              display: true
            }],
          }
        }
        });
  }
}

As you can see the solution is to initialize chartRef:

@ViewChild('lineChart', {static: true}) private chartRef;

After migration to Angular 8 you should declare manually if it's static or not, if you don't add {static: true}, by compiling you will have error for missing argument. Than you can easily create your chart in this way:

this.chart = new Chart(this.chartRef.nativeElement,{ ... });

Comments

2

I know this is an old thread, but I could not get any of these solutions to work for angular 9. After some research I've found a much simpler solution

For the html

   <div>
     <canvas id="myChart"></canvas>
   </div>

For the Component.ts file

import { Component } from '@angular/core';
import { Chart } from 'chart.js';

...

export class AppComponent {
  constructor() {}

  canvas: any;
  ctx: any;

  ngAfterViewInit() {
    this.canvas = document.getElementById('myChart');
    this.ctx = this.canvas.getContext('2d');

    let chart = new Chart( this.ctx, {data});
  }
}

1 Comment

shoud not access DOM code directly in angular. Please check @Pittuzzo code.
0

Just simply match the chartItem in the Chart(), with the id attribute.

example:

this.chart = new Chart("myChart", ...);
...
<canvas id="myChart">{{chart}}</canvas>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.