primereact icon indicating copy to clipboard operation
primereact copied to clipboard

FilterMatchMode.CUSTOM & filterFunction broken + custom filter type errors

Open luketpena opened this issue 3 years ago • 4 comments

Describe the bug

Potentially deprecated custom match mode

We had a situation where we needed custom filtering. Details on custom filtering are in the middle of large "Documentation" page instead of "Filter" page. Googling for answers led to using FilterMatchMode.CUSTOM and a filterFunction on the column.

The result: filterFunction never fires and all content is permanently filtered out of the table. So I dug into the types and found this: image The return type for the filterFunction within the Column type is "void", whereas all examples I found online were expecting it to be a type of boolean. If this is being used in a .filter function, then it always returning void and the behavior of filtering out all data makes sense.

So all in all, this seems to be completely broken / abandoned, and yet there is no indication of that directly in the documentation or the types themselves, and is in fact the only method mentioned in the StackOverflow posts I found. (Maybe there is more? My Google skills aren't 100%.)

Bad documentation around real custom match mode

The real (?) custom filter method is found in the aforementioned Documentation page.

This method involves 1) register a custom filter with the FilterService 2) declare a match mode and pass it to the filterMatchModeOptions prop on the Column (the order in the documentation makes this unclear) 3) on your filters matchMode, give it the string name of the new custom match mode.

However, here is the example they give in the docs: image

Notice there is no declaration of matchMode (that is done in a previous code snippet) and there is no use of custom filter match modes in this example. It's so bizarre, that I need to confirm - am I missing something? Why does the DataTableCustomFilterDemo have no custom filter matchMode implemented? It is demonstrating a custom filter element, but it's positioned below the section on custom filter match modes. And there is no other example on this.

Type errors on custom matchMode

If you do the steps above and pass a custom matchMode on your filters and pass those filters on the DataTable, I get a type error where it is expecting matchMode to be of type DataTableFilterMatchModeType, but is instead being given a string. Which is required by the official way of defining these custom matchModes outlined above.

The solution is to cast {filters as DataTableFilterMeta} on the filters input of the DataTable.

Being forced to cast types opens up possibility for better typing of the filters state

The filters are by default untyped. You can cast them as DataTableFilterMeta as well, but this creates the same type error around custom matchModes. So I made my own type for this that includes value, matchMode, operators, etc.

But let's say we stick with DataTableFilterMeta - it is a union type between DataTableFilterMetaData and DataTableOperatorMetaData. Because of this, you actually get type errors if you try to access any properties of a filter. (For example, if I have a filter called "name", filters.name.value will throw a type error because the property "value" does not exist, despite being declared on type DataTableFilterMetaData.)

Here is the type I declared to get intellisense out of it: image

This seems to work? So I declare the filters with useState<FilterState>({...}). This will also throw a type error when passed to DataTable, but we already have to cast that anyways to get custom matchModes working.

But this seems to be emblematic of seemingly missing type usage / implicit any throughout the documentation and unhelpful types declared in the codebase. For example the options type in all examples in the docs is implicit type "any". There is a type ColumnFilterElementTemplateOptions, but I made my own custom type for it: image

Now, we could use the ColumnFilterElementTemplateOptions, but that has a value of type "any". It would seem beneficial to be able to type this. Here is what it currently is

interface ColumnFilterElementTemplateOptions {
    field: string;
    index: number;
    filterModel: ColumnFilterModelOptions;
    value: any;
    filterApplyCallback(value?: any, index?: number): void;
    filterCallback(value?: any, index?: number): void;
}

This gives no intellisense on the value without casting. My solution defaults to any, but gives you the option to give it a strict type.

