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

Angular 14中Angular Material Table数据变更后无法刷新的求助

解决Angular Material Table增删改后不刷新的问题

问题根源

你当前自定义的TestTableDataSource中,connect()方法仅在初始化、分页切换、排序变化时推送数据。直接调用this.dataSource.data.pop()修改数组时,数据源并未发出新的数据流,表格无法感知数据变化——renderRows()只是强制重绘现有数据,无法触发数据源的更新逻辑,因此无效。

解决方案

方案一:改造自定义DataSource,添加数据更新触发器

在自定义数据源中引入Subject监听数据变化,每次修改数据后主动通知数据流更新:

  1. 修改test-table-datasource.ts:
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { map } from 'rxjs/operators';
import { Observable, of as observableOf, merge, Subject } from 'rxjs';
import { DataSource } from '@angular/cdk/table'; // 注意补充导入DataSource

export interface TestTableItem {
  name: string;
  id: number;
}

const EXAMPLE_DATA: TestTableItem[] = [
  {id: 1, name: 'Hydrogen'},
  {id: 2, name: 'Helium'},
  {id: 3, name: 'Lithium'},
  {id: 4, name: 'Beryllium'},
  {id: 5, name: 'Boron'},
  {id: 6, name: 'Carbon'},
  {id: 7, name: 'Nitrogen'},
  {id: 8, name: 'Oxygen'},
  {id: 9, name: 'Fluorine'},
  {id: 10, name: 'Neon'},
  {id: 11, name: 'Sodium'},
  {id: 12, name: 'Magnesium'},
  {id: 13, name: 'Aluminum'},
  {id: 14, name: 'Silicon'},
  {id: 15, name: 'Phosphorus'},
  {id: 16, name: 'Sulfur'},
  {id: 17, name: 'Chlorine'},
  {id: 18, name: 'Argon'},
  {id: 19, name: 'Potassium'},
  {id: 20, name: 'Calcium'},
];

export class TestTableDataSource extends DataSource<TestTableItem> {
  data: TestTableItem[] = EXAMPLE_DATA;
  paginator: MatPaginator | undefined;
  sort: MatSort | undefined;
  private dataUpdated = new Subject<void>(); // 新增数据更新触发器

  constructor() {
    super();
  }

  connect(): Observable<TestTableItem[]> {
    if (this.paginator && this.sort) {
      // 将dataUpdated合并到数据流中,触发数据更新
      return merge(observableOf(this.data), this.paginator.page, this.sort.sortChange, this.dataUpdated)
        .pipe(map(() => {
          return this.getPagedData(this.getSortedData([...this.data]));
        }));
    } else {
      throw Error('Please set the paginator and sort on the data source before connecting.');
    }
  }

  // 新增方法:修改数据后调用此方法触发更新
  refreshData() {
    this.dataUpdated.next();
  }

  disconnect(): void {
    this.dataUpdated.complete(); // 组件销毁时清理资源
  }

  private getPagedData(data: TestTableItem[]): TestTableItem[] {
    if (this.paginator) {
      const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
      return data.slice(startIndex, startIndex + this.paginator.pageSize); // 注意用slice代替splice,避免修改原数组
    } else {
      return data;
    }
  }

  private getSortedData(data: TestTableItem[]): TestTableItem[] {
    if (!this.sort || !this.sort.active || this.sort.direction === '') {
      return data;
    }

    return data.sort((a, b) => {
      const isAsc = this.sort?.direction === 'asc';
      switch (this.sort?.active) {
        case 'name': return compare(a.name, b.name, isAsc);
        case 'id': return compare(+a.id, +b.id, isAsc);
        default: return 0;
      }
    });
  }
}

function compare(a: string | number, b: string | number, isAsc: boolean): number {
  return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
}
  1. 修改组件中的removeData方法:
removeData(){
  console.log(this.dataSource.data.length);
  this.dataSource.data.pop();
  console.log(this.dataSource.data.length);
  this.dataSource.refreshData(); // 触发数据源更新
  // 同步分页器长度
  if(this.paginator){
    this.paginator.length = this.dataSource.data.length;
  }
}

方案二:改用MatTableDataSource(更简便)

如果不需要自定义复杂的数据源逻辑,直接使用Angular Material提供的MatTableDataSource,它内置了数据变化监听:

  1. 修改test-table-component.ts:
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTable, MatTableDataSource } from '@angular/material/table';
import { TestTableItem } from './test-table-datasource';
import { AfterViewInit, Component, ViewChild } from '@angular/core'; // 补充导入必要装饰器

@Component({
  selector: 'app-test-table',
  templateUrl: './test-table.component.html',
  styleUrls: ['./test-table.component.css']
})
export class TestTableComponent implements AfterViewInit {
  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;
  @ViewChild(MatTable) table!: MatTable<TestTableItem>;
  dataSource: MatTableDataSource<TestTableItem>;

  displayedColumns = ['id', 'name'];

  constructor() {
    const EXAMPLE_DATA: TestTableItem[] = [
      {id: 1, name: 'Hydrogen'},
      {id: 2, name: 'Helium'},
      {id: 3, name: 'Lithium'},
      {id: 4, name: 'Beryllium'},
      {id: 5, name: 'Boron'},
      {id: 6, name: 'Carbon'},
      {id: 7, name: 'Nitrogen'},
      {id: 8, name: 'Oxygen'},
      {id: 9, name: 'Fluorine'},
      {id: 10, name: 'Neon'},
      {id: 11, name: 'Sodium'},
      {id: 12, name: 'Magnesium'},
      {id: 13, name: 'Aluminum'},
      {id: 14, name: 'Silicon'},
      {id: 15, name: 'Phosphorus'},
      {id: 16, name: 'Sulfur'},
      {id: 17, name: 'Chlorine'},
      {id: 18, name: 'Argon'},
      {id: 19, name: 'Potassium'},
      {id: 20, name: 'Calcium'},
    ];
    this.dataSource = new MatTableDataSource(EXAMPLE_DATA);
  }

  ngAfterViewInit(): void {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
  }
  
  removeData(){
    console.log(this.dataSource.data.length);
    this.dataSource.data.pop();
    console.log(this.dataSource.data.length);
    // 通过重新赋值数组触发变更检测
    this.dataSource.data = [...this.dataSource.data];
    // 同步分页器长度
    if(this.paginator){
      this.paginator.length = this.dataSource.data.length;
    }
  }
}

关键注意点

  • 自定义DataSource必须通过可观察对象推送新数据,表格才会响应变化;
  • 使用MatTableDataSource时,避免直接修改数组(如pop/push),需通过重新赋值数组触发变更检测;
  • 分页器的length需手动同步,否则数据变化后分页器不会自动更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 03:54:10