Angular 8与ng2-charts:图表标签及数据动态更新问题求助
Hey there! Let's get that ng2-charts doughnut chart updating correctly instead of adding new entries every time you modify a value. I've been there as an Angular newbie too, so let's break this down simply.
The Root Problem
Right now, you're using push() every time, whether you're adding a new label or updating an existing one. That's why modifying a value creates a new entry instead of updating the old one—you never check if the label already exists first!
Step-by-Step Solution
Here's a complete implementation that handles both adding new data and updating existing entries:
1. Component TypeScript Code
First, let's set up the component with proper data handling. We'll use the dataset structure (recommended for ng2-charts) and add a method that checks for existing labels before updating or adding data:
import { Component, ViewChild } from '@angular/core'; import { ChartConfiguration, ChartType } from 'chart.js'; import { DoughnutChartComponent } from 'ng2-charts'; @Component({ selector: 'app-doughnut-chart', templateUrl: './doughnut-chart.component.html', styleUrls: ['./doughnut-chart.component.css'] }) export class DoughnutChartComponent { // Ring chart configuration public doughnutChartType: ChartType = 'doughnut'; public doughnutChartData: ChartConfiguration['data'] = { labels: [], datasets: [ { data: [], backgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF'], hoverBackgroundColor: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF'] } ] }; // Get reference to the chart instance for manual updates (optional) @ViewChild(DoughnutChartComponent) doughnutChart?: DoughnutChartComponent; // User input bindings userLabel: string = ''; userValue: number = 0; handleChartUpdate() { // Basic validation to avoid empty or invalid inputs if (!this.userLabel.trim() || this.userValue <= 0) { alert('Please enter a valid label and positive number!'); return; } // Check if the label already exists in our labels array const labelIndex = this.doughnutChartData.labels?.indexOf(this.userLabel.trim()); if (labelIndex !== undefined && labelIndex !== -1) { // Label exists: update the corresponding value this.doughnutChartData.datasets[0].data[labelIndex] = this.userValue; } else { // Label doesn't exist: add new entry this.doughnutChartData.labels?.push(this.userLabel.trim()); this.doughnutChartData.datasets[0].data.push(this.userValue); } // Trigger Angular change detection to update the chart // We create a new object reference so Angular notices the change this.doughnutChartData = { ...this.doughnutChartData }; // Fallback: If the above doesn't work, manually update the chart // this.doughnutChart?.chart?.update(); } }
2. Corresponding HTML Template
Keep your existing structure, but bind the inputs to our component variables and wire up the button to the new method:
<div class="chart-controls"> <input type="text" [(ngModel)]="userLabel" placeholder="Enter label" class="label-input" > <input type="number" [(ngModel)]="userValue" placeholder="Enter value" min="1" class="value-input" > <button (click)="handleChartUpdate()" class="update-btn"> Add/Update Data </button> </div> <div class="chart-container"> <canvas baseChart [data]="doughnutChartData" [type]="doughnutChartType" ></canvas> </div>
Key Things to Note
- Check for Existing Labels: We use
indexOf()to find if the user's label is already in ourlabelsarray. If it is, we update the matching index in thedataarray instead of pushing a new entry. - Trigger Change Detection: Angular might not pick up changes if you only modify array elements (since the array reference stays the same). By reassigning
doughnutChartDatawith{ ...this.doughnutChartData }, we create a new object reference, which Angular detects and updates the chart. - Manual Update Fallback: If the change detection trick doesn't work (sometimes happens with older ng2-charts versions), use the
ViewChildreference to callchart.update()directly. - Input Validation: We added a simple check to prevent empty labels or non-positive values—you can expand this to fit your needs.
If You're Using the Old ng2-charts Structure
If your original code uses separate labels and data arrays instead of datasets, adjust the method like this:
// Replace the chart data variables with these public doughnutChartLabels: string[] = []; public doughnutChartData: number[] = []; // Update the handleChartUpdate method handleChartUpdate() { if (!this.userLabel.trim() || this.userValue <= 0) return; const labelIndex = this.doughnutChartLabels.indexOf(this.userLabel.trim()); if (labelIndex !== -1) { this.doughnutChartData[labelIndex] = this.userValue; } else { this.doughnutChartLabels.push(this.userLabel.trim()); this.doughnutChartData.push(this.userValue); } // Trigger update this.doughnutChartLabels = [...this.doughnutChartLabels]; this.doughnutChartData = [...this.doughnutChartData]; }
And update the HTML to use [labels] and [data]:
<canvas baseChart [labels]="doughnutChartLabels" [data]="doughnutChartData" [type]="doughnutChartType" ></canvas>
That should fix your issue—now modifying an existing label's value will update the chart instead of adding a new slice!
内容的提问来源于stack exchange,提问作者RocketMatt

