angulartypescriptloopsangular-materialangular-material-table

Angular Material - How to display data with the loop in the mat-table


I use the Angular Material table to display records inside a loop. According to my code, only one record is getting displayed. However, two records are coming from the response. Please review my array and code and provide me with a solution. The table is displayed like this:

enter image description here

Array:

[
    {
        "unitTypeSizeConcat": [
            "HJHJ",
            "ABC"
        ],
        "list": [
            {
                "id": "6665c40f93ff924ef96e05de",
                "subscriberId": "6331733aa38f414a418ab3fc",
                "locationId": "64f85dff2f4280212657f7e7",
                "description": "test",
                "unitRateType": "Rented Unit Below Board Rate",
                "unitRateTypeId": 1,
                "rateChangeType": "Rotating Fixed Amount",
                "value": "5",
                "effectiveDate": "01/01/2024",
                "recurringPeriod": "5",
                "noticeDays": "5",
                "applyBySize": true,
                "applyByUnit": false,
                "applyByUnitSizeCode": "6662dc6325bec37c0cedf0d9",
                "applyByUnits": [],
                "applyByUnitId": "MongoObjectId(id=null)",
                "applyByUnitName": null,
                "revisionHistory": 0,
                "unitTypeSizeConcat": "HJHJ;ABC",
                "lastRateChangeDate": null,
                "lastRateChangeAmount": null,
                "noticeDate": null
            },
            {
                "id": "66f4f05eb5c2b8424c431fc7",
                "subscriberId": "6331733aa38f414a418ab3fc",
                "locationId": "64f85dff2f4280212657f7e7",
                "description": "ghgh",
                "unitRateType": "Rented Unit Below Board Rate",
                "unitRateTypeId": 1,
                "rateChangeType": "Rotating Fixed Amount",
                "value": "2",
                "effectiveDate": null,
                "recurringPeriod": "2",
                "noticeDays": "2",
                "applyBySize": true,
                "applyByUnit": false,
                "applyByUnitSizeCode": "6662dc6325bec37c0cedf0d9",
                "applyByUnits": [
                    "666ab7306ac32055804a25b5",
                    "666bdba59783af20ce55b5ff",
                    "6679aba38a764d4b153d6d8d",
                    "667aac1bbcb1e01439e96368",
                    "667d1b6d0306513a6c75ed30",
                    "66c5d8e97cf2c6598e91c134"
                ],
                "applyByUnitId": "000000000000000000000000",
                "applyByUnitName": null,
                "revisionHistory": 0,
                "unitTypeSizeConcat": "HJHJ;ABC",
                "lastRateChangeDate": null,
                "lastRateChangeAmount": null,
                "noticeDate": null
            }
        ]
    }
]

HTML:

<div *ngFor="let rc of filteredSizeCode" class="table-responsive table-content">
  <h3 class="text-primary mt-1 mb-3">Unit Type : {{rc.unitTypeSizeConcat[0]}}</h3>
  <table mat-table [dataSource]="datasource" matSort class="mat-elevation-z8" matSortDisableClear>
    <ng-container matColumnDef="unitRateType">
      <th class="centered-sorted-header" mat-header-cell *matHeaderCellDef mat-sort-header>Unit Rate Filter</th>
      <td mat-cell *matCellDef="let row; let i=index">{{row.list[i].unitRateType}}</td>
    </ng-container>
    <ng-container matColumnDef="rateChangeType">
      <th class="centered-sorted-header" mat-header-cell *matHeaderCellDef mat-sort-header>Rate Change Type</th>
      <td mat-cell *matCellDef="let row; let i=index">{{row.list[i].rateChangeType}}</td>
    </ng-container>
    <ng-container matColumnDef="effectiveDate">
      <th class="centered-sorted-header" mat-header-cell *matHeaderCellDef mat-sort-header>Effective Date</th>
      <td mat-cell *matCellDef="let row; let i=index">{{row.list[i].effectiveDate | date: 'MM-dd-yyyy'}}</td>
    </ng-container>
    <ng-container matColumnDef="noticeDays">
      <th class="centered-sorted-header" mat-header-cell *matHeaderCellDef mat-sort-header>Notice Days</th>
      <td mat-cell *matCellDef="let row; let i=index ">{{row.list[i].noticeDays}}</td>
    </ng-container>
    <ng-container matColumnDef="value">
      <th style="padding-left:28px;" mat-header-cell *matHeaderCellDef mat-sort-header>Value</th>
      <td mat-cell *matCellDef="let row; let i=index">{{row.list[i].rateChangeType == 'Rotating Fixed Amount' || row.list[i].rateChangeType == 'One Time Only Fixed Amount'?'$':null }}
        {{row.list[i].value}}{{row.list[i].rateChangeType == 'Rotating Fixed Percentage' || row.list[i].rateChangeType == 'One Time Only Fixed Percentage'?'%':null}}
      </td>
    </ng-container>
    <ng-container matColumnDef="recurringPeriod">
      <th style="padding-left:28px;" mat-header-cell *matHeaderCellDef mat-sort-header>Recurring Period</th>
      <td mat-cell *matCellDef="let row; let i=index">{{row.list[i].recurringPeriod?row.list[i].recurringPeriod:null}}</td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>
