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

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管道自动管理订阅,无需手动取消订阅:

  1. 在服务中替换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
    });
  }
}
  1. 表格组件中直接使用Observable:
export class PixTableComponent implements IPix {
  pixRecords$ = this.pixSearchService.pix$;

  constructor(private pixSearchService: PixSearchService) {}

  // ...其他代码
}
  1. 模板中使用async管道:
<!-- 示例表格循环 -->
<tr *ngFor="let record of pixRecords$ | async">
  <!-- 表格列渲染 -->
</tr>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 03:12:03