39

I am doing a project in Angular8 and creating charts using ChartJS. After running the project, it will show the charts. But it will give an error saying:

Property 'getContext' does not exist on type 'HTMLElement'.

How do I get rid of this error?

Here is my code:

chart.component.html

<div id="container" style="width:350px;height:250px">
  <canvas id="myChart" width=300 height=300></canvas>   
</div>

chart.component.ts

import {Component, OnInit} from '@angular/core';
import {Chart} from 'chart.js';
import {ChartService} from '../charts/chart.service';
import {HttpClient} from '@angular/common/http';

// import {DATA} from '../CHART/CHARTS.MODEL';

@Component({
  selector: 'app-charts',
  templateUrl: './charts.component.html',
  styleUrls: ['./charts.component.scss']
})
export class ChartsComponent implements OnInit {

  constructor(
    private ChartItems: ChartService,
    private httpClient: HttpClient
  ) {   }

  ngOnInit() {
    this.getChartDetails();
}

  getChartDetails() {
    this.ChartItems.getChart().subscribe(data => {
      console.log(data);
      const chartLable = [];
      const chartDetails = [];

      for (let i = 0; i < data.chartDetails[0].chartData.length; i++) {
        chartLable.push(data.chartDetails[0].chartData[i].x);
        chartDetails.push(data.chartDetails[0].chartData[i].y);
      }

 

      const ctx = document.getElementById('myChart').getContext('2d');
      const myChart = new Chart(ctx, {
          type: 'bar',
          data: {
              labels: chartLable,
              datasets: [{
                  label: '# of Votes',
                  data: chartDetails,
                  backgroundColor: [
                      'rgba(255, 99, 132, 0.2)',
                      'rgba(54, 162, 235, 0.2)',
                      'rgba(255, 206, 86, 0.2)',
                  ],
                  borderColor: [
                      'rgba(255, 99, 132, 1)',
                      'rgba(54, 162, 235, 1)',
                      'rgba(255, 206, 86, 1)',
                  ],
                  borderWidth: 1
              }]
          },
          options: {
              scales: {
                  yAxes: [{
                      ticks: {
                          beginAtZero: true
                      }
                  }]
              }
          }
      });
  }
  );
 
}}

chart.service.ts

import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type':  'application/json',
    })
};

@Injectable({
  providedIn: 'root'
})
export class ChartService {

  httpOptions: any;
  baseUrl: any;
  headers: any;
  constructor( private http: HttpClient ) {
      this.headers = new Headers( { 'content-type': 'application/json'} );
      // this.httpOptions = new RequestOptions( { headers: this.headers } );
}

  getChart() {
    console.log('SUCCESS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
    return this.http.get('https://api.myjson.com/bins/8au55',"");

}
}
shreyasm-dev
  • 2,711
  • 5
  • 16
  • 34
CSK
  • 569
  • 1
  • 7
  • 19

5 Answers5

91

I would try:

const canvas = <HTMLCanvasElement> document.getElementById('myChart');
const ctx = canvas.getContext('2d');

the purpose of Typescript is to avoid wrong types. By default document.getElementById returns a HTMLElementtype which is a generic type. In order to make your app understand it is a canvas element you need to cast it using <CastedToType> syntax.

JSmith
  • 4,519
  • 4
  • 29
  • 45
  • It will work. Thank you. But in service file, in getChart() method, after url , how to send second parameter. – CSK Oct 03 '19 at 12:09
  • can you marked as answered if that answered your question please. What you are asking in the comment is another question. By the way I'm not sure to understand what you mean by asking "how to send second parameter". Thanks in advance – JSmith Oct 03 '19 at 12:38
  • This answered helped, in my case I wrote `const canvas: HTMLCanvasElement = document.getElementById('myChart');` – csalmeida Jun 29 '21 at 12:06
28

Try this:

const canvas = document.getElementById('myChart') as HTMLCanvasElement;
const ctx = canvas.getContext('2d');
Utkarsh
  • 635
  • 7
  • 14
  • Welcome to stackoverflow. In addition to the answer you've provided, please consider providing a brief explanation of why and how this fixes the issue. – jtate Nov 15 '19 at 13:42
  • We simply just assign that canvas element to the typescript variable and we do declare that it is a 'HtmlCanvasElement' because the getContext property exists on HtmlCanvasElement. If we donot declare this then the compiler will be default treat it as HtmlElement and will generate error that getContext is not its property.. Hope i answered your question. – Utkarsh Nov 16 '19 at 15:34
2

Best to use runtime type validation which TS understands.

const canvas = document.querySelector('#my-canvas')
if (!(canvas instanceof HTMLCanvasElement)) return

canvas.getContext(...)

This handles the case where the element you query for has the wrong tag name.

<div id="my-canvas" /> 
<canvas id="my-canvas1" />
vaughan
  • 6,982
  • 6
  • 47
  • 63
1

const canvas = document.getElementsByTagName('canvas')[0]; will return an HTMLCanvasElement, but

const canvas = document.getElementById('someId'); will return an HTMLElement object instead of HTMLCanvasElement, which has no 'getContext' method.

Benjamin L
  • 11
  • 1
0

simply cast canvas as HTMLCanvasElement inline as follows

const canvas = document.getElementById('myChart');
const ctx = (canvas as HTMLCanvasElement).getContext('2d');

cheers.

Mussa Charles
  • 659
  • 7
  • 10