Angular Material表格在ngOnInit中设置Sort和Pagination时报错
问题排查与解决
错误原因分析
报错提示“提供了undefined而非预期的流”,核心问题出在stateService.startupData上:
startupData未被正确定义为合法的Observable类型,比如服务中直接将其赋值为undefined,而非用BehaviorSubject/Subject等RxJS流类型初始化。- 额外注意:
ngOnInit钩子执行时,@ViewChild获取的paginator和sort还未完成视图初始化(Angular中视图元素在ngAfterViewInit阶段才会就绪),此时给dataSource赋值这两个属性会导致undefined,但这不是当前报错的直接触发原因。
解决方法
1. 修复StateService中的startupData定义
确保startupData是合法的Observable,示例代码如下:
// state.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class StateService { private readonly startupDataSubject = new BehaviorSubject<any>(null); // 对外暴露为Observable,避免外部直接修改流数据 public startupData: Observable<any> = this.startupDataSubject.asObservable(); // 当数据准备完成时调用此方法推送数据 setStartupData(data: any) { this.startupDataSubject.next(data); } }
2. 优化组件逻辑,避免重复创建数据源+正确利用生命周期
无需每次订阅都创建新的MatTableDataSource实例,同时确保在视图元素就绪后再绑定分页和排序:
import { AfterViewInit, OnInit, OnDestroy, Component } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { StateService } from './state.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html' }) export class YourComponent implements OnInit, AfterViewInit, OnDestroy { dataSource = new MatTableDataSource<any>([]); @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort!: MatSort; private dataSubscription?: Subscription; constructor(private stateService: StateService) {} ngOnInit(): void { this.dataSubscription = this.stateService.startupData.subscribe((data: any) => { if (data?.dataejers) { // 直接更新数据源的data属性,无需重新创建实例 this.dataSource.data = data.dataejers; } }); } ngAfterViewInit(): void { // 视图就绪后一次性绑定分页和排序 this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; } ngOnDestroy(): void { // 销毁订阅,避免内存泄漏 this.dataSubscription?.unsubscribe(); } }
3. 可选:使用Async管道简化代码(推荐)
通过Async管道自动管理订阅,无需手动处理订阅销毁:
// 组件代码 import { AfterViewInit, OnInit, Component } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { StateService } from './state.service'; import { map } from 'rxjs'; @Component({ selector: 'app-your-component', templateUrl: './your-component.component.html' }) export class YourComponent implements OnInit, AfterViewInit { data$ = this.stateService.startupData.pipe( map(data => data?.dataejers || []) ); dataSource = new MatTableDataSource<any>([]); @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort!: MatSort; constructor(private stateService: StateService) {} ngOnInit(): void { this.data$.subscribe(data => { this.dataSource.data = data; }); } ngAfterViewInit(): void { this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; } }
模板中无需额外处理订阅:
<table mat-table [dataSource]="dataSource"> <!-- 表格列定义 --> </table> <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
内容的提问来源于stack exchange,提问作者Rud Faden
相关产品推荐
相关产品推荐

