Search code examples
reactjstypescriptprimereact

Filtering with multiple values over an array column in Primereact Datatable


I'm using a primereact datatable, and i have a column which is tags, every row of the table has an array of tags.

So i wanted to create a filter, where you have a multiselect form, displaying all the possible tags (the user shouldn't be able to write anything, just use the options the system gives).

I achieved this with a custom filterElement, but when i apply the filter, no matters which tag i select, it will give no results, i think is not filtering well.

I'm using this matchMode

tags: {
    operator: FilterOperator.AND,
    constraints: [{ value: null, matchMode: FilterMatchMode.IN }]
}

This is my column

<Column
    header="Tags"
    field="tags"
    style={{ minWidth: '16rem' }}
    filter
    filterElement={(options) => <TagsRowFilterTemplate options={options} />}
    sortable
    body={(contact) => <TagBodyTemplate contact={contact} tags={tags} />}
/>

And this is my TagsRowFilterTemplate component

export const TagsRowFilterTemplate = ({ options }: TagsFilterProps) => {
    const { tags } = useTags()

    return (
        <MultiSelect
            value={options.value ? tagsAsOptionFormat(options.value) : []}
            options={tags}
            onChange={(e: MultiSelectChangeEvent) => options.filterApplyCallback(e.value, options.index)}
            itemTemplate={itemTemplate}
            placeholder="Select One or More"
            optionLabel="name"
            className="p-column-filter"
            showClear
            style={{ minWidth: '12rem' }}
            maxSelectedLabels={3}
            filter
        />
    )
}

I tried using filterMatchMode, filterFunction, i tried user the matchmode: CONTAINS.

What i expect: To give an example, if i have 2 users:

John Doe with tags: ['foo', 'bar']

Jane Doe with tags: ['foo']

When i filter by foo i want to get jane and joe, but when i filter for bar i want to see only John


Solution

  • I finally solved using custom filtering in a bizarre way.
    I guided myself with [this issue] (https://github.com/primefaces/primereact/issues/3325).
    And with this codesandbox.
    So i registered a new FilterService this way

    FilterService.register(ArrayContainsMatchMode, tagRowFilterFunction)
    
    const tagRowFilterFunction = (contactTagIds: string[], filterValue: Tag[]) => {
        if (!filterValue || !contactTagIds) return true
        if (filterValue.length === 0) return true
        else if (filterValue.length !== 0 && contactTagIds.length === 0) return false
        const selectedTags = filterValue.map((tag: Tag) => tag.tid)
        return selectedTags.every((tid) => contactTagIds.includes(tid))
    }