Search code examples
angularobservabledatasourcemat-tableangular-changedetection

How do I update my Angular Table dataSource with data from an Observable


Im trying to display data in my Angular Material Table, that I receive from my backend.

Everything works fine as long as my _timelogService.getAllTimelogs() function returns an Observable of dummy data which I hard coded into the function. As soon as I make an actualy HTTP POST request to my backend - and return an Observable of that data - the html table doesnt display any rows eventhough my dataSource contains the required data.

When I use logData() it display the correct data even if i use the actual Observable.

I suspect that my Angular Table does not get updated when the dataSource gets updated.

Did anyone else ever encounter such an issue?

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);
  }
}

My Service

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);
  */
}

Here a screenshot from the console.log(dataObs): enter image description here


Solution

  • I found the issue that was causing my problem. My getAllTimelogs() function returned an empty Object first and then filled it up with data later. The MatTableDataSource somehow could not handle that. Here is my working code:

    export class OverviewComponent implements OnInit, AfterViewInit {
    
      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) { }
    
      timelogsArr: TimeLogTable[] = [];
    
      ngOnInit(): void {
        this._timelogService.getAllTimelogs().subscribe(
          res=>{
            //Create timeLogTable from json with backend response
            console.log("alert");
            for (let i = 0; i < res.timelogs.length; i++) {
              //Change the format of the data
              this.timelogsArr.push({
                roomId: res.timelogs[i].roomId,
                startTime: new Date(res.timelogs[i].startTime),
                endTime: new Date (res.timelogs[i].endTime), 
                duration: this.msToTime(res.timelogs[i].endTime - res.timelogs[i].startTime)
              });
            }
            //Update table datasource
            this.dataSource.data = this.timelogsArr;
          }
        );
      }
    
      ngAfterViewInit(): void {
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;
      }

    And here the getAlltimelogs() function:

    getAllTimelogs(): Observable<any>{
        return this._http.get<any>('http://localhost:3000/gettimelogs?token=' + localStorage.getItem('token'), this.httpOptions)
      }

    Thanks to everyone who kindly helped me.