Search code examples
javascripthtmlangularangular-materialangular7

Angular Material - Compare and iterate through two datasources


I am using Mat-Table to display records in grid format. Also I have implemented expandable rows by using two different datasources.

First datasource will have records without duplicate and when I click on a row, it expands and display records from second datasource which has duplicate records. My requirement is to display only matching records in the expanded rows but it is showing all the records from second datasource.

I used *ngFor and *ngIf options but it is throwing error. Can someone please guide me to identify the correct code.

HTML Code:

<mat-table [dataSource]="mDataSource1" multiTemplateDataRows matSort>

    <ng-container matColumnDef="Id">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
        <mat-cell *matCellDef="let element">{{element.Id}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="Name">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
        <mat-cell *matCellDef="let element">{{element.Name}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="Weight">
        <mat-header-cell *matHeaderCellDef mat-sort-header>Weight</mat-header-cell>
        <mat-cell *matCellDef="let element">{{element.Weight}}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="expandedDetail">
        <mat-table [dataSource]="mDataSource2" matSort>
          <ng-container *ngIf = "element.Id === item.Id">              
            <ng-container matColumnDef="Id">
                <mat-header-cell *matHeaderCellDef mat-sort-header>Id</mat-header-cell>
                <mat-cell *matCellDef="let item">{{item.Id}}</mat-cell>
            </ng-container>

            <ng-container matColumnDef="Name">
                <mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
                <mat-cell *matCellDef="let item">{{item.Name}}</mat-cell>
            </ng-container>

            <ng-container matColumnDef="Weight">
                <mat-header-cell *matHeaderCellDef mat-sort-header>Weight</mat-header-cell>
                <mat-cell *matCellDef="let item">{{item.Weight}}</mat-cell>
            </ng-container>

            <mat-row *matRowDef="let row; columns: mDataSource2Columns;"></mat-row>
          </ng-container>
        </mat-table>
    </ng-container>

    <mat-header-row *matHeaderRowDef="mDataSource1Columns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: mDataSource1Columns;" class="example-element-row"
        [class.example-expanded-row]="expandedElement === row"
        (click)="expandedElement = expandedElement === row ? null : row"
        (mouseover)="row.gridHovered = true" (mouseout)="row.gridHovered = false">
    </mat-row>

    <mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></mat-row>

    <mat-footer-row *matFooterRowDef="['loading']" [ngClass]="{'hide':mDataSource1!=null}">
    </mat-footer-row>
    <mat-footer-row *matFooterRowDef="['noData']"
        [ngClass]="{'hide':!(mDataSource1!=null && mDataSource1.data.length==0)}">
    </mat-footer-row>

</mat-table>


mDataSource1 =  [
      {Id:1, name: 'ABC', weight: 40 },
      {Id:2, name: 'DEF', weight: 45 },
      {Id:4, name: 'GHI', weight: 85 }
    ]

mDataSource2 = [
  {Id:1, name: 'ABC', weight: 10 },
  {Id:1, name: 'ABC', weight: 14 },
  {Id:1, name: 'ABC', weight: 16 },
  {Id:2, name: 'DEF', weight: 23 },
  {Id:2, name: 'DEF', weight: 22 },
  {Id:4, name: 'GHI', weight: 44 },
  {Id:4, name: 'GHI', weight: 41 }
]

When I click second row it should display only 2 records inside the expanded row and not all the records.

  ID   Name  Weight
  2     DEF   23
  2     DEF   22

Solution

  • I didn't see the ngFor in your example. Angular does not allow multiple structural directive on one tag. Instead of this:

    <div *ngIf="true" *ngFor="let..."></div>
    

    use this

    <ng-container *ngIf="true">
      <div *ngFor="let..."></div>
    </ng-container>
    

    Don't worry about ng-container, Angular doesn't put it in the DOM.