I am using PrimeNG Table to show some data in my page. To show data in table I have used Row Group with Collapsible style. It's working find. But the problem is, after using Row Group Column Sorting is not working now. Here is my GitHub Repo.
HTML Code:
<p-table #dt2 [columns]="selectedColumns" [value]="products" sortField="category" sortMode="single" (onSort)="onSort()"
dataKey="category" styleClass="p-datatable-gridlines p-datatable-striped">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of columns" pSortableColumn="{{col.field}}">
{{col.header}}
<p-sortIcon field="{{col.field}}"></p-sortIcon>
</th>
</tr>
<tr>
<th *ngFor="let col of columns" [ngSwitch]="col.field">
<p-columnFilter *ngSwitchCase="'code'" type="text" field="code" matchMode="contains"
(input)="applyFilter1($event, 'code', 'contains')">
</p-columnFilter>
<p-columnFilter *ngSwitchCase="'name'" type="text" field="name" matchMode="contains"
(input)="applyFilter1($event, 'name', 'contains')">
</p-columnFilter>
<p-columnFilter *ngSwitchCase="'category'" field="category" matchMode="equals" [showMenu]="false">
<ng-template pTemplate="filter" let-value let-filter="filterCallback">
<p-dropdown [options]="categories" (onChange)="dropdownFilter(filter, $event.value)" placeholder="Any"
[showClear]="true">
<ng-template let-option pTemplate="item">
<div class="p-multiselect-representative-option">
<span class="p-ml-1">{{option.label}}</span>
</div>
</ng-template>
</p-dropdown>
</ng-template>
</p-columnFilter>
<p-columnFilter *ngSwitchCase="'quantity'" type="text" field="quantity" matchMode="equals"
(input)="dt2.filter($event.target.value1)">
</p-columnFilter>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex" let-expanded="expanded">
<tr *ngIf="rowGroupMetadata[rowData.category].index === rowIndex">
<td colspan="4">
<button type="button" pButton pRipple [pRowToggler]="rowData"
class="p-button-text p-button-rounded p-button-plain p-mr-2"
[icon]="expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'"></button>
<span class="p-text-bold p-ml-2">{{rowData.category}}</span>
</td>
</tr>
</ng-template>
<ng-template pTemplate="rowexpansion" let-rowData let-columns="columns">
<tr>
<td *ngFor="let col of columns">
<span>{{rowData[col.field]}}</span>
</td>
</tr>
</ng-template>
</p-table>
TS File
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Table } from 'primeng/table';
import { Product } from '../_models/product.model';
import { ProductService } from '../_services/product.service';
@Component({
selector: 'app-row-group-grid',
templateUrl: './row-group-grid.component.html',
styleUrls: ['./row-group-grid.component.css']
})
export class RowGroupGridComponent implements OnInit {
products: Product[] = [];
cols: any[] = [];
_selectedColumns: any[] = [];
categories: any[] = [];
rowGroupMetadata: any;
@ViewChild('dt2') dt2!: Table;
constructor(private productService: ProductService) { }
ngOnInit() {
this.productService.getProductsSmall().then(data => {
this.products = data;
this.updateRowGroupMetaData();
});
this.cols = [
{ field: 'code', header: 'Code' },
{ field: 'name', header: 'Name' },
{ field: 'category', header: 'Category' },
{ field: 'quantity', header: 'Quantity' }
];
this._selectedColumns = this.cols;
this.categories = [
{ label: "Clothing", value: "Clothing" },
{ label: "Electronics", value: "Electronics" },
{ label: "Fitness", value: "Fitness" },
{ label: "Accessories", value: "Accessories" },
];
}
@Input() get selectedColumns(): any[] {
return this._selectedColumns;
}
set selectedColumns(val: any[]) {
//restore original order
this._selectedColumns = this.cols.filter(col => val.includes(col));
}
applyFilter1($event: any, field: string, matchMode: string) {
let value = ($event.target as HTMLInputElement)?.value;
this.dt2.filter(value, field, matchMode);
}
onSort() {
this.updateRowGroupMetaData();
}
updateRowGroupMetaData(rows?: Product[]) {
let products = rows ?? this.products;
this.rowGroupMetadata = {};
if (products) {
for (let i = 0; i < products.length; i++) {
let rowData = products[i];
let category1 = rowData.category;
if (i == 0) {
this.rowGroupMetadata[category1] = { index: 0, size: 1 };
}
else {
let previousRowData = products[i - 1];
let previousRowGroup = previousRowData.category;
if (category1 === previousRowGroup)
this.rowGroupMetadata[category1].size++;
else
this.rowGroupMetadata[category1] = { index: i, size: 1 };
}
}
}
}
dropdownFilter(filter: (a: any) => void, value: string) {
filter(value);
this.updateRowGroupMetaData(this.dt2.filteredValue);
}
}