[FIXED] Primeng FilterUtils unique per component?

Issue

I have a page:

<app-new-grid [isTotals]="false"></app-new-grid>
<hr>
<app-new-grid [isTotals]="true"></app-new-grid>

Which renders fine (with differences by checking the isTotals variable), and is a primeng table.

<p-table #dt [value]="data" [columns]="cols" dataKey="name"
    [autoLayout]="true" sortMode="single" (sortFunction)="customSort($event)" [customSort]="true" (onFilter)="onFilter($event)">
...

Each grid has it’s own dataset and is displayed correctly. However when I try to filter the first table, it is using the variables that were setup for the second table. Is this because of the #dt in the table declaration? How do I solve this?

Component:

import { Component, OnInit, Input } from '@angular/core';
import { } from '@angular/cdk/scrolling';
import { MyData } from './MyData-Interface';
import rawJson from '../../../assets/json/myData.json';
import { SelectItem } from 'primeng/api/selectitem';
import { FilterUtils } from 'primeng/utils';
import { SortEvent } from 'primeng/api/sortevent';
import { PercentPipe } from '@angular/common'

@Component({
  selector: 'app-new-grid',
  templateUrl: 'new-grid.component.html',
  styleUrls: ['new-grid.component.scss']
})

export class MyDataNewGridComponent implements OnInit {
  @Input() isTotals: boolean;

  myData: MyData[];

  pp: PercentPipe;

  cols: any[];

  classSelect: any[] = [];
  classes: SelectItem[];

  products: SelectItem[];

  soldRangeValues: number[];
  soldRangeMin: number;
  soldRangeMax: number;

  rowGroupMetadata = {};

  groupingVar = 'name';

  constructor() { }

  ngOnInit(): void {
    console.log(this.isTotals);
    this.pp = new PercentPipe('en-US');

    this.myData = <MyData[]>rawJson.filter(
      detail => !this.isTotals ? detail.sortOrder < 5000 : detail.sortOrder > 5000);

    this.fillMyData();

    this.cols = [
      { field: 'name', header: 'Product' },
      { field: 'description', header: 'Class' }
    ];

    var productNames = this.myData
      .map(item => item.name)
      .filter((value, index, self) => self.indexOf(value) === index);

    this.products = productNames.map(item => ({ label: item, value: item }));

    this.initializeRangeValues();

    this.declareFilters();

    this.updateRowGroupMetaData(this.myData);
  }

  private fillMyData() {
    //Group by defined variable
    var grouped = this.myData.reduce((g: any, person: MyData) => {
      g[person[this.groupingVar]] = g[person[this.groupingVar]] || [];
      g[person[this.groupingVar]].push(person);
      return g;
    }, {});

    this.myData = [];

    for (let key of Object.keys(grouped)) {
      let entry = grouped[key] as MyData[];

      //Check if we already have a subtotal
      var temp = entry.map(item => item['description']).filter(x => x.toUpperCase().includes("TOTAL"));

      if (temp.length === 0) {
        var subTotal = {} as MyData;
        subTotal.name = entry[0].name;

        entry.push(subTotal);
      }

      for (let x of entry) {
        this.myData.push(x);
      }
    }
  }

  declareFilters() {
    FilterUtils['soldRangeFilter'] = (value, filter): boolean => {
      return value >= this.soldRangeValues[0] && value <= this.soldRangeValues[1];
    }
  }

  initializeRangeValues() {
    let sold = this.getMinMax('sold');
    this.soldRangeMin = sold[0];
    this.soldRangeMax = sold[1];
    this.soldRangeValues = [this.soldRangeMin, this.soldRangeMax];
  }

  onFilter(event) {
    this.updateRowGroupMetaData(event.filteredValue);
  }

  updateRowGroupMetaData(data) {
    this.rowGroupMetadata = {};
    if (data) {
      for (let i = 0; i < data.length; i++) {
        let rowData = data[i];
        let name = rowData.name;
        if (i == 0) {
          this.rowGroupMetadata[name] = { index: 0, size: 1 };
        }
        else {
          let previousRowData = data[i - 1];
          let previousRowGroup = previousRowData.name;
          if (name === previousRowGroup)
            this.rowGroupMetadata[name].size++;
          else
            this.rowGroupMetadata[name] = { index: i, size: 1 };
        };
      }
    }
  }

  arraySum = function (items, prop) {
    return items.reduce(function (a, b) {
      return a + b[prop];
    }, 0);
  };

  customSort(event: SortEvent) {
    let map = new Map<string, number>(event.data
      .filter(x => x.description.includes('Subtotal'))
      .map(x => [x[this.groupingVar], x[event.field]]));

    this.myData = event.data.slice()
      .sort((a, b) => (map.get(a.name) - map.get(b.name)) * event.order);

    this.updateRowGroupMetaData(this.myData);
  }

  getMinMax(field: string) {
    let fieldSelect = this.myData.map(item => item[field]).filter(item => Number.isFinite(item));
    fieldSelect = fieldSelect.sort((n1, n2) => n1 - n2);

    return [fieldSelect[0], fieldSelect[fieldSelect.length - 1]];
  }
}

Update:

So I figured out the problem was with my use of FilterUtils. If I change the declaration of the filters to be unique per grid:

declareFilters() {
        FilterUtils['soldRangeFilter' + isTotals] = (value, filter): boolean => {
          return value >= this.soldRangeValues[0] && value <= this.soldRangeValues[1];
        }
      }

then it works. Is there a cleaner way to make sure each grid has it’s own instance of FilterUtils?

Solution

So I figured out the problem was with my use of FilterUtils. If I change the declaration of the filters to be unique per grid:

declareFilters() {
        FilterUtils['soldRangeFilter' + isTotals] = (value, filter): boolean => {
          return value >= this.soldRangeValues[0] && value <= this.soldRangeValues[1];
        }
      }

then it works.
Later versions of primeng changed FilterUtils to a service.

Answered By – Shawn

Answer Checked By – Pedro (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published