saikiran
saikiran

Reputation: 2445

Angular Material Row when looping through data

My Data Source is like below

[{"isGroup":true,"groupName":"MV Reddy","items":[{"id":1,"name":"MV Reddy","verticalid":5,"vertical":"Colocation - Large > 20 Racks","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2019},{"id":10,"name":"MV Reddy","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020}]},{"isGroup":true,"groupName":"Neeraj Jha","items":[{"id":2,"name":"Neeraj Jha","verticalid":4,"vertical":"Alliances","target":"70","sap":"20","colo":"30","others":"20","quarter":2,"year":2019},{"id":5,"name":"Neeraj Jha","verticalid":4,"vertical":"Alliances","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2019}]},{"isGroup":false,"groupName":"Suresh Rathod","items":[{"id":3,"name":"Suresh Rathod","verticalid":3,"vertical":"C4C India (Public Cloud)","target":"100","sap":"20","colo":"30","others":"50","quarter":1,"year":2019}]},{"isGroup":false,"groupName":"Arun Dubey","items":[{"id":4,"name":"Arun Dubey","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":4,"year":2019}]},{"isGroup":true,"groupName":"Atin Singh","items":[{"id":6,"name":"Atin Singh","verticalid":5,"vertical":"Colocation - Large > 20 Racks","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":7,"name":"Atin Singh","verticalid":2,"vertical":"IAAS and Rest of Ctrls Services","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":8,"name":"Atin Singh","verticalid":3,"vertical":"C4C India (Public Cloud)","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020},{"id":9,"name":"Atin Singh","verticalid":6,"vertical":"Govt","target":"150","sap":"80","colo":"20","others":"50","quarter":1,"year":2020}]}]

and I wrote/printing my Table like this:

<table class="mat-elevation-z8 " mat-table matSort [dataSource]='targetData' (matSortChange)="sortData($event)">
    <ng-container matColumnDef="Employee">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Employee </th>
        <td mat-cell *matCellDef="let element"> {{element.items[0].name}}
        </td>
    </ng-container>

    <ng-container matColumnDef="groupData">

        <ng-container *matCellDef="let group">
            <ng-container *ngFor="let groupCol of group.items;index as i;">
                <ng-container *ngIf="i==0 else newRow;">
                    <td mat-cell rowspan="group.items.length">
                        {{group.groupName}}
                    </td>
                    <td mat-cell>
                        {{groupCol.vertical}}
                    </td>
                    <td mat-cell>
                        {{groupCol.target}}
                    </td>
                    <td mat-cell>
                        {{groupCol.sap}}
                    </td>
                    <td mat-cell>
                        {{groupCol.colo}}
                    </td>
                    <td mat-cell>
                        {{groupCol.others}}
                    </td>
                </ng-container>
                <ng-template #newRow>
                    <tr mat-row>
                        <td mat-cell>
                            {{groupCol.vertical}}
                        </td>
                        <td mat-cell>
                            {{groupCol.target}}
                        </td>
                        <td mat-cell>
                            {{groupCol.sap}}
                        </td>
                        <td mat-cell>
                            {{groupCol.colo}}
                        </td>
                        <td mat-cell>
                            {{groupCol.others}}
                        </td>
                    </tr>
                </ng-template>

            </ng-container>
        </ng-container>

    </ng-container>

    <ng-container matColumnDef="Vertical">
        <th mat-header-cell *matHeaderCellDef>Vertical</th>
        <td mat-cell *matCellDef="let element"> {{element.items[0].vertical}} </td>
    </ng-container>
    <ng-container matColumnDef="Target">
        <th mat-header-cell *matHeaderCellDef>Target</th>
        <td mat-cell *matCellDef="let element"> {{element.items[0].target}} </td>
    </ng-container>
    <ng-container matColumnDef="SAP">
        <th mat-header-cell *matHeaderCellDef>SAP</th>
        <td mat-cell *matCellDef="let element">{{element.items[0].sap}}</td>
    </ng-container>
    <ng-container matColumnDef="COLO">
        <th mat-header-cell *matHeaderCellDef>COLO</th>
        <td mat-cell *matCellDef="let element">{{element.items[0].colo}}</td>
    </ng-container>
    <ng-container matColumnDef="Others">
        <th mat-header-cell *matHeaderCellDef>Others</th>
        <td mat-cell *matCellDef="let element">{{element.items[0].others}}</td>
    </ng-container>
    <ng-container matColumnDef="Action">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Action </th>
        <td mat-cell *matCellDef="let element">
            <div class="tableActions ">

                <button class="view mat-button" (click)='edit(element.items[0])'>
                    <i class="material-icons">
                        create
                    </i>
                </button>
            </div>
        </td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="TargetTable;"></tr>
    <tr mat-row *matRowDef="let row; columns: TargetTable;"></tr>
    <tr mat-row *matRowDef="let row; columns: ['groupData']; when: isAGroup"></tr>
