4

I am trying to implement server-side column filtering in TanStack Table (React-Table V8). The problem is that I don't know how to convert the ColumnFiltersState object to the right format for the backend. My backend uses nestjs-paginate which uses the following operators: $eq, $not, $null, $in, $gt, $gte, $lt, $lte, $btw, $ilike for filtering based on the query. The ColumnFiltersState contains a value field, which is of type unknown, and the value it contains will depend on the filter component being used, I plan to use select, date inputs, range inputs for filtering. Also, some fields can be filtered as 'contains', 'equals' etc.

Additionally, another problem is that I need to support both client-side and server-side column filtering depending on the manualFiltering prop passed to my custom table component.

Here is a piece of code from my UsersList component which use my custom table:

...
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
    [],
  );

  const { data, isFetching, isLoading, isSuccess, isError } = useGetUsersQuery({
    search: globalFilter,
    page: pageIndex + 1,
    limit: pageSize,
    sortBy: sorting.map((s) => `${s.id}:${s.desc ? 'DESC' : 'ASC'}`).join(','),
    columnFilters: columnFilters.map((columnFilter) => { // Here is the problem
      ...
      return {
        column: columnFilter.id,
        filter: {
          operator: ...,
          value: ...,
        },
      };
    }),
  });
...

So then I can send it to the server in the needed format:

// user.api.ts
...
query: ({ search, page, limit, sortBy, columnFilters }) => {
        const params: any = {
          page,
          limit,
          search,
          sortBy,
        };


        // example query URL with filters:
        // http://localhost:3000/cats?filter.age=$gte:3

        if (columnFilters) {
          columnFilters.forEach(({ column, filter: { operator, value } }) => {
            params[`filter.${column}`] = `${operator}:${value}`;
          });
        }

        return {
          url: 'users/',
          params,
        };
      },
...

Here are the nestjs-paginate types:

// Available filter operators:
export enum FilterOperator {
  EQ = '$eq',
  GT = '$gt',
  GTE = '$gte',
  IN = '$in',
  NULL = '$null',
  LT = '$lt',
  LTE = '$lte',
  BTW = '$btw',
  NOT = '$not',
  ILIKE = '$ilike',
}

// Return data type from the backend
export interface Paginated<T> {
  data: T[];
  meta: {
    itemsPerPage: number;
    totalItems: number;
    currentPage: number;
    totalPages: number;
    sortBy: SortBy<T>;
    searchBy: Column<T>[];
    search: string;
    filter?: {
      [column: string]: string | string[];
    };
  };
  links: {
    first?: string;
    previous?: string;
    current: string;
    next?: string;
    last?: string;
  };
}

A possible solution is to add a custom prop to ColumnMeta by which it will be possible to determine which filtering operator to use, but then I don’t know how to do it correctly or maybe I could determine it using the built-in solutions. I would appreciate any help and ideas .

monotype
  • 217
  • 2
  • 10
  • Did you find any solution? (without using custom hooks) – Saad Abdullah Jan 17 '23 at 09:04
  • 1
    @SaadAbdullah A possible solution is to use the "filterFn" property for each column and pass in the filter operator with the value, or use a separate mapping function that maps the "ColumnFiltersState" to the backend format using the appropriate filter operator and value for each column. Another option is to add a custom meta prop to the "columnDef" to specify the filter operator. But I did not find a specific example of a solution. I like how the filters are looks here: https://codesandbox.io/s/react-table-datagrid-eojw8 or https://mantine-react-table-storybook.vercel.app – monotype Jan 17 '23 at 11:57
  • Yeah. There is no nice way to get filter operator but I was able to get the operators using custom method as well. – Saad Abdullah Jan 18 '23 at 09:23
  • @SaadAbdullah Currently, there are limited examples and creating UI, as well as implementing server-side filtering, can be difficult tasks. I had initially considered using cmdk to create a UI (similar to Linear.app), but it has proven to be too complex for me at this time. It may be more appropriate to have basic filters built-in within the table component, as seen in the examples I provided, and have more complex filters added as separate components. I will attempt to implement it using the examples provided but would appreciate it if someone could provide a code example for reference. – monotype Jan 18 '23 at 09:42
  • And it's still not clear to me how to correctly format the column filter state into the correct format for the backend if it uses the filter operators that I specified in the question. I hope someone can help answer all these questions :D – monotype Jan 18 '23 at 09:44

0 Answers0