</div>

ts code:

displayedColumns = [
  'unitRateType',
  'rateChangeType',
  'effectiveDate',
  'noticeDays',
  'value',
  'recurringPeriod',
];
datasource = new MatTableDataSource([]);

ngOnInit() {
  this.datasource.data = this.filteredSizeCode;
}

Solution

  • Before answering your problem regarding not being able to display all the records from the list array, my concern is that you are iterating the filteredSizeCode in the view, and at the same time, there is only 1 MatTableDataSource which is shared with the data filteredSizeCode.

    This works if you only have a single entry in the filteredSizeCode array. If you have multiple entries, I am sure that in each iterated rc element, your <mat-table> will display those data that shouldn't belong to the rc element.

    The correct way is you need to create the MatTableDataSource instance(s) for each rc element and not to share it.

    Back to your problem, i (in the View) is the index referring to the row of filteredSizeCode (root array), not the list array from each element. Hence, it will never display the second items and so on for the list array.

    In that case, you need to flatten the list array from each element.


    Changes

    1. Flatten the list array from each element.

    2. Create each MatTableDataSource instance for each element in the filteredSizeCode array.

    datasources: MatTableDataSource<any[]>[] = [];
    
    ngOnInit() {
      this.filteredSizeCode.forEach((size: any) => {
        let data: any[] = size.list.map((x: any) => ({ ...size, list: x}))
    
        this.datasources.push(new MatTableDataSource(data));
      })
    }
    
    1. Provide the MatTableDataSource instance based on the current iterated index from the rc element.

    2. Remove [i] from the list as it is flattened to an object.

    <div *ngFor="let rc of filteredSizeCode; let i = index" class="table-responsive table-content">
      <h3 class="text-primary mt-1 mb-3">
        Unit Type : {{rc.unitTypeSizeConcat[0]}}
      </h3>
      <table
        mat-table
        [dataSource]="datasources[i]"
        matSort
        class="mat-elevation-z8"
        matSortDisableClear
      >
        <ng-container matColumnDef="unitRateType">
          <th
            class="centered-sorted-header"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Unit Rate Filter
          </th>
          <td mat-cell *matCellDef="let row; let i=index">
            {{row.list.unitRateType}}
          </td>
        </ng-container>
        <ng-container matColumnDef="rateChangeType">
          <th
            class="centered-sorted-header"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Rate Change Type
          </th>
          <td mat-cell *matCellDef="let row; let i=index">
            {{row.list.rateChangeType}}
          </td>
        </ng-container>
        <ng-container matColumnDef="effectiveDate">
          <th
            class="centered-sorted-header"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Effective Date
          </th>
          <td mat-cell *matCellDef="let row; let i=index">
            {{row.list.effectiveDate | date: 'MM-dd-yyyy'}}
          </td>
        </ng-container>
        <ng-container matColumnDef="noticeDays">
          <th
            class="centered-sorted-header"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Notice Days
          </th>
          <td mat-cell *matCellDef="let row; let i=index ">
            {{row.list.noticeDays}}
          </td>
        </ng-container>
        <ng-container matColumnDef="value">
          <th
            style="padding-left: 28px"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Value
          </th>
          <td mat-cell *matCellDef="let row; let i=index">
            {{ row.list.rateChangeType == 'Rotating Fixed Amount' || row.list.rateChangeType == 'One Time Only Fixed Amount' ? '$' : null }}
            {{ row.list.value }} {{ row.list.rateChangeType == 'Rotating Fixed Percentage' || row.list.rateChangeType == 'One Time Only Fixed Percentage' ? '%' : null }}
          </td>
        </ng-container>
        <ng-container matColumnDef="recurringPeriod">
          <th
            style="padding-left: 28px"
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
          >
            Recurring Period
          </th>
          <td mat-cell *matCellDef="let row; let i=index">
            {{row.list.recurringPeriod ? row.list.recurringPeriod : null}}
          </td>
        </ng-container>
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
      </table>
    </div>
    

    Demo @ StackBlitz