</table>

I am unable to print another row inside a table while looping through my data

Final result should be like below.

End Result should look like this

Upvotes: 0

Views: 1622

Answers (2)

saikiran
saikiran

Reputation: 2445

My Table:

<table mat-table matSort [dataSource]="targetData" class="mat-elevation-z8">

    <ng-container matColumnDef="Employee">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Employee </th>
        <td mat-cell *matCellDef="let element" [attr.rowspan]="rowSpanLength(element)"
            [style.display]="rowSpanLength(element)>0 ? ''  : 'none'">
            {{element.name}}
        </td>
    </ng-container>
    <ng-container matColumnDef="Vertical">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Vertical </th>
        <td mat-cell *matCellDef="let element"> {{element.vertical}}
        </td>
    </ng-container>
    <ng-container matColumnDef="Target">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> Target </th>
        <td mat-cell *matCellDef="let element"> {{element.target}}
        </td>
    </ng-container>
    <ng-container matColumnDef="SAP">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> SAP </th>
        <td mat-cell *matCellDef="let element"> {{element.sap}}
        </td>
    </ng-container>
    <ng-container matColumnDef="COLO">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> COLO </th>
        <td mat-cell *matCellDef="let element"> {{element.colo}}
        </td>
    </ng-container>
    <ng-container matColumnDef="Others">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Others</th>
        <td mat-cell *matCellDef="let element"> {{element.others}}
        </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="TargetTableColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: TargetTableColumns"></tr>
</table>

And my rowSpanLength function like below:

rowSpanLength(item) {
    let nameArr = this.targetData.filter(i => i.name === item.name);
    //return length if the item is first element in above array else 0
    return nameArr[0].id === item.id ? nameArr.length : 0;
}

This function will keep rowSpan if the item/tr is first one from Group, for rest of all items the Name td will be hidden.

The result is like below which is what i wanted. got this idea from @uminder (https://stackoverflow.com/users/2358409/uminder) stackblitz Final Result Image

Upvotes: 0

uminder
uminder

Reputation: 26190

Your approach goes in the right direction as you're using the rowspan attribute. The template however is unnecessary complex and can be simplified if you pre-process your data.

I solved a similar problem in the open source project Koia using a RowSpanComputer class. Within summary-table.component.html, the computed row spans are then used to define the rowspan attribute of the td element.

[attr.rowspan]="rowSpans[iCol][iRow].span"

The RowSpanComputer class computes the rowspan for each cell out of the specified table data (array of rows). It basically loops over the rows and increments the rowspan for cells as long as their value remains unchanged and left located cells were also spanned. As soon as the value changes, the corresponding rowspan is reset to zero.

Please have a look at the following StackBlitz that uses the data you provided. This must obviously further be refined in order to obtain the result you expect.

UPDATE

If you want to have rowspan applied for cells even if left located cells were not spanned, simply remove the following line from the RowSpanComputer class.

spanColumnContexts.slice(iCol + 1).forEach(c => c.spannedRow = {}); 

I did this in this StackBlitz where a renamed RowSpanComputer to GroupingRowSpanComputer in order to avoid confusion.

Upvotes: 1

Related Questions