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

Angular Material Table使用后端HTTP请求返回的Observable数据时无法更新显示的问题求助

问题:Angular Material Table 无法显示后端返回的数据

我尝试将从后端获取的数据展示在Angular Material Table中。当我的_timelogService.getAllTimelogs()方法返回硬编码的模拟数据的Observable时,一切正常。但当我改为向后端发起实际的HTTP GET请求并返回该数据的Observable时,尽管dataSource中包含所需数据,HTML表格却无法显示任何行。即使使用实际的Observable,调用logData()方法时也能在控制台打印出正确的dataSource数据。我怀疑Angular Table没有在dataSource更新时同步更新,请问有人遇到过类似问题吗?

组件代码

export class OverviewComponent implements OnInit { 
  displayedColumns: string[] = ['roomId', 'startTime', 'endTime', 'duration']; 
  dataSource = new MatTableDataSource<TimeLogTable>(); 
  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; 
  @ViewChild(MatSort, { static: true }) sort: MatSort; 

  constructor(private _timelogService: TimelogService) { 
    //In the Docs example the dummy data gets created here 
  } 

  ngOnInit(): void { 
    this._timelogService.getAllTimelogs().subscribe( 
      dataObs=>{ 
        console.log("Display received data"); 
        console.log(dataObs); 
        this.dataSource.data = dataObs; 
        this.dataSource.paginator = this.paginator; 
        this.dataSource.sort = this.sort; 
      } 
    ) 
  } 

  logData(){ 
    console.log(this.dataSource); 
  } 
}

服务代码

getAllTimelogs(): Observable<TimeLogTable[]>{ 
  var timelogsArr: TimeLogTable[] = []; 
  var timelogsArrDummy: TimeLogTable[] = []; 

  //Call to backend 
  this._http.get<any>('http://localhost:3000/gettimelogs?token=' + localStorage.getItem('token'), this.httpOptions) 
    .subscribe( 
      res=>{ 
        //Create timeLogTable from json with backend response 
        for (let i = 0; i < res.timelogs.length; i++) { 
          timelogsArr.push({ 
            roomId: res.timelogs[i].roomId, 
            startTime: new Date(res.timelogs[i].startTime), 
            endTime: new Date (res.timelogs[i].endTime), 
            duration: "test" 
          }); 
        } 
      }, 
      err=>{ 
        //Error handling 
      } 
    ); 

  //Return the Observable - DOES NOT WORK 
  return of (timelogsArr); 

  /* //Return the dummy data as an Observable - DOES WORK 
  //Dummy data 
  timelogsArrDummy = [ 
    {roomId: 'kit_A', startTime: new Date(1631185600000), endTime: new Date (1631185661311), duration: "test"}, 
    {roomId: 'din_A', startTime: new Date(1631185600000), endTime: new Date (1631195661311), duration: "test"}, 
    {roomId: 'off_A', startTime: new Date(1631185600000), endTime: new Date (1632185661311), duration: "test"}, 
    {roomId: 'kit_B', startTime: new Date(1631185600000), endTime: new Date (1631885661311), duration: "test"}, 
  ] 
  return of (timelogsArrDummy); 
  */ 
}

问题分析与解决方法

兄弟,我一眼就看出问题出在你的服务代码里了!你犯了一个典型的异步操作错误:

  • 你在服务里先订阅了HTTP请求,然后立刻返回了of(timelogsArr)。但HTTP请求是异步的,这时候timelogsArr还是空数组,返回的Observable已经把空数组发出去了。等之后HTTP请求完成,你把数据塞进timelogsArr,但组件订阅的那个Observable早就完成了,根本不会收到更新后的数据。

正确的服务写法

不要在服务里订阅HTTP请求,而是用RxJS的map操作符来转换后端返回的数据,直接返回这个经过处理的Observable,让组件去订阅:

import { map } from 'rxjs/operators';

getAllTimelogs(): Observable<TimeLogTable[]>{ 
  // 直接返回HTTP请求的Observable,用map处理数据
  return this._http.get<any>('http://localhost:3000/gettimelogs?token=' + localStorage.getItem('token'), this.httpOptions)
    .pipe(
      map(res => {
        // 在这里把后端返回的数据转换成TimeLogTable数组
        const timelogsArr: TimeLogTable[] = [];
        for (let i = 0; i < res.timelogs.length; i++) { 
          timelogsArr.push({ 
            roomId: res.timelogs[i].roomId, 
            startTime: new Date(res.timelogs[i].startTime), 
            endTime: new Date(res.timelogs[i].endTime), 
            duration: "test" 
          }); 
        }
        return timelogsArr;
      }),
      // 这里可以加catchError处理错误
    );
}

为什么这样能行?

HTTP请求本身就是一个Observable,当后端返回数据时,它才会发出值。我们用map操作符在数据流里转换数据,这样返回的Observable会在请求完成时发出转换后的完整数组。组件订阅这个Observable时,就能拿到正确的数据,赋值给dataSource.data后,Material Table就能正常渲染了。

另外,你组件里的写法没问题,只要服务返回正确的Observable,订阅后赋值给dataSource就能正常显示。如果你想更简洁,还可以用Angular的async管道,直接在模板里订阅Observable,这样连手动订阅都省了:

比如组件里定义timelogs$: Observable<TimeLogTable[]>;,然后ngOnInit里this.timelogs$ = this._timelogService.getAllTimelogs();,模板里<table mat-table [dataSource]="timelogs$ | async" ...>,这样还能避免内存泄漏~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 09:49:07