[Chartjs]-Chart.js creating multiple Charts in Angular in same Component

0👍

in the template (html), the id for the canvas has to be different for each chart

0👍

i am going to give you diferrents approaches the first one it is the most simple the anothers you need a litle more knowledge…i hope it’s help

1.-
You can genera a single component just for render the chartjs graphic for example call it chart-dynamic with several inputs id for grabs the unique id you need for render several charts, and dataChart for all fully object to render , asuming that your tile. component looks like this

Important!! you dataChart must be thinking like a array of object and each object it is basicly a chart you will render into your template (follow the oficial documentacion of chartJs)

<div *ngIf="tile.type === 'tileImg'">
  <div class="card custom-card"
       routerLinkActive="glowing">
    <img class="card-img-top rounded" src="{{ tile.imgPath }}" alt="Tile image" />
    <div class="card-body">
      <p class=" card-text text-center">{{ tile.name }}</p>
    </div>
  </div>
</div>
<div *ngIf="tile.type === 'tileChart'">
  <div class="card custom-card"
       routerLinkActive="glowing">
<!-- NEW CODE -->

<ng-container *ngIf="dataChart?.length > 0" >
<div *ngFor="let chart of dataChart; let i=index">
    <app-chart-dynamic [id]="SomeUniqueID" [dataChart]="chart" [type]="chart.type"></app-chart-dynamic>
</div>
</ng-container>

<!-- Finish here -->
    <div class="card-body">
      <p class=" card-text text-center">{{ tile.name }}</p>
    </div>
  </div>
</div>

IN YOUR tile.component.ts Generate data method as array of objects, move generateChart function into the new component

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

import { Tile } from 'src/app/tile-container/tile/tile.model';
//import { TileChart } from 'src/app/tile-container/tile/tile-chart.model';

@Component({
  selector: 'app-tile',
  templateUrl: './tile.component.html',
  styleUrls: ['./tile.component.css']
})
export class TileComponent implements OnInit {
  @Input() tile: Tile;
  //tileChart: TileChart;
  chart = [];
  public dataChart: [];

  constructor() { }

  ngOnInit() {
    //console.log(this.tile);
    //console.log(this.tile.getType());
    //console.log(this.tile.getChartType() + "   " + this.tile.getChartData() + "  " + this.tile.getType().localeCompare('tileChart'));
    //console.log(this.tile.getType() == 'tileChart');
    this.getCharts();
  }

  public getCharts() { 
    // call data from you service or data mock
    this.dataChart = {....response};
  }


}

now assuming you has created your new component should looks like this (you have already import charJs and another stuff)

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

@Component({
  selector: 'app-chart-dynamic',
  templateUrl: './chart-dynamic.component.html',
  styleUrls: ['./chart-dynamic.component.css']
})
export class ChartDynamic implements OnInit, AfterViewInit {

  @Input() datasChart: any;
  @Input() id: string;
  @Input() type?: string;
  public idChart: any;
  @ViewChild('chart') chart: ElementRef;
  public chartObject: any;

  constructor() { }

  ngOnInit() {

  }

  generateChart(id: string ,chartType?: string, chartData: any) {
    this.idChart = this.id;
    this.chart = new Chart(`${this.idChart}`,  this.datasChart );
  }

  ngAfterViewInit() {
    this.drawGraphics();
  }

}

app-chart-dynamic html file

<div class="some-class-style" >
    <canvas [id]="id" #chart> {{ chart }}</canvas>
</div>

it should work if you add into your modules and etc

the another approach is combine viewChild and viewChildren with factory resolver it is more complex but more power full you should check firts based on angular documentation

Leave a comment