Сортировка столбцов не работает с табличными данными группы строк в элементах управления PrimeNG в Angular

#angular #primeng #primeng-datatable

Вопрос:

Я использую таблицу PrimeNG для отображения некоторых данных на своей странице. Для отображения данных в таблице я использовал группу строк со складным стилем. Это рабочая находка. Но проблема в том, что после использования группы строк Сортировка столбцов сейчас не работает. Вот мое репо на GitHub.

HTML-код:

 <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

 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);
  }
}
 

Комментарии:

1. Я думаю, что сортировка по другим столбцам не работает, так как таблица сортируется по категориям. Допустим, сортировка по названию по возрастанию, представьте, что аксессуары имеют A и C; в то время как электроника имеет B. Затем строка группы будет разбита по мере ее упорядочения как A (в соответствии) —> B (выборка) —>> C (в соответствии).

2. Есть ли какой-нибудь способ решить эту проблему?

3. Я бы сказал, что сортировка по другим столбцам невозможна для таблицы групп строк.