Angular 2表格组件无法感知共享服务数组变更的技术求助
问题解决方案
核心问题分析
- 服务中
retrievePixData错误地将异步请求返回的Observable直接赋值给pixData,未等待请求完成就触发事件,导致传递的不是实际数据 - 表格组件在元数据中声明了
providers: [PixSearchService],会创建独立的服务实例,与触发请求的组件使用的不是同一个单例,因此无法接收到数据更新事件
修复步骤
1. 修正PixSearchService的异步请求逻辑
修改retrievePixData方法,正确处理HTTP请求的异步响应:
import { HttpClient, HttpErrorResponse, HttpHeaders, } from '@angular/common/http'; import { EventEmitter, Injectable } from '@angular/core'; import { catchError, map, tap, throwError } from 'rxjs'; import { IPix } from './model/IPix'; @Injectable({ providedIn: 'root', }) export class PixSearchService { constructor(private http: HttpClient) {} pixUpdated: EventEmitter<IPix[]> = new EventEmitter(); errorMessage: string = ''; pixData!: IPix[]; pixUrl: string = 'https://example.ckp-dev.example.com/example'; setPixData(pixData: IPix[]) { this.pixData = pixData; this.pixUpdated.emit(this.pixData); } getPixData() { return this.pixData; } retrievePixData(): void { const headers = new HttpHeaders({ 'x-api-key': 'ewogICAgImFwaUtleSIgOiAiMTIzIiwKICAgICJ1c2VySWQiID3649807253098ESSBEZXZlbG9wZXIiCn0=', }); this.http .get<any>(this.pixUrl, { headers }) .pipe( tap((data) => console.log('All:', JSON.stringify(data))), map((data: any) => data.results), catchError(this.handleError) ) .subscribe({ next: (pixData) => this.setPixData(pixData), error: (err) => this.errorMessage = err }); } handleError(err: HttpErrorResponse) { let errorMessage = ''; if (err.error instanceof ErrorEvent) { errorMessage = `An error occurred: ${err.error.message}`; } else { errorMessage = `Server returned code:: ${err.status}, error message is: ${err.message}`; } console.error(errorMessage); return throwError(() => errorMessage); } }
2. 修正PixTableComponent的服务实例问题
移除组件元数据中的providers配置,确保使用根注入的单例服务:
import { Component, OnDestroy, OnInit, } from '@angular/core'; import type { TableSize } from '@dauntless/ui-kds-angular/table'; import type { TableStickyType } from '@dauntless/ui-kds-angular/table'; import type { TableScrollType } from '@dauntless/ui-kds-angular/table'; import { CardElevation } from '@dauntless/ui-kds-angular/types'; import { PixSearchService } from '../pix-search.service'; import { Subscription } from 'rxjs'; import { IPix } from '../model/IPix'; import { IContract } from '../model/IContract'; import { IAudit } from '../model/IAudit'; import { ICapitation } from '../model/ICapitation'; import { IChangeRequest } from '../model/IChangeRequest'; import { IHnetAudit } from '../model/IHnetAudit'; import { IProduct } from '../model/IProduct'; import { IProvider } from '../model/IProvider'; @Component({ selector: 'pix-table-component', templateUrl: 'pix-table.component.html', styleUrls: ['pix-table.component.css'] // 移除此行:providers: [PixSearchService] }) export class PixTableComponent implements IPix, OnDestroy { private pixSubscription!: Subscription; constructor(private pixSearchService: PixSearchService) { this.pixSubscription = this.pixSearchService.pixUpdated.subscribe((pix) => { this.pixRecords = pix; }); } ngOnDestroy(): void { this.pixSubscription.unsubscribe(); } columns = [ 'ID', 'Network', 'LOB', 'HP Code', 'Atypical', 'TIN', 'GNPI', 'Org', 'Business Unit Code', 'National Contract', 'National ContractType', 'Contract Type', 'Super Group', 'Contract ID', 'Amendment ID', 'Contract Effective Date', 'Contract Termination Date', ]; rows: any; tableSize: TableSize = 'small'; showHover = true; sticky: TableStickyType = 'horizontal'; scrollType: TableScrollType = 'both'; label = 'Payment Index Management'; disabled = 'disabled'; error = 'error'; maxlength = 'maxlength'; showCounter = false; elevation: CardElevation = 'medium'; legacyConfigTrackerId!: number; contract!: IContract; audit!: IAudit; capitation!: ICapitation; changeRequest!: IChangeRequest; claimType!: string; deleted!: string; hnetAudit!: IHnetAudit; id!: string; noPayClassReason!: string; payClass!: string; product!: IProduct; provider!: IProvider; rateEscalator!: string; status!: string; selected: boolean = false; pixRecords: IPix[] = []; errorMessage: string = ''; }
额外优化建议
可以改用BehaviorSubject替代EventEmitter,配合async管道自动管理订阅,无需手动取消订阅:
- 在服务中替换EventEmitter为BehaviorSubject:
import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class PixSearchService { private pixSubject = new BehaviorSubject<IPix[]>([]); pix$ = this.pixSubject.asObservable(); // ...其他代码 retrievePixData(): void { // ...请求逻辑 .subscribe({ next: (pixData) => this.pixSubject.next(pixData), error: (err) => this.errorMessage = err }); } }
- 表格组件中直接使用Observable:
export class PixTableComponent implements IPix { pixRecords$ = this.pixSearchService.pix$; constructor(private pixSearchService: PixSearchService) {} // ...其他代码 }
- 模板中使用async管道:
<!-- 示例表格循环 --> <tr *ngFor="let record of pixRecords$ | async"> <!-- 表格列渲染 --> </tr>
内容的提问来源于stack exchange,提问作者public_void_kee
相关产品推荐
相关产品推荐

