1

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;
}
1
  • Hmmm, I not sure that your code works. As filteredSizeCode is an array, and you are iterating it in the view, this will create N MatTableDataSource instance. But in your component, you are specifying a single MatTableDataSource instance.
    – Yong Shun
    Commented Sep 26, 2024 at 7:31

2 Answers 2

1

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

2
  • It is working fine with your solution. However, the sorting stopped working now?
    – Asna Khan
    Commented Sep 26, 2024 at 12:51
  • Sorting is not working can be due to: 1. You are not import the MatSortModule. 2. As few columns are with the data from the nested field. You need to implement the additional logic for sorting. Check out my answer from customized sorting in here.
    – Yong Shun
    Commented Sep 26, 2024 at 13:06
0

You do not have to create multiple tables using loop. Instead create one table and pass your data in array format. You can refer this example.

https://material.angular.io/components/table/overview#table-basic

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.