Requests / questions / TLDR

  • Is "FilterMatchMode.CUSTOM" and filterFunction deprecated? Officially mark them deprecated and remove from documentation if so. If not deprecated, are they broken / why is there no documentation on their use?
  • DataTable documentation poorly organized: break out individual sections out of the huge "Documentation" page into the already existing individual pages (e.g. Filtering documentation on Filtering page, Sorting docs on Sorting page, etc.) instead of leaving the them in one giant, difficult to parse mass.
  • Custom match modes registration not recognized by type input on DataTable filter prop. Make that more seamless without requiring casting.
  • Fix custom matchMode documentation to actually document custom matchModes usage
  • Provide a useful type for the filters state that gives real intellisense. Currently defaults to any, using official type gives no intellisense, using custom type breaks type expected by DataTable filter prop.
  • Just better typing in general (example: ColumnFilterElementTemplateOptions)

I'm sure there are reasons why some of these things are the way they are, but the process of learning this was not great. And having to implement workarounds to increase type usability does not feel good.

Reproducer

No response

PrimeReact version

8.0.0

React version

18.x

Language

TypeScript

Build / Runtime

Create React App (CRA)

Browser(s)

No response

Steps to reproduce the behavior

FilterMatchMode.CUSTOM:

  1. Set filter matchMode to FilterMatchMode.CUSTOM
  2. Pass a filterFunction to a column
  3. Observe that filterFunction never fires and all content is permanently filtered from the table

matchMode registration:

  1. Register a custom match match mode
  2. Define the match mode array
  3. Pass the matchModes to the appropriate column
  4. On the filters definition, set the matchMode for that column to the name of the custom matchMode
  5. Pass the filters to the DataTable
  6. Observe a type error on string not matching FilterMatchMode

Alternate path:

  1. Follow previous steps up to step 3
  2. Do not set match mode in filters - attempt to set filterMatchMode on Column to name of custom matchMode name
  3. Observe it is expecting one of the FilterMatchMode enum values and throws a type error

Expected behavior

There is only one method of implementing custom match modes. This method is clearly documented and throws no type errors. If FilterMatchMode.CUSTOM is broken, fix it. If it is deprecated, mark it as such / remove from docs. If it is functional, show documentation on correct use. There ought to be types for every value that provide useful intellisense and those types ought to be used in documentation examples. Documentation on DataTables should not be one single wall of text and should be broken up into the already existing discreet pages.

luketpena avatar Sep 15 '22 15:09 luketpena

I think really the DataTable Filter demo needs to be updated to show Custom usage as well: https://primefaces.org/primereact/datatable/filter/

melloware avatar Sep 15 '22 16:09 melloware

For now here is a code sandbox someone posted of a working Custom filter in column 1: https://codesandbox.io/s/loving-bush-5gr5y4?file=/src/demo

melloware avatar Sep 15 '22 16:09 melloware

One thing to note about the example above - it is in JavaScript, so the type errors around custom matchModes don't occur. FilterMatchModes.CUSTOM issue still stands, but the issues around types are exclusive to using it in a TypeScript-based project.

luketpena avatar Sep 15 '22 16:09 luketpena

yep agreed just wanted to show you what someone else had done.

melloware avatar Sep 15 '22 16:09 melloware

Just had hours wasted trying to get this to work and found this issue on StackOverflow. From what I understand @luketpena is saying, this basically cannot work in TypeScript projects at the moment. Would really appreciate an update to the docs or the callback signature to be correct. Also I don't think the component tag for this issue is correct, is marked as documentation but in TypeScript projects this feature is just plain broken.

margaretdax avatar Jul 12 '23 08:07 margaretdax

@margaretdax Can you update my Sandbox reproducer to TS to show what is not working. It will help get it fixed.

melloware avatar Jul 12 '23 13:07 melloware

Version 9 has this issue too.

lenard-a avatar Aug 02 '23 10:08 lenard-a

@lenard-a as I stated above can someone update my provided Code Sandbox to show the typescript issue?

melloware avatar Aug 02 '23 11:08 melloware

@melloware Here is the updated CodePen I just did some small changes to highlight the typescript issue. Once you type the state variable that holds the filters with DataTableFilterMeta (line 31), the matchmode in initFilters1 function displays a warning (line 70) (and it prevents successful builds).

However, if you type the state variable as 'any' it works. So it indeed is just a documentation issue.

lenard-a avatar Aug 02 '23 12:08 lenard-a

Thanks I will take a look.

