Angular MatTable执行PUT操作后不更新问题求助
问题:Angular MatTable执行PUT操作后表格未自动更新
我开发了一个可复用的父表格组件,只需传入数据源就能用。使用该表格的组件得注入提供Observable的服务,实现Get、Put、Post、Delete等HTTP方法,本来期望这些操作完成后能自动同步到MatTable里。表格初始加载没问题,但执行PUT操作后,后端返回200和更新后的对象,表格却没同步更新。
父表格组件(简化代码)
export class TableComponent { public tableDataSource = new MatTableDataSource(); public displayedColumns: string[] = []; @ViewChild(MatPaginator, { static: false }) matPaginator?: MatPaginator; @ViewChild(MatSort, { static: true }) matSort?: MatSort; @Input() set tableData(data: MatTableDataSource<any>) { this.setTableDataSource(data); } constructor() { console.log("Hello") } setTableDataSource(data: MatTableDataSource<any>) { this.tableDataSource = data; if (this.matPaginator) { this.tableDataSource.paginator = this.matPaginator; } if (this.matSort) { this.tableDataSource.sort = this.matSort; } } }
子组件模板(使用表格)
<app-data-table [isFilterable]="true" [isSortable]="true" [isPageable]="true" [tableColumns]="customerColumns" [tableData]="customers" [rowActionIcon]="'more_vert'" [menuActions]="this.menuActions" (rowAction)="onTableAction($event)" (sort)="sortData($event)" > </app-data-table>
子组件代码
export class CustomersComponent { customers; selectedCustomer: Customer | null; menuActions: MenuItemDefinition[]; customerColumns: { name: string; dataKey: string; isSortable: boolean }[]; constructor(private cust_api: CustomerApiService) { this.customers = new MatTableDataSource<Customer>([]); } ngOnInit(): void { /** 发起GET请求并将返回的Observable绑定到MatTableDataSource */ this.cust_api.getCustomers().subscribe((customers) => { this.customers.data = customers; }); } updateCustomer(customer: Customer): void { this.cust_api.updateCustomer(customer as Customer) .subscribe((updated_customer: Customer) => (customer = updated_customer)); } }
目前上面的updateCustomer方法没法更新表格,手动修改this.customers.data数组能实现更新(如下代码),但这种方式不够优雅,想知道正确的实现方式,能不能用async管道?
updateCustomer(customer: Customer): void { this.cust_api .updateCustomer(customer as Customer) .subscribe((updated_customer: Customer) => { const to_keep = this.customers.data.filter( (customer) => customer.id !== updated_customer.id ); this.customers.data = [updated_customer, ...to_keep]; }); }
解决方案
1. 用Async管道优化数据流(推荐)
用Async管道替代手动订阅,Angular会自动管理订阅,数据更新时自动触发视图刷新,代码更简洁也更符合Angular的最佳实践。
修改子组件代码
把customers改成Observable类型,不再手动创建MatTableDataSource:
export class CustomersComponent { customers$: Observable<Customer[]>; // 改为Observable数组 selectedCustomer: Customer | null; menuActions: MenuItemDefinition[]; customerColumns: { name: string; dataKey: string; isSortable: boolean }[]; constructor(private cust_api: CustomerApiService) {} ngOnInit(): void { // 直接赋值Observable,不用手动订阅 this.customers$ = this.cust_api.getCustomers(); } updateCustomer(customer: Customer): void { this.cust_api.updateCustomer(customer) .pipe( // 更新后重新获取完整列表,保证数据和后端完全一致 switchMap(() => this.cust_api.getCustomers()) ) .subscribe(updatedList => { this.customers$ = of(updatedList); // 更新Observable触发视图刷新 }); } }
修改父组件Input逻辑
让父组件接收Observable,自动转换为MatTableDataSource:
export class TableComponent { public tableDataSource = new MatTableDataSource(); public displayedColumns: string[] = []; @ViewChild(MatPaginator, { static: false }) matPaginator?: MatPaginator; @ViewChild(MatSort, { static: true }) matSort?: MatSort; @Input() set tableData(data$: Observable<any[]>) { data$.subscribe(data => { this.tableDataSource.data = data; this.setTableDataSource(this.tableDataSource); }); } setTableDataSource(data: MatTableDataSource<any>) { this.tableDataSource = data; if (this.matPaginator) { this.tableDataSource.paginator = this.matPaginator; } if (this.matSort) { this.tableDataSource.sort = this.matSort; } } }
修改子组件模板
用Async管道绑定数据:
<app-data-table [isFilterable]="true" [isSortable]="true" [isPageable]="true" [tableColumns]="customerColumns" [tableData]="customers$ | async" [rowActionIcon]="'more_vert'" [menuActions]="menuActions" (rowAction)="onTableAction($event)" (sort)="sortData($event)" > </app-data-table>
2. 优化现有手动更新方式(不换Async管道)
如果不想重构代码,可以优化现有逻辑,要么替换数组引用,要么手动通知数据源更新:
方式一:替换数组引用(推荐)
updateCustomer(customer: Customer): void { this.cust_api.updateCustomer(customer) .subscribe((updated_customer: Customer) => { // 用map替换对应元素,生成新数组赋值 this.customers.data = this.customers.data.map(c => c.id === updated_customer.id ? updated_customer : c ); }); }
方式二:手动触发数据源更新(依赖私有属性,不推荐)
updateCustomer(customer: Customer): void { this.cust_api.updateCustomer(customer) .subscribe((updated_customer: Customer) => { const index = this.customers.data.findIndex(c => c.id === updated_customer.id); if (index !== -1) { this.customers.data[index] = updated_customer; // 手动调用私有属性的next方法通知更新 this.customers._data.next(this.customers.data); } }); }
内容的提问来源于stack exchange,提问作者enrm
相关产品推荐
相关产品推荐

