6

i'm developing a web application - MEAN stack. i'm trying to use ChartJS doughnut chart but i need it to be completely dynamic - first, the number of charts is dynamic (each chart represent something else) so sometimes it will be 3 and sometime 20. second, i want ti be able to access each of the charts for real-time data changing. does it even possible? i tried to create an array that will hold each of the charts data and use *ngFor to create each chart an canvas element but it didn't work.

my chartjs.component.ts:

import { Component, OnInit } from '@angular/core';
import { DataService } from '../data.service';
import { Chart } from 'chart.js';
import { pieceLabel } from 'chart.piecelabel.js';
import {ElementRef} from '@angular/core';
@Component({
selector: 'app-chartjs',
templateUrl: './chartjs.component.html',
styleUrls: ['./chartjs.component.css']
})
export class ChartjsComponent implements OnInit {
constructor( private _dataService : DataService, private elementRef: ElementRef) { 

}
jsons: any;
NumberOfSystems: Number;
charts = [];
ngOnInit() {
this._dataService.getData().subscribe(data => {
  this.jsons = data
  this.NumberOfSystems = this.jsons.data[0][1].systems.length
  this.createChartsData()
}); 
}
createChartsData()
{
var array=[];
for(var i =0; i<this.NumberOfSystems;i++)
{
var pie ={
  type: 'doughnut',
  data: {
    labels: ["Disks", "Mgmt", "Hardware", "FC", "Vols&Pols"],
    datasets: [
      {
        backgroundColor:["#008000","#008000","#008000","#008000","#008000"],
        data: [20,20,20,20,20]
      }
    ]
  },
  options: {
    title: {
      display: false
    },
    animations: true,
    tooltips: {
      enabled: true
     },
     legend: {
      display: true
    }
  }
};
array.push(pie);
}
this.createCharts(array);
}
createCharts(pieData){
for(var j = 0; j<this.NumberOfSystems;j++)
{
  let htmlRef = this.elementRef.nativeElement.select(`#canvas`+j);
  console.log(htmlRef);
  var tempChart = new Chart(htmlRef,pieData[j]);
  this.charts.push(tempChart);
}   
}
}

and this is the chartjs.component.html:

<div>
<canvas *ngFor="let chart of charts; let i = index" id="canvas{{i}}">{{charts}}</canvas>
</div>

in this state, the ElementRef is null.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Arad Gonen
  • 75
  • 1
  • 1
  • 5
  • "I doesn't work" without providing any code about what you tried is useless. We cannot help you if you don't help us understanding the problem. Also keep in mind that we can help you find out what you're doing wrong not do it for you. – YounesM Jan 29 '18 at 09:20
  • 1
    OK, thanks for. The quick response I'll post the code when I'll be home – Arad Gonen Jan 29 '18 at 09:30
  • how to fetch data from mongodb and display it in chartjs? – liza Sep 25 '18 at 11:51
  • are you sure into your canvas it's `{{charts}}` and not `{{chart}}` – Pipo Feb 28 '19 at 20:19

2 Answers2

6

In your

canvas ... add a #yourId

(example : canvas *ngFor="let chart of charts; let i = index" id="canvas{{i}} #yourId")

Then you can use @ViewChildren('yourId') myCharts: any; (you can't use myCharts in ngOnInit, only in ngAfterViewInit and after) which will give you your array of charts.

I won't provide much more detail but you can use what's inside your myCharts (use a console.log(myCharts) to see in detail what's in there), you can use this to change data and so on.

Hope this helps.

3

Here is one of the possible implementations of the previously proposed solution. I created an array called "charts", which will contain as many elements as charts I want to create. Each element of this array has an identifier and the key where we will place the chart later (AfterViewInit).

HTML:

<div>
  <canvas *ngFor="let chart of charts; let i = index" id="mychart{{i}}" #mycharts>{{chart.chart}}</canvas>
</div>

.TS:

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

 // ...

 @ViewChildren('mycharts') allMyCanvas: any;  // Observe #mycharts elements
 charts: any;    // Array to store all my charts

 constructor() {
   this.charts = [
    {
      "id": "1",   // Just an identifier
      "chart": []            // The chart itself is going to be saved here
    },
    {
      "id": "2",
      "chart": []
    },
    {
      "id": "3",
      "chart": []
    }
  ]
 }

 ngAfterViewInit() {
   let canvasCharts = this.allMyCanvas._results;  // Get array with all canvas
   canvasCharts.map((myCanvas, i) => {   // For each canvas, save the chart on the charts array 
      this.charts[i].chart = new Chart(myCanvas.nativeElement.getContext('2d'), {
        // ...
      }
   })
 }
Leonardo Kuffo
  • 901
  • 9
  • 10