#angular #primeng #primeng-datatable
Вопрос:
В моем проекте angular я установил элементы управления PrimeNG версии 11.4.4. Я использовал элемент управления таблицей для создания табличных данных, отображающих строки в группе со складным стилем. Теперь я добавил текстовое поле и раскрывающийся элемент управления прямо перед строкой заголовка для фильтрации данных таблицы. Но проблема в том, что с данными таблицы групп строк фильтрация с помощью выпадающего списка работает не всегда. Работает только выпадающий список «Аксессуары». Но для других выпадающих элементов фильтрация не работает. Вот мое репозиторий на GitHub. Может ли кто-нибудь запустить код, чтобы увидеть проблему и предложить мне, как ее решить?
<h2>Table with Rog Group</h2>
<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">
{{col.header}}
</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 [ngModel]="value" [options]="categories" (onChange)="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() {
this.rowGroupMetadata = {};
if (this.products) {
for (let i = 0; i < this.products.length; i ) {
let rowData = this.products[i];
let category1 = rowData.category;
if (i == 0) {
this.rowGroupMetadata[category1] = { index: 0, size: 1 };
}
else {
let previousRowData = this.products[i - 1];
let previousRowGroup = previousRowData.category;
if (category1 === previousRowGroup)
this.rowGroupMetadata[category1].size ;
else
this.rowGroupMetadata[category1] = { index: i, size: 1 };
}
}
}
}
}
Ответ №1:
Вопрос
Проверил, что эта логика приводит к rowGroupMetadata
сбою при фильтрации таблицы.
<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>
Вам нужно убедиться, что rowGroupMetadata
это также обновляется при фильтрации таблицы.
Решение
Для HTML-части, вместо прямого filter
обратного вызова, вы должны вызвать dropdownFilter
пользовательскую функцию filter
, проанализировав обратный вызов и $event.value
.
.component.html
<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>
dropDownFilter
метод принимаетfilter
обратный вызов иvalue
параметры. В этом методе после фильтрации таблицы будет передан
filteredValue
(отфильтрованный результат) вupdateRowGroupMetaData
метод.updateRowGroupMetaData
изменяется метод, который получаетrows
в качестве необязательного параметра. Когда будет полученоrows
, обновитrowGroupMetadata
на его основе. В противном случаеthis.products
используется существующая логика.
.компонент.ts
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: string) => void, value: string) {
filter(value);
this.updateRowGroupMetaData(this.dt2.filteredValue);
}
Комментарии:
1. Я получаю эту ошибку: параметр » a «неявно имеет тип «любой». ошибка в функции dropdownFilter. Дайте мне знать, как решить эту проблему, пожалуйста.
2. Обновил свой ответ. Укажите
a
в качестве типа строки.dropdownFilter(filter: (a: string) => void, value: string)
3. Спасибо за решение. Сейчас это работает.