【问题标题】:Dropdown filter is not working in with Row Group table in PrimeNG controls下拉过滤器不适用于 PrimeNG 控件中的行组表
【发布时间】:2021-08-14 19:22:05
【问题描述】:

在我的 Angular 项目中,我安装了 PrimeNG 控件版本 11.4.4。我已经使用表格控件创建表格数据以显示具有可折叠样式的组中的行。

现在我在标题行之前添加了一个文本框和下拉控件来过滤表格数据。但问题在于行组表数据,使用下拉列表进行过滤并不总是有效。只有下拉项目附件在工作。但是对于其他下拉项过滤不起作用。

Here is my GitHub Repo.

任何人都可以运行代码来查看问题并向我建议如何解决这个问题吗?

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

【问题讨论】:

    标签: angular typescript primeng primeng-datatable


    【解决方案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回调,不如通过解析filter回调和$event.value来调用dropdownFilter自定义函数。

    .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>
    
    1. dropDownFilter 方法接受 filter 回调和 value 参数。在这个方法中,表格被过滤后,会通过 filteredValue(过滤结果)到updateRowGroupMetaData 方法。
    2. updateRowGroupMetaData 方法被修改为接收rows 作为可选参数。当收到rows 时,将根据它更新rowGroupMetadata。否则,this.products 用于保留现有逻辑。

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

    Sample Solution on StackBlitz

    【讨论】:

    • 我收到此错误:参数“a”隐含地具有“任何”类型。错误在 dropdownFilter 函数中。请告诉我如何解决这个问题。
    • 更新了我的答案。将a 指定为字符串类型。 dropdownFilter(filter: (a: string) =&gt; void, value: string)
    • 感谢您的解决方案。它现在可以工作了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-17
    • 2022-06-21
    • 2021-01-08
    • 2017-10-24
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    相关资源
    最近更新 更多