You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中如何在所有数据就绪后加载渲染NG2Charts图表

问题原因

图表显示空白的核心原因有两点:

  • 组件初始化阶段,doughnutChartData的datasets.data读取的是三个未赋值的变量,值为undefined,图表会直接用这份空数据源完成首次渲染。
  • 异步请求返回后,仅修改了三个独立的数值变量,既没有更新图表绑定的doughnutChartData数据源,也没有触发图表重绘,图表无法自动感知到外部变量的变化。

此外代码中存在两处会导致运行报错的笔误:

  • ngOnInit生命周期中调用的方法名为getEmpleados(),和实际定义的getEmployee()不匹配
  • 请求回调内使用了未定义的变量empleados,和入参名employees不一致

解决方案

以下两种方案任选其一即可,推荐优先使用第一种,逻辑更简单不易出错。

方案1:控制渲染时机,数据加载完成前不初始化图表

通过加载标记控制canvas元素的渲染,等所有异步数据准备完成后,再初始化图表,从根源避免空值渲染:

  1. 在组件类中新增布尔类型的加载标记,初始值为false
  2. 初始化图表配置时,datasets.data先设为空数组
  3. 异步请求拿到数据后,先更新图表配置里的数据源,再把加载标记设为true
  4. 模板中给canvas元素添加*ngIf判断,只有加载标记为true时才渲染图表元素

修正后的组件代码(detail.component.ts)

import { Component, OnInit, ViewChild } from '@angular/core';
import { ChartData, ChartType } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';
// 这里记得补全你自己的employee服务引入

@Component({
  selector: 'app-detail',
  templateUrl: './detail.component.html'
})
export class DetailComponent implements OnInit {
  empHoursLearning!: number;
  empHProject1!: number;
  empHProject2!: number;
  // 新增加载标记
  isDataLoaded = false;

  public doughnutChartLabels: string[] = [
    'Hours learning',
    'Hours Project 1',
    'Hours Project 2'
  ];
  public doughnutChartData: ChartData<'doughnut'> = {
    labels: this.doughnutChartLabels,
    datasets: [
      {
        // 初始化为空数组
        data: [],
        backgroundColor: ['#7DFF93', '#36A2EB', '#FFCE56'],
        hoverBackgroundColor: '#E6E6E6',
        hoverBorderColor: '#E6E6E6',
      },
    ],
  };
  public doughnutChartType: ChartType = 'doughnut';

  @ViewChild(BaseChartDirective) chart?: BaseChartDirective;

  ngOnInit(): void {
    // 修正方法名笔误
    this.getEmployee();   
  }

  async getEmployee() {
    const employees = await this._employeeService.getEmployee();
    this.empHoursLearning = employees!['hl'];
    this.empHProject1 = employees!['p1'];
    // 修正变量名笔误
    this.empHProject2 = employees!['p2'];

    // 更新图表绑定的数据源
    this.doughnutChartData.datasets[0].data = [
      this.empHoursLearning,
      this.empHProject1,
      this.empHProject2
    ];
    // 标记数据加载完成,触发图表渲染
    this.isDataLoaded = true;
  }
}

修正后的模板代码(detail.component.html)

只需要给canvas标签添加*ngIf判断即可:

<div class="container mt-4">
  <div class="card">
    <div class="card-body">
      <div class="container d-flex">
        <span class="h3">Employee detail</span>
      </div>
      <div>
        <div>
          <div style="display: block">
            <canvas baseChart
              *ngIf="isDataLoaded"
              [data]="doughnutChartData"
              [type]="doughnutChartType">
            </canvas>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

方案2:保留图表初始渲染,数据返回后手动触发更新

如果需要先显示图表占位,可以在数据返回后,手动调用图表实例的update()方法触发重绘:

  1. 同样需要先更新doughnutChartData.datasets[0].data的实际值,注意不能只修改三个独立变量,因为初始化时变量值已经被传入数组,后续单独修改变量不会同步更新数组内容
  2. 调用@ViewChild获取到的图表实例的update()方法强制刷新

对应修改getEmployee方法即可:

async getEmployee() {
  const employees = await this._employeeService.getEmployee();
  this.empHoursLearning = employees!['hl'];
  this.empHProject1 = employees!['p1'];
  this.empHProject2 = employees!['p2'];

  // 更新图表数据源
  this.doughnutChartData.datasets[0].data = [
    this.empHoursLearning,
    this.empHProject1,
    this.empHProject2
  ];
  // 手动触发图表重绘
  this.chart?.update();
}

内容的提问来源于stack exchange,提问作者AhmedSHA256

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 19:09:21