Angular 15实现表格每行复选框值获取与选中项数组维护
Angular 15 表格复选框实现与选中状态管理方案
需求说明
- 在Angular 15项目中,为表格每行添加复选框,表格数据通过HTTP Get请求获取
- 根据复选框选中/取消事件,将对应数据的
paymentFor值添加至指定数组或从数组中移除
示例数据
[ {paymentFor: 'P29', paymentPurpose: 'Advance payment', paymentAmount: 1000000, paymentType: 'Payment Schedule', isActiveTrigger: ''}, {paymentFor: 'P30', paymentPurpose: 'Advance payment', paymentAmount: 2000000, paymentType: 'Payment Schedule', isActiveTrigger: ''}, {paymentFor: 'P31', paymentPurpose: 'Head room', paymentAmount: 310000, paymentType: 'Payment Schedule', isActiveTrigger: ''}, {paymentFor: 'U10', paymentPurpose: 'Mosquoto Mesh', paymentAmount: 60000, paymentType: 'Additional Quotation', isActiveTrigger: ''}, {paymentFor: 'U9', paymentPurpose: 'Double door entrance', paymentAmount: 25000, paymentType: 'Additional Quotation', isActiveTrigger: ''} ]
现有代码
Service 代码
import { Injectable } from '@angular/core'; import { HttpClient, HttpErrorResponse } from '@angular/common/http'; import { Subject, Observable, tap } from 'rxjs'; import { environment } from 'src/environments/environment.development'; @Injectable({ providedIn: 'root' }) export class PaymentTriggerService { constructor(private httpClient: HttpClient) { } private _refreshNeeded$ = new Subject<void>(); get refreshNeeded$(){ return this._refreshNeeded$; } GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger(companyID: number, quoteHeaderID: number): Observable<any> { let apiURL = `${environment.netapiurl}PaymentTriggers/GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger/${companyID}/${quoteHeaderID}`; return this.httpClient.get<any>(apiURL) .pipe( tap(() => { this._refreshNeeded$.next(); }) ); } }
HTML 代码
<div class="row mt-4"> <div class="col-lg-12"> <div class="form-group"> <label *ngFor="let data of arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger" class="form-control"> <input type="checkbox" name="data" [(ngModel)]="data.paymentFor" value]="data.paymentFor" (selectionchange)="getValues(data.paymentFor)" > {{data.paymentFor}} </label> </div> </div> </div>
Component 代码
export class DataEntryComponent implements OnInit{ arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger: any = []; arrAppendAllPaymentForIDs: string[] = []; constructor(private paymentTriggerSvc: PaymentTriggerService) {} getValues(paymentFor: string){ this.arrAppendAllPaymentForIDs.push(paymentFor); console.warn(this.arrAppendAllPaymentForIDs); } ngOnInit(): void { this.paymentTriggerSvc.GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger(this.companyID, this.editQuotationQuoteHeaderID) .subscribe((response: any) => { this.arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger = response; console.log(this.arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger); }); } }
问题分析与优化方案
1. 现有代码核心问题
- 复选框绑定错误:将
ngModel绑定到字符串类型的paymentFor,无法正确维护选中状态 - 事件绑定错误:使用非标准的
selectionchange事件,复选框应使用change事件 - 逻辑缺失:仅处理选中添加操作,未实现取消选中时的移除逻辑
- 类型不安全:Service返回类型定义错误,Component数组未指定类型
- 内存泄漏风险:HTTP请求未取消,组件销毁后可能残留订阅
2. 完整优化实现
步骤1:定义数据接口增强类型安全
创建payment-item.interface.ts文件:
export interface PaymentItem { paymentFor: string; paymentPurpose: string; paymentAmount: number; paymentType: string; isActiveTrigger: string; isChecked?: boolean; // 新增属性存储复选框选中状态 }
步骤2:修正Service返回类型
// 修改Service中的方法返回类型 GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger(companyID: number, quoteHeaderID: number): Observable<PaymentItem[]> { let apiURL = `${environment.netapiurl}PaymentTriggers/GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger/${companyID}/${quoteHeaderID}`; return this.httpClient.get<PaymentItem[]>(apiURL) .pipe( tap(() => this._refreshNeeded$.next()) ); }
步骤3:优化Component逻辑
import { OnInit, OnDestroy } from '@angular/core'; import { Subscription } from 'rxjs'; import { PaymentItem } from './payment-item.interface'; export class DataEntryComponent implements OnInit, OnDestroy{ arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger: PaymentItem[] = []; arrAppendAllPaymentForIDs: string[] = []; private dataSubscription?: Subscription; constructor(private paymentTriggerSvc: PaymentTriggerService) {} // 处理复选框选中/取消事件 onCheckboxChange(item: PaymentItem) { if (item.isChecked) { // 避免重复添加 if (!this.arrAppendAllPaymentForIDs.includes(item.paymentFor)) { this.arrAppendAllPaymentForIDs.push(item.paymentFor); } } else { // 取消选中时移除对应值 const index = this.arrAppendAllPaymentForIDs.indexOf(item.paymentFor); if (index > -1) { this.arrAppendAllPaymentForIDs.splice(index, 1); } } } ngOnInit(): void { this.dataSubscription = this.paymentTriggerSvc.GetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger(this.companyID, this.editQuotationQuoteHeaderID) .subscribe((response: PaymentItem[]) => { // 初始化每个数据项的选中状态 this.arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger = response.map(item => ({ ...item, isChecked: false })); }); } // 组件销毁时取消订阅,避免内存泄漏 ngOnDestroy(): void { this.dataSubscription?.unsubscribe(); } }
步骤4:修正HTML表格模板
<div class="row mt-4"> <div class="col-lg-12"> <div class="form-group"> <table class="table table-striped"> <thead> <tr> <th>选择</th> <th>Payment For</th> <th>Purpose</th> <th>Amount</th> <th>Type</th> </tr> </thead> <tbody> <tr *ngFor="let data of arrGetPaymentSchAndUpgByQuoteHeaderIDForPaymentTrigger"> <td> <input type="checkbox" [(ngModel)]="data.isChecked" (change)="onCheckboxChange(data)"> </td> <td>{{data.paymentFor}}</td> <td>{{data.paymentPurpose}}</td> <td>{{data.paymentAmount}}</td> <td>{{data.paymentType}}</td> </tr> </tbody> </table> </div> </div> </div>
3. 额外优化建议
- 使用Reactive Forms替代
ngModel:适合大型项目,更便于表单验证和状态管理 - 添加加载状态与错误处理:请求时显示加载动画,捕获并处理HTTP错误
- 使用Set存储选中ID:避免重复值,比数组的
includes和splice操作更高效 - 增加全选/取消全选按钮:提升批量操作效率
内容的提问来源于stack exchange,提问作者user17782650
相关产品推荐
相关产品推荐

