Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add custom filterfunction with PrimeNG DataTable?

Basicly all info is provided in the title.

It seems to me that I am bound to the filterMatchModes that are available ( contains, in, equals, endsWith, startsWith). In my usecase my column field is an array, and no single value.

My specified column looks like this:

<p-column field="types" [filter]="true" header="{{'AIRPORTS.TYPES' | translate}}">
    <template let-airport="rowData" pTemplate="body">
        <span *ngFor="let type of airport.types; let isLast = last">
            {{('AIRPORTS.' + type) | translate}}{{isLast ? '' : ', '}}
        </span>
    </template>
    <template pTemplate="filter" let-col>
        <p-dropdown [options]="choices"
                    [style]="{'width':'100%'}"
                    (onChange)="airportsDataTable.filter($event.value,col.field,col.filterMatchMode)"
                    styleClass="ui-column-filter">
        </p-dropdown>
    </template>
</p-column>
like image 930
dendimiiii Avatar asked Mar 10 '17 09:03

dendimiiii


2 Answers

I had a similar problem where I had to filter array column-data with multiple selectable filter-values (from a p-multiSelect, so the filter was an array too). I figured out a way to extend the available filterMatchModes with some help from the original source-code. Unfortunately I can't vouch for it being good practice, but hey, in the version I'm using (PrimeNG 4.1.2) it works.

You may have to adapt and tune your filter-function to your needs, but here is what my solution would look like in your case (with a p-dropdown):

  • in the view, export the DataTable into a template-reference-variable (#dt)
  • make it accessible in the component via the @ViewChild-decorator
  • add your own filter-function directly to the DataTable's array of filters (in ngOnInit())

component.ts

@Component({...})
export class DatatableComponent implements OnInit {
    ...
    @ViewChild('dt') dt: DataTable;
    ...
    ngOnInit() {
        this.dt.filterConstraints['inCollection'] = function inCollection(value: any[], filter: any): boolean {
            // value = array of data from the current row
            // filter = value from the filter that will be searched in the value-array

            if (filter === undefined || filter === null) {
                return true;
            }

            if (value === undefined || value === null || value.length === 0) {
                return false;
            }

            for (let i = 0; i < value.length; i++) {
                if (value[i].toLowerCase() === filter.toLowerCase()) {
                    return true;
                }
            }

            return false;
        }
    }
}

In your view you can now use the new filter-function by setting the filterMatchMode of the column to what you named it before:

component.html

<p-dataTable #dt ...>
    ...
    <p-column field="types" filterMatchMode="inCollection" header="{{'AIRPORTS.TYPES' | translate}}">
        <template let-airport="rowData" pTemplate="body">
            <span *ngFor="let type of airport.types; let isLast = last">
                {{('AIRPORTS.' + type) | translate}}{{isLast ? '' : ', '}}
            </span>
        </template>
        <template pTemplate="filter" let-col>
            <p-dropdown [options]="choices"
                        [style]="{'width':'100%'}"
                        (onChange)="dt.filter($event.value,col.field,col.filterMatchMode)"
                        styleClass="ui-column-filter">
            </p-dropdown>
        </template>
    </p-column>
    ...
</p-dataTable>

All I did in the view was set the filterMatchMode, otherwise I copied your code. (I also renamed the template-reference to #dt to make it shorter and more readable)
Hint: you don't need [filter]=true in this column, since the standard filter won't show when your column has a custom filter-template.

As I mentioned, with a custom filter function like this you can for example implement filtering array-data with a p-multiSelect filter (nested loop in filter-function), search for substrings in array or whatever else you can think of.

like image 138
mtx Avatar answered Sep 19 '22 23:09

mtx


As a simple workaround, you can directily change the FilterUtils:

import { FilterUtils } from 'primeng/utils';

FilterUtils['filterTest'] = (value, filter) => value <= filter && value >= filter;

this.dt.filter(search, 'field', 'filterTest');
like image 24
Rodolfo Jorge Nemer Nogueira Avatar answered Sep 20 '22 23:09

Rodolfo Jorge Nemer Nogueira