refine icon indicating copy to clipboard operation
refine copied to clipboard

[FEAT] Draft: Add support to switch filter operator dynamically from useTable

Open IgnusG opened this issue 2 years ago • 3 comments

Is your feature request related to a problem? Please describe. Currently it is only possible to set the filter operator on the initial call to useTable. This suggestion would allow switching between full string filter (eq), negation (ne) or partial string match/not match (contains/ncontains).

Operators are set here initially: https://github.com/pankod/refine/blob/445baad768c51fc0c734ddf179402de2664ef471/packages/core/src/hooks/table/useTable/useTable.ts#L144-L146

The filter value can be changed but not the operator: https://github.com/pankod/refine/blob/445baad768c51fc0c734ddf179402de2664ef471/packages/core/src/hooks/table/useTable/useTable.ts#L198-L211

Describe the solution you'd like

  • Allow <FilterDropdown> changing the operator through props

    • Breaking change?

    • Would antd even allow this for filter?

      <Table.Column 
          dataIndex="contentName"
          filterDropdown={({ dropdownProps, filterOperatorProps }) => { // Would something like this even work?
              return (
                  <Fragment>
                      <Select onChange={filterOperatorProps.onChange}>
                          <Select.Option value="eq">Equals</Select.Option>
                          <Select.Option value="ne">Not Equal</Select.Option>
                      </Select>
                      <FilterDropdown {...dropdownProps}><Input /></FilterDropdown>
                  </Fragment>
              )
          }}
      />
      
  • Export a helper method from useTable, something like changeFilterOperator(forField: string, newOperator: CrudOperators) which could be hooked up manually

    • More work for the developer to hook it up but not breaking

    • Supports changing the filter outside the dropdown too which is cool

    • The operator change input field/select would most likely already be inside of the dropdownFilter render prop of a column so specifying the column name/field again seems redundant

       const { changeFilterOperator, ...tableProps } = useTable({});
      
       ...
      
       useEffect(() => {
           changeFilterOperator("contentName", "contains"); // We can change the filter operator outside of the dropdown
           // Maybe even the value itself with a slightly different signature
           // changeFilter("contentName", "contains", someWeirdValue);
       }, [someWeirdValue])
      
      <Table.Column 
          dataIndex="contentName" // First column specification
          filterDropdown={(props) => {
              return (
                  <Fragment>
                      <Select onChange={(newOp) => changeFilterOperator("contentName", newOp)}> // "contentName" must be specified here again
                          <Select.Option value="eq">Equals</Select.Option>
                          <Select.Option value="ne">Equals</Select.Option>
                      </Select>
                      <FilterDropdown {...props}><Input /></FilterDropdown>
                  </Fragment>
              )
          }}
      />
      

Work in Progress

Describe alternatives you've considered

  • Making the initially passed options to useTable dynamic so changing them changes the filters state
    • Unintuitive since it behaves differently than react hooks
    • Would overwrite user input or developer would have to merge in current filter input themselves
    • The name of the option is initialFilters not filters - it's not intuitive that changing these should result in updates

IgnusG avatar Dec 17 '21 22:12 IgnusG

Hey @IgnusG , Thank you for your great effort. If I remember correctly, this can be achieved with the operator given as initialFilter. Wouldn't such complex filters be easier to do with an external Form? What do you think?

Table Filter Form example, https://refine.dev/docs/examples/table/tableFilter/

omeraplak avatar Dec 21 '21 11:12 omeraplak

You are right @omeraplak that giving the operator to initialFilter can change it - but just initially.

My use case was however to switch between filter equals and not equals (and also switching between match exactly and match partially) for strings similar to this Airtable UI component:

image

This is already possible by adding a select field or checkbox to renderDropdownFilter (or in an external filter component like the one you linked to), but the problem is useTable does not allow to change the filter operator dynamically (because it does not offer a method to do so). The change in #1375 is very simple but already versatile enough to achieve this behaviour.

I'll try to create a proof of concept with a patched version of refine to showcase what I had in mind (using #1375 as a baseline).

If a developer wanted to support this themselves they would effectively have to write a custom copy of the useTable hook that exposes some way to change the filter operators I think.

IgnusG avatar Dec 21 '21 12:12 IgnusG

Yes, you are right, there is definitely a need for improvement here. We look forward to it! Thanks a lot

omeraplak avatar Dec 21 '21 12:12 omeraplak

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Feb 21 '23 08:02 stale[bot]

So what's the best way to do it? What I want is to use a fixed operator, like "contains" rather than "eq" for the filter.

dzcpy avatar May 26 '23 04:05 dzcpy