Angular组件中ng-repeat渲染Chart.js环形图重叠问题求助
Hey there, let's break down why your two doughnut charts are merging into one, and fix it step by step!
The Root Cause
The main issue here is how you're selecting the canvas element for Chart.js:
new Chart(document.getElementsByClassName("doughnut-chart"), { ... })
document.getElementsByClassName grabs all elements with that class across the entire page. When your ng-repeat renders multiple instances of your appSeveritiesComponent, the second component's chart initialization will target every matching canvas (including the first one) and overwrite it with its own data. That's why you end up with one chart showing combined (actually, overwritten) data.
Step-by-Step Fix
1. Use Component-Specific DOM Selection
Instead of querying the entire document, use Angular's $element service to only target the canvas inside the current component instance. First, inject $element into your controller.
2. Clean Up Chart Configuration
You also have a duplicate labels property in your Chart config (you first set it to Object.keys(that.severities), then overwrite it with { display: false }). The legend visibility belongs in the options section, not the data section.
Modified Controller Code
'use strict'; const appModule = angular.module('appModule'); appModule.component('appSeveritiesComponent', { templateUrl: '/app/components/severitiesComponent/severitiesComponent.html', controller: severitiesComponentController, bindings: { severities: '<' } }); // Inject $element to access the component's DOM severitiesComponentController.$inject = ["$timeout", "$element"]; function severitiesComponentController($timeout, $element) { var that = this; that.keys = function() { return Object.keys(that.severities); } $timeout(that.keys, 0); that.initChart = function() { // Get ONLY the canvas inside THIS component instance const canvas = $element.find('.doughnut-chart')[0]; if (!canvas) return; // Exit if canvas isn't found // Prepare chart data that.arr = []; for (var key in that.severities) { that.arr.push(that.severities[key]); } new Chart(canvas, { type: 'doughnut', animationEnabled: true, responsive: true, data: { labels: Object.keys(that.severities), datasets: [{ backgroundColor: ["rgb(213, 65, 65)", "rgb(243, 171, 16)", "rgb(65, 176, 213)"], data: that.arr }] }, options: { plugins: { legend: { display: false // Correct place to hide the legend } } } }); } $timeout(that.initChart, 0); // Optional: Update chart when severities data changes that.$onChanges = function(changes) { if (changes.severities && changes.severities.currentValue) { $timeout(that.initChart, 0); } } }
Key Improvements
- Component-Specific Selection:
$element.find('.doughnut-chart')ensures each component only interacts with its own canvas, preventing overlaps. - Fixed Chart Config: Moved the legend visibility setting to
options.plugins.legendwhere it belongs, removing the duplicatelabelsproperty. - Optional Data Update Handling: The
$onChangeshook ensures your chart updates if theseveritiesdata passed from the parent changes (useful for async data loads).
With these changes, each component instance will render its own independent doughnut chart, no more overlapping or merged data!
内容的提问来源于stack exchange,提问作者Tom Cohen

