1

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);
  }
}
mnu-nasir
  • 1,642
  • 5
  • 30
  • 62
  • 1
    I think sorting for other columns is not working as the table is sorted based on category. Let say sort by name ascending, imagine Accessories have A and C; while Electronics have B. Then the group row will be broken as it orders as A (accs.) --> B (elec.) --> C (accs.) – Yong Shun Aug 15 '21 at 07:38
  • Is there any way to solve it? – mnu-nasir Aug 15 '21 at 14:04
  • Would say sorting for other columns is not possible for row group table. – Yong Shun Aug 15 '21 at 23:43

0 Answers0