Alexander_Barton
Alexander_Barton

Reputation: 11

update mat table datasource within subscribe

I am relatively new to angular and am having a bit of trouble in my typescript of updating a mat table datasource (declared as datasource :any) inside a subscription.

My function below goes away to the adminservice and makes an api call, the function then loops over the returned array and makes another api call via the adminservice to get some more information about the fleet.

At the bottom part of my code is the original method to update the datasource, but without the extra required data. This works fine, and is quite confusing to me.

Any help would be greatly appreciated.

refresh(): void {
    const data = {};
    const that = this;
    this.adminService.fleets(data).subscribe(result => {

      that.fleetTableData = [];

      result.forEach(function (fleetObject){

        if (typeof fleetObject.fleetTotals === 'undefined'){
          fleetObject.fleetTotals = {};
          fleetObject.fleetTotals.totalVehicles = 0;
          fleetObject.fleetTotals.totalActiveVehicles = 0;
          fleetObject.fleetTotals.totalStatusTestedVehicles = 0;
        }

        that.fleetTableData[fleetObject.fleetId] = fleetObject;

        that.adminService.vehicles(
          {fleetId: fleetObject.fleetId}
        ).subscribe(result2 => {

          result2.forEach(function (vehicleForFleet) {
            var fleetId = vehicleForFleet.fleetId;
            that.fleetTableData[fleetId].fleetTotals.totalVehicles = (that.fleetTableData[fleetId].fleetTotals.totalVehicles + 1);
            if (typeof vehicleForFleet.commissioning !== 'undefined') {
              if (vehicleForFleet.commissioning.commissionStatus === 'tested') {
                that.fleetTableData[fleetId].fleetTotals.totalStatusTestedVehicles = (that.fleetTableData[fleetId].fleetTotals.totalStatusTestedVehicles + 1);
              }
              if (vehicleForFleet.commissioning.commissionStatus === 'active') {
                that.fleetTableData[fleetId].fleetTotals.totalActiveVehicles = (that.fleetTableData[fleetId].fleetTotals.totalActiveVehicles + 1);
              }
            }
          });
        });
      });
      // in subscribe doesn't save to that.datasorce
      that.dataSource.data = new MatTableDataSource(that.fleetTableData);
      that.dataSource.sort = that.sort;
      console.log(that.fleetTableData);
    });
    //out subscribe doest work as it is returning undefined
    // console.log(this.fleetTableData);
    // this.dataSource = new MatTableDataSource(this.fleetTableData);
    // this.dataSource.sort = this.sort;


//works
    // const data = {};
    // this.adminService.fleets(data).subscribe(result => {
    //   this.fleets = result;
    //   this.dataSource = new MatTableDataSource(this.fleets);
    //   this.dataSource.sort = this.sort;
    //
    //   console.log(result);
    // });
  }

Upvotes: 0

Views: 4863

Answers (3)

Andres Doncel
Andres Doncel

Reputation: 44

I had the same problem at one time when I worked with mat-table, I solved this in this way.

this.dataSource = new MatTableDataSource(data)

Upvotes: 0

Mike Hanson
Mike Hanson

Reputation: 306

Looking at your code it looks like this.datasource is already a MatTableDatasource. If that is the case then try just setting the .data property to this.fleets instead of a new MatTableDatasource.

this.dataSource.data = that.fleetTableData;

Upvotes: 1

Joshua McCarthy
Joshua McCarthy

Reputation: 1852

There are two main strategies to address in your code example:

  1. You have nested subscribe() methods, which is an anti-pattern in RxJS. You should only have one subscribe(), otherwise things will quickly break.
  2. The logic your executing inside subscribe() should instead be handled by RxJS "operators". This will also help with your nested subscribe() issue.

Here's the strategy I would recommend.

this.adminService.fleets(data).pipe(
  map(result=>{
    // define and return the data you need for adminService.vehicles
  }),
  switchMap(fleetId=>this.adminService.vehicles(fleetId)),
  map(result2=>{
    // Your logic to define and update this.dataSource for your table
  })
).subscribe()

The map() operator will let you take the emitted value and return a new value.

The switchMap() works the same way as map() but will let you return a new observable (in this case, your vehicles method that requires the parameter from our first observable.

After that, we use another map() operator to take the value emitted from adminService.vehicles() and update the state property this.dataSource.

Upvotes: 0

Related Questions