Prime NG Row Group with Subheader and Totals Row

Prime NG Row Group with Subheader
Table – RowGroup
It is easy to implement row grouping using the flexible template-driven approach of the p-table. In this example, sorting is enabled by default to sort the data by brand initially and then a rowGroupMetadata
object is created to represent how many rows a brand should span along with the rowIndex of the group. Similarly, multiple field grouping can be implemented as well.
Points covered in this blog:
- We have created PRIME NG table using Angular framework.
- Implemented the Sorting feature of Prime Ng.
- Implemented Row Grouping with Subheader.
- Grouped by a region field.
- Display Total Row as the first row of each group.
Code
app.component.html
This is HTML template contains Prime Ng Table with Angular framework.
<div class="card">
<h5>Region Summary Data with Subheader, Grouping & total row</h5>
<p-table
[value]="summary"
[columns]="summaryTableColumns"
(sortFunction)="customSort($event)"
[customSort]="true"
>
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of columns" [pSortableColumn]="col.field">
{{ col.header }}
<p-sortIcon
[field]="col.field"
ariaLabel="Activate to sort"
ariaLabelDesc="Activate to sort in descending order"
ariaLabelAsc="Activate to sort in ascending order"
></p-sortIcon>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-summary let-rowIndex="rowIndex">
<tr
class="subheader-row"
*ngIf="rowGroupMetadata[summary.region].index === rowIndex"
>
<td *ngFor="let col of summaryTableColumns; let colIndex = index">
<span
*ngIf="col.field === 'region'; else displayTotalFields"
style="font-weight: bold"
>{{ summary.region }}</span
>
<ng-template #displayTotalFields>
<span class="total">{{
rowGroupMetadata[summary.region][col.field]
}}</span>
</ng-template>
</td>
</tr>
<tr>
<td></td>
<ng-container
*ngFor="let col of summaryTableColumns; let colIndex = index"
>
<td *ngIf="col.field !== 'region'">
<span>{{ summary[col.field] }}</span>
</td>
</ng-container>
</tr>
</ng-template>
</p-table>
</div>
app.component.css
This css file contains styling.
.subheader-row {
background-color:antiquewhite !important;
}
.total {
font-weight: bold;
}
app.component.ts
This typescript file contains code to get summary data from a JSON file and custom sort functionality and row grouping.
import { Component } from '@angular/core';
import { Summary } from './summary.model';
import { SummaryService } from './summary.service';
import { SortEvent } from 'primeng/api';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
summary: Summary[];
rowGroupMetadata: any;
summaryTableColumns = [
{
field: 'region',
header: 'Region',
},
{
field: 'city',
header: 'City',
},
{
field: 'hospitals',
header: 'Total Hospitals',
},
{
field: 'schools',
header: 'Total Schools',
},
{
field: 'colleges',
header: 'Total Colleges',
},
{
field: 'companies',
header: 'Total Companies',
},
];
constructor(private SummaryService: SummaryService) {}
/**
* Hit an API to get summary data
* call updateRowGroupMetaData to create sub header and grouping
*/
ngOnInit() {
this.SummaryService.getCustomersMedium().then((data) => {
this.summary = data;
this.updateRowGroupMetaData();
});
}
/**
* Sorting data
* @param event
*/
customSort(event: SortEvent) {
event.data.sort((data1, data2) => {
let value1 = data1[event.field];
let value2 = data2[event.field];
let result = null;
if (value1 == null && value2 != null) result = -1;
else if (value1 != null && value2 == null) result = 1;
else if (value1 == null && value2 == null) result = 0;
else if (data1.region === data2.region && data1.city && data2.city) {
if (typeof value1 === 'string' && typeof value2 === 'string') {
result = value1.localeCompare(value2);
} else {
result = value1 < value2 ? -1 : value1 > value2 ? 1 : 0;
}
} else if (event.field === 'region') {
result = value1.localeCompare(value2);
} else {
result = 0;
}
return event.order * result;
});
this.updateRowGroupMetaData();
}
/**
* Updates Rows with Groups
*/
updateRowGroupMetaData() {
this.rowGroupMetadata = {};
if (this.summary) {
for (let i = 0; i < this.summary.length; i++) {
let rowData = this.summary[i];
const totalRowObj = {
index: 0,
size: 1,
hospitals: rowData.hospitals,
schools: rowData.schools,
colleges: rowData.colleges,
companies: rowData.companies,
};
if (i == 0) {
this.rowGroupMetadata[rowData.region] = totalRowObj;
} else {
let previousRowData = this.summary[i - 1];
if (rowData.region === previousRowData.region)
this.rowGroupMetadata[rowData.region].size++;
else
this.rowGroupMetadata[rowData.region] = {
...totalRowObj,
index: i,
};
}
}
}
console.log(this.rowGroupMetadata);
}
}
summary.service.ts
This is service file contans http request to fetch data.
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Summary } from './summary.model';
@Injectable()
export class SummaryService {
constructor(private http: HttpClient) {}
getCustomersMedium() {
return this.http
.get<any>('assets/summary-data.json')
.toPromise()
.then((res) => <Summary[]>res.data)
.then((data) => {
return data;
});
}
}
summary.model.ts
This is view model defines Summary fields.
export interface Summary {
region? : string;
city?:string;
hospitals?: number;
schools?: number;
colleges?: number;
companies?: number;
}
summary-data.json file
This is JSON file.
Complete Code on Git hub
https://github.com/msaxena25/Prime-NG-Row-Group-with-Subheader-and-Totals-Row
Learn document: https://www.primefaces.org/primeng-8.1.5/#/table/rowgroup
VS Code Useful Extensions for Web Development
One thought on “Prime NG Row Group with Subheader and Totals Row”