Angular服务订阅后如何全局赋值并渲染ngx-charts图表
问题:Angular中ngx-charts饼图无法更新数据
在Angular组件中,尝试通过服务获取数据后更新全局变量,进而渲染ngx-charts饼图,但饼图始终无法显示正确数据。具体情况:
- CandidateService的
getCuestionarioRespuestas方法返回Verdaderos类型的Observable数组 - 组件中定义了全局变量M、N、P并初始化为0,在
getRespuestasCandidato方法中订阅服务,计算得到countN2、countM2、countP2后赋值给全局变量,控制台能打印正确数值,但饼图的数据源single数组无法更新 - 已在
AfterViewInit生命周期钩子中调用getRespuestasCandidato方法,但问题依旧
服务代码
import { NumberInput } from '@angular/cdk/coercion'; import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { Candidato } from "../interfaces/candidato"; import { Cuestionario } from '../interfaces/cuestionario'; import { Respuesta } from '../interfaces/Respuesta'; import { Verdaderos } from '../interfaces/verdaderos'; @Injectable({ providedIn: 'root' }) export class CandidateService { url="http://localhost:3000/api" constructor(private http:HttpClient) { } getPersona(ID:Number):Observable<Candidato[]>{ return this.http.get<Candidato[]>(this.url + "/persona/searchrh/"+ID) } deletePersona(ID_RH:Number,ID:Number){ return this.http.delete<Respuesta>(this.url+"/persona/deleteRH/"+ID_RH+"/"+ID) } getCandidato(ID:Number):Observable<Candidato>{ return this.http.get<Candidato>(this.url + "/persona/search/"+ID) } getCuestionarioRespuestas(ID:Number):Observable<Verdaderos[]>{ return this.http.get<Verdaderos[]>(this.url + "/cuestionario/"+ID) } }
Verdaderos接口
export interface Verdaderos{ Pregunta: number; }
组件方法代码
getRespuestasCandidato(ID: Number) { this.Persona.getCuestionarioRespuestas(ID).subscribe((data:Verdaderos[]) =>{ this.conteo = data; this.numbers = this.conteo.map(x => x.ID_Pregunta); console.log(this.numbers) const N2 = this.N1.filter(x => this.numbers.includes(x)); const countN2 = N2.length; console.log(countN2) const M2 = this.M1.filter(x => this.numbers.includes(x)); const countM2 = M2.length; console.log(countM2) const P2 = this.P1.filter(x => this.numbers.includes(x)); const countP2 = P2.length; console.log(countM2) this.N = countN2; this.M = countM2; this.P = countP2 }) }
饼图数据代码
NE = 100 - this.N- this.M- this.P single = [ { "name": "Narcisismo", "value": this.N }, { "name": "Maquiavelismo", "value": this.M }, { "name": "Psicopatia", "value": this.P }, { "name": "No evaluado", "value": this.NE } ];
HTML模板
<div class="wrapperuser"> <div class="container-sm grafico"> <ngx-charts-pie-chart [view]="view" [results]="single" [gradient]="gradient" [legend]="showLegend" [labels]="showLabels" [doughnut]="isDoughnut"> </ngx-charts-pie-chart> </div> </div>
问题原因
single数组初始化时机错误:single数组是在组件类初始化时(构造函数执行前)定义的,此时N、M、P都是初始值0,后续即使这些变量更新,single数组不会自动重新计算。- 未触发变更检测:虽然更新了
N、M、P,但没有更新single数组的引用,Angular的变更检测机制无法感知到数据变化,因此饼图不会重新渲染。
解决方案
方案1:数据更新后重新生成single数组
修改getRespuestasCandidato方法,在赋值N、M、P后,重新计算并赋值single数组:
getRespuestasCandidato(ID: Number) { this.Persona.getCuestionarioRespuestas(ID).subscribe((data:Verdaderos[]) =>{ this.conteo = data; this.numbers = this.conteo.map(x => x.ID_Pregunta); console.log(this.numbers) const N2 = this.N1.filter(x => this.numbers.includes(x)); const countN2 = N2.length; console.log(countN2) const M2 = this.M1.filter(x => this.numbers.includes(x)); const countM2 = M2.length; console.log(countM2) const P2 = this.P1.filter(x => this.numbers.includes(x)); const countP2 = P2.length; console.log(countP2) // 修正原代码笔误:将countM2改为countP2 this.N = countN2; this.M = countM2; this.P = countP2; // 重新生成single数组 const NE = 100 - this.N - this.M - this.P; this.single = [ { name: "Narcisismo", value: this.N }, { name: "Maquiavelismo", value: this.M }, { name: "Psicopatia", value: this.P }, { name: "No evaluado", value: NE } ]; }) }
同时将组件中原来的NE和single改为类属性:
N = 0; M = 0; P = 0; single: any[] = [];
方案2:使用Getter动态计算single数组
将single定义为Getter属性,每次访问时自动根据最新的N、M、P计算:
N = 0; M = 0; P = 0; get single() { const NE = 100 - this.N - this.M - this.P; return [ { name: "Narcisismo", value: this.N }, { name: "Maquiavelismo", value: this.M }, { name: "Psicopatia", value: this.P }, { name: "No evaluado", value: NE } ]; }
此时无需提前初始化single数组,Angular会在每次渲染模板时调用Getter获取最新数据。
额外注意点
- 原代码中
console.log(countM2)是笔误,应改为console.log(countP2),需修正。 - 两种方案都能触发Angular变更检测,让饼图获取到最新数据,可根据实际场景选择。
内容的提问来源于stack exchange,提问作者Alex Ramos
相关产品推荐
相关产品推荐

