0

I need to merge data from 4 different endpoints to create a ListElement that will be displayed in angular material table. I can see correct data in logs, but the table remains empty. If I add condition: "data.data.length > 0" it manages to show only 1 row, "data.data.length > 1" shows only 2 rows etc.

Constructor includes nested subscriptions which is probably not the best solution, but I'm not sure how to use forkJoin, mergeMap etc. when each subscription depends on the previous one.

This is component constructor:

  constructor(injected services...) {
this.userId = this.tokenStorageService.getCurrentUserId();
this.isLoading = true;

let getAllBookingsParams = new GetAllBookingsParams();
getAllBookingsParams.userId = this.userId;

this.bookingsService
  .getAll(getAllBookingsParams)
  .toPromise()
  .then((bookings) => {
    let permData = [];
    bookings.forEach((booking) => {
      this.propertiesService
        .get(booking.propertyId)
        .subscribe((property) => {
          this.citiesService.get(property.cityId).subscribe((city) => {
            this.propertyImagesService
              .getAll(property.id)
              .subscribe((images) => {
                let listElement = new BookingsListElement();
                # initialize listElement with data from above
                permData.push(listElement);
              });
          });
        });
    });

    this.data = new MatTableDataSource(permData);
    this.data.data = permData;
    console.log(this.data);
    this.isLoading = false;
  });

}

This is my html page:

<div *ngIf="!isLoading">
<table *ngIf="data"      <------- If I add another condition: "data.data > 0" it shows only 1 row, "data.data > 1" shows only 2 etc.
mat-table
[dataSource]="data"
multiTemplateDataRows
class="mat-elevation-z8">
<ng-container
  matColumnDef="{{ column }}"
  *ngFor="let column of columnsToDisplay"
>
  <th mat-header-cell *matHeaderCellDef>{{ column }}</th>
  <td mat-cell *matCellDef="let element">{{ element[column] }}</td>
</ng-container>

<ng-container matColumnDef="expandedDetail">
  <td
    mat-cell
    *matCellDef="let element"
    [attr.colspan]="columnsToDisplay.length"
  >
    <div
      class="example-element-detail"
      [@detailExpand]="
        element == expandedElement ? 'expanded' : 'collapsed'
      "
    >
      <div class="example-element-diagram">
        <div *ngIf="element.imageUrl" class="example-element-image">
          <img [src]="element.imageUrl" />
        </div>
      </div>
      <div class="example-element-content">
        <div class="example-element-description">
          {{ element.propertyName }}
        </div>
        <div class="example-element-description">
          <span class="example-element-description-attribution"
            >{{ element.address }}, {{ element.city }}</span
          >
        </div>
        <div class="example-element-description">
          {{ element.description }}
        </div>
        <div class="example-element-description">
          Accommodates number:
          {{ element.accommodatesNumber }}
        </div>
        <div class="example-element-description">
          Bathroom number:
          {{ element.bathroomNumber }}
        </div>
        <div class="example-element-description">
          Bedroom number:
          {{ element.bedroomNumber }}
        </div>
      </div>
      <div class="example-element-diagram">
        <button
          mat-raised-button
          color="primary"
          [routerLink]="['/properties/details', element.propertyId]"
        >
          Property details
        </button>
        <br />
        <button
          *ngIf="!element.cancellationDate"
          mat-raised-button
          color="warn"
          (click)="cancelBooking(element.id)"
        >
          Cancel booking
        </button>
        <br />
        <button
          *ngIf="element.cancellationDate"
          mat-raised-button
          color="warn"
          disabled
        >
          Booking cancelled {{ element.cancellationDate | date }}
        </button>
      </div>
    </div>
  </td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr
  mat-row
  *matRowDef="let element; columns: columnsToDisplay"
  class="example-element-row"
  [class.example-expanded-row]="expandedElement === element"
  (click)="expandedElement = expandedElement === element ? null : element"
></tr>
<tr
  mat-row
  *matRowDef="let row; columns: ['expandedDetail']"
  class="example-detail-row"
></tr>

logs

cannelle28
  • 168
  • 5
  • 17

1 Answers1

1

It looks like you assign the value of permData to this.data, however this assignment is reached before the subscriptions return their respective values that are needed for permData.

If turn your data into an observable you can use an async pipe in your template to let Angular take care of the rest.

Erik
  • 722
  • 4
  • 11