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

Angular 8中创建带分页字段的MatTable数据源遇TS2416错误如何解决?

解决MatTable数据源与后端分页集成的类型错误问题

问题根源

你遇到的TS2416错误核心在于**DataSource的泛型类型和connect方法返回值不匹配**:DataSource<T>要求connect返回Observable<T[]>(单条数据的数组),但你现在返回的是Observable<Samples>(包含数组和分页信息的对象),这就导致了类型冲突。

我们需要调整数据源的设计,既要满足MatTable对数据源的类型要求,又要保留分页所需的total、pageSize、pageIndex参数。

解决方案步骤

1. 重构SamplesDataSource

修改数据源的泛型为Sample,单独维护分页参数的Subject,确保connect返回正确的样本数组Observable:

import { DataSource, CollectionViewer } from '@angular/cdk/collections';
import { BehaviorSubject, Observable, of, catchError } from 'rxjs';
import { Sample, Samples, NO_SAMPLES } from '../models/sample.model';
import { SamplesService } from '../services/samples.service';

export class SamplesDataSource extends DataSource<Sample> {
  // 维护样本数组的Subject
  private samplesSubject = new BehaviorSubject<Sample[]>(NO_SAMPLES.samples);
  // 维护分页参数的Subject
  private totalSubject = new BehaviorSubject<number>(NO_SAMPLES.total);
  private pageSizeSubject = new BehaviorSubject<number>(NO_SAMPLES.pageSize);
  private pageIndexSubject = new BehaviorSubject<number>(NO_SAMPLES.pageIndex);

  // 暴露分页参数的Observable供组件使用
  public total$ = this.totalSubject.asObservable();
  public pageSize$ = this.pageSizeSubject.asObservable();
  public pageIndex$ = this.pageIndexSubject.asObservable();

  constructor(private samplesService: SamplesService) {
    super();
  }

  // 现在返回的是Sample[]的Observable,符合DataSource要求
  connect(collectionViewer: CollectionViewer): Observable<Sample[]> {
    return this.samplesSubject.asObservable();
  }

  disconnect(collectionViewer: CollectionViewer): void {
    this.samplesSubject.complete();
    this.totalSubject.complete();
    this.pageSizeSubject.complete();
    this.pageIndexSubject.complete();
  }

  getSamples() {
    this.samplesService.getSamples().pipe(
      catchError(err => {
        console.error('获取样本失败:', err);
        // 错误时返回空的Samples结构,而不是空数组
        return of(NO_SAMPLES);
      })
    ).subscribe((response: Samples) => {
      // 更新样本数组
      this.samplesSubject.next(response.samples);
      // 更新分页参数
      this.totalSubject.next(response.total);
      this.pageSizeSubject.next(response.pageSize);
      this.pageIndexSubject.next(response.pageIndex);
    });
  }

  // 可选:添加分页变更后的请求方法(比如页码、页大小变化时调用)
  getPaginatedSamples(pageIndex: number, pageSize: number) {
    this.samplesService.getSamples(pageIndex, pageSize).pipe(
      catchError(err => {
        console.error('分页获取样本失败:', err);
        return of(NO_SAMPLES);
      })
    ).subscribe((response: Samples) => {
      this.samplesSubject.next(response.samples);
      this.totalSubject.next(response.total);
      this.pageSizeSubject.next(response.pageSize);
      this.pageIndexSubject.next(response.pageIndex);
    });
  }
}

2. 调整组件代码

在组件中使用数据源的Observable来绑定分页器参数,同时修正mat-table的dataSource绑定:

// App component.ts
import { Component, OnInit } from '@angular/core';
import { SamplesDataSource } from './shared/data-sources/samples-data-source';
import { SamplesService } from './shared/services/samples.service';

export class AlertCasesComponent implements OnInit {
  samplesTableColumns: string[] = ['sampleId', 'sample'];
  samplesTablePageSizes: number[] = [10, 20, 50, 100];
  samplesDataSource: SamplesDataSource;

  constructor(private samplesService: SamplesService) {}

  ngOnInit(): void {
    this.samplesDataSource = new SamplesDataSource(this.samplesService);
    this.samplesDataSource.getSamples();
  }

  // 处理分页器变更事件
  onPageChange(event: any) {
    this.samplesDataSource.getPaginatedSamples(event.pageIndex, event.pageSize);
  }
}

3. 修改模板绑定

使用async管道绑定分页参数,同时mat-table直接绑定数据源实例:

<!-- App Component.html -->
<mat-table class="..." [dataSource]="samplesDataSource">
  <!-- 你的列和行实现 -->
  <ng-container matColumnDef="sampleId">
    <mat-header-cell *matHeaderCellDef> 样本ID </mat-header-cell>
    <mat-cell *matCellDef="let sample"> {{sample.id}} </mat-cell>
  </ng-container>
  <ng-container matColumnDef="sample">
    <mat-header-cell *matHeaderCellDef> 样本名称 </mat-header-cell>
    <mat-cell *matCellDef="let sample"> {{sample.name}} </mat-cell>
  </ng-container>

  <mat-header-row *matHeaderRowDef="samplesTableColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: samplesTableColumns;"></mat-row>
</mat-table>

<mat-paginator 
  [length]="samplesDataSource.total$ | async" 
  [pageIndex]="samplesDataSource.pageIndex$ | async" 
  [pageSize]="samplesDataSource.pageSize$ | async" 
  [pageSizeOptions]="samplesTablePageSizes" 
  showFirstLastButtons
  (page)="onPageChange($event)">
</mat-paginator>

关键说明

  • DataSource<Sample>:明确泛型为单个样本类型,让connect返回Sample[]的Observable,符合Angular CDK的类型要求。
  • 分页参数独立维护:通过单独的Subject保存total、pageSize等参数,并暴露Observable给组件,配合async管道实现响应式绑定。
  • 错误处理优化:catchError中返回NO_SAMPLES而不是空数组,确保分页参数不会因为请求错误出现异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:22:01