Search code examples
javascriptangulartypescriptprimeng

Custom Global filter in PrimeNG (FilterService)


I was facing an issue while filtering the p-table in PrimeNG. Scenario:

table containing: John Kelvin Doe

Search key: John Doe

expected: 1 row, I was getting 0 row using built-in filters;

I tried built-in filters, but i was getting 0 records.

I have created a Custom Global Filter that check if input has two words then checking startsWith and endsWith filters.

onGlobalFilter(table: Table, event: Event) {
    table.filterGlobal((event.target as HTMLInputElement).value, 'customContains');
}

private configureFilter () {
    // build-in filter
    let containsFilter = this.filterService.filters['contains']; 
    let startsWithFilter = this.filterService.filters['startsWith']; 
    let endsWithFilter = this.filterService.filters['endsWith']; 

    // register  custom filter
    this.filterService.register("customContains", (value, filter): boolean => {
        if (filter === undefined || filter === null || filter.trim() === '') {
            return true;
        }
        if (value === undefined || value === null) {
            return false;
        }
        const str = filter.trim().split(" ");
        if (str.length === 2 ) {
            console.log(filter)

            return startsWithFilter(value, str[0]) &&  endsWithFilter(value, str[1]);
        } else {
            return containsFilter(value, filter); 
        }
    });
}

Scenario 2: search key: john man doe table entries: john man doe han

Above filter is not working.

I'm looking for a solution which gives correct result for N number of words.


Solution

  • John Kelvin Doe

    does not contain

    John Doe

    It contains John and it contains Doe, but does not contain John Doe. If you want to find entries that contain both words, then you will need to search for contains filter for both and put an && between them.

    john man doe han

    starts with

    john man doe

    but does not end with

    john man doe

    Hence, it's not true that it starts with john man doe AND ends with it. So, instead of your

            const str = filter.trim().split(" ");
            if (str.length === 2 ) {
                console.log(filter)
    
                return startsWithFilter(value, str[0]) &&  endsWithFilter(value, str[1]);
            } else {
                return containsFilter(value, filter); 
            }
    

    I recommend

            const str = filter.trim().split(" ");
            for (let f of filter) {
                if (!containsFilter(value, f)) return false;
            }
            return true;
    

    as the solution. Basically we break up the filter by space and we loop the items and we check for each whether they are contained by value.