melloware avatar Aug 02 '23 12:08 melloware

I thought you were supposed to use "custom" for match mode? I updated your example: https://codesandbox.io/s/vigorous-grass-qsrt7t?file=/src/demo/DataTableFilterDemo.tsx

melloware avatar Aug 02 '23 13:08 melloware

Hello, Im facing this same issue. Is there any updates on this?

juancamiloqhz avatar Aug 21 '23 21:08 juancamiloqhz

Hello, Im facing this same issue. Is there any updates on this?

@juancamiloqhz what exactly is your issue. Did you see my code sandbox example 1 post above?

melloware avatar Aug 21 '23 22:08 melloware

https://codesandbox.io/s/vigorous-grass-qsrt7t?file=/src/demo/DataTableFilterDemo.tsx

Hi @melloware,

Yes, I've tried the example. But I'm still having issues with the custom filter function. I did the same thing trying to put the custom filter function to work, but it's actually never called.

juancamiloqhz avatar Aug 21 '23 22:08 juancamiloqhz

Ok if you can put a code sandbox together showing your issue or compare your code to above?

melloware avatar Aug 21 '23 22:08 melloware

@melloware Does your codesandbox example works? Because I can see that is not data present in the table. But when I comment the name field in the initFilters function, all the data appears in the table.

juancamiloqhz avatar Aug 22 '23 15:08 juancamiloqhz

You are using this one: https://codesandbox.io/s/thirsty-cerf-944hml ??

melloware avatar Aug 22 '23 15:08 melloware

@melloware sorry I was using the other link.

Now I have the data in the table. But when I try to apply the "My Filter" custom function in the name column, I dont get the custom function to be called at all. I dont know if Im missing something, but I'm pretty sure I'm trying it the right way. Please try to console log the custom filter function and check if something is in the console: FilterService.register(FilterMatchMode.CUSTOM, (a, b) => { console.log(a, b); return a === null; });

juancamiloqhz avatar Aug 22 '23 16:08 juancamiloqhz

Yeah something looks not good. I don't use this functionality so I have never really looked into it.

melloware avatar Aug 22 '23 23:08 melloware

I ran into this issue when trying to add custom filtering to a data table, it seems filterFunction is never called the match mode is CUSTOM. Is there an alternate way of providing custom filtering? (e.g. for when the property is an enum).

hans-pragt avatar Dec 26 '23 22:12 hans-pragt

I ran into this issue when trying to add custom filtering to a data table, it seems filterFunction is never called the match mode is CUSTOM. Is there an alternate way of providing custom filtering? (e.g. for when the property is an enum).

Yes, I facing the same problem.

enmanuelmag avatar Jan 09 '24 19:01 enmanuelmag

Is there any deadline for this to get fixed, or any estimated time. @nitrogenous @gucal

Mursalin7 avatar Jan 24 '24 07:01 Mursalin7

Tips to work properly the custom filter until fixing this issue.


To apply a custom filter, the following conditions must be met.

  1. Set FilterMatchMode.CUSTOM to matchMode of the target column of the filters property in the DataTable components.
  2. Define a filterFunction using FilterService.register.
  3. The first argument of FilterService.register should be a string in the format "custom_[field]".

Note: The filterFunction prop of Column components is a trap property that does not work.

yunics-highfield avatar Feb 05 '24 11:02 yunics-highfield

@yunics-highfield is there any way you could update my Stackblitz to show a Custom Filter and then I will take your example and add it to the ShowCase for others to see!

StackBlitz: https://stackblitz.com/edit/vz6wt2?file=src%2FApp.tsx

melloware avatar Feb 05 '24 15:02 melloware

@melloware Sure. Here's the example. I hope this will help many people. I added an activity column using a custom filter.

https://stackblitz.com/edit/vz6wt2-oq6xd9?file=src%2FApp.tsx

yunics-highfield avatar Feb 05 '24 16:02 yunics-highfield

AWESOME I am going to update the showcase with this. Because a LOT of people ask this question.

melloware avatar Feb 05 '24 16:02 melloware