0

I'm starting to learn how to build Angular apps and I need to implement a toggle button that show/hide 2 charts, one chart has static data and the other on call data from a db.json file through a service an interface previously configurated.

I achieve to show both Charts.js without the toggle button, but when I add the event handling and the *ngIf directive to the section tag, it just show the first chart with the static data and a empty container with no chart.

These are my component.ts and .html files:

api-plot.component.ts:

import { AfterViewInit, Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ApiPlotService } from '../api-plot.service'; import { BaseChartDirective } from 'ng2-charts'; import { ChartOptions, ChartConfiguration, Chart, registerables } from 'chart.js'; import { ApiPlot } from '../api-plot'; Chart.register(...registerables) @Component({ standalone: true, selector: 'app-api-plot', imports: [BaseChartDirective, CommonModule], templateUrl: './api-plot.component.html', styleUrl: './api-plot.component.css' }) export class ApiPlotComponent { showChart = false; toggleChart() { this.showChart = !this.showChart; // this.loadChartData; // this.renderChart; } chartData: ApiPlot[] = []; labelData: string[] = []; realData: number[] = []; stationData: string[] = []; public testChartData: ChartConfiguration<'line'>['data'] = { labels: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July' ], datasets: [ { data: [ 65, 59, 80, 81, 56, 55, 40 ], label: 'Series A', fill: true, tension: 0.5, borderColor: 'black', backgroundColor: 'rgba(255,0,0,0.3)' } ] }; public testChartOptions: ChartOptions<'line'> = { responsive: true }; public testChartLegend = true; constructor( private service: ApiPlotService ) { } loadChartData() { this.service.loadTimeSeriesData().subscribe( item => { this.chartData = item; if (this.chartData != null) { this.chartData.map( o => { this.labelData.push(o.timestamp); this.realData.push(o.value); this.stationData.push(o.station_code); }); this.renderChart(this.labelData, this.realData, this.stationData); } }); } renderChart( labelData: any, valueData: number[], stationData: any ) { const myChart = new Chart('lineChart', { type: 'line', data: { labels: labelData, datasets: [ { label: 'Water Height in ml', data: valueData, } ] }, options: { } }); } // ngAfterViewInit(): void { // this.loadChartData; // } // ngOnInit(): void { // this.loadChartData(); // } } 

api-plot.component.html:

<div class="api-call-container"> <div> <h3 class="api-call-title">Graficar una collección de serie de tiempo:</h3> </div> <div class="api-buttons-container"> <button class="plot-button" (click)="toggleChart()">{{ showChart ? 'Hide Chart' : 'Show Chart' }}</button> <button class="clean-button">Limpiar Gráfico</button> </div> </div> <section class="plot-results" *ngIf="showChart"> <div class="div-test-results"> <h2 class="test-plot-title">Line Chart from static data</h2> <canvas baseChart class="test-plot" [type]="'line'" [data]="testChartData" [options]="testChartOptions" [legend]="testChartLegend"> </canvas> </div> <div class="div-line-results"> <h2 class="plot-title">Line Chart from db.json data (uses inerface and service)</h2> <canvas baseChart id="lineChart"></canvas> </div> </section> 

api-plot.service.ts:

import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ApiPlot } from './api-plot'; import { ApiPlotComponent } from './api-plot/api-plot.component'; @Injectable({ providedIn: 'root' }) export class ApiPlotService { constructor( private http: HttpClient ) { } // call to the api to plot the data within db.json loadTimeSeriesData() { return this.http.get<ApiPlot[]> ( "http://localhost:3000/water_heigth" ) } } 

And this is the final result without the *ngIf in the section tag:

Final result with the w charts js

I tried to add some conditional to execute the function that load the data and render the Chart.js when the toggle variable change to true but without succces.

Also tried to apply ngAfterViewInit() to my component, but without succes.

If you need more info please let me know. Thanks in advance.

New contributor
Gastón Rayo is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1
  • Hi, done, I added my app service with the function, which read the data stored in the db.json file.Commentedyesterday

1 Answer 1

1

Because when loadChartData is executed immediately without waiting for the DOM:

<canvas id="lineChart"></canvas> 

is rendered completely.

Approach 1: Use setTimeout to delay the execution

toggleChart() { this.showChart = !this.showChart; if (this.showChart) setTimeout(() => { this.loadChartData(); }); } 

Approach 2: Use AfterViewChecked lifecycle

Execute the loadChartData function once the change detector completes checking for the component view's changes.

ngAfterViewChecked() { this.showChart && this.loadChartData(); } 

Demo @ StackBlitz

1
  • 1
    Thanks!! It worked perfectly adding both approaches.Commentedyesterday

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.