T
TanStack4w ago
rare-sapphire

Column Filtering: when column is an array?

Example Data:
export const data: TeamMember[] = [
{
id: "1",
src: "/user.jpg",
alt: "User",
name: "user",
description: "@user",
status: "active",
role: "Product Designer",
email: "user@example.com",
teams: ["Design", "Product", "Marketing", "Engineering"],
},
];
export const data: TeamMember[] = [
{
id: "1",
src: "/user.jpg",
alt: "User",
name: "user",
description: "@user",
status: "active",
role: "Product Designer",
email: "user@example.com",
teams: ["Design", "Product", "Marketing", "Engineering"],
},
];
I have successfully done column filtering for regular strings: status. I have a Popover with checkbox that you can show or hide columns with that value. I don't know how to handle teams which is an arrya and get all UniqueValues. Example of ColumnDef for status:
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => renderSnippet(statusCell, { row }),
filterFn: "enum",
meta: {
filterType: "enum",
},
},
{
accessorKey: "status",
header: "Status",
cell: ({ row }) => renderSnippet(statusCell, { row }),
filterFn: "enum",
meta: {
filterType: "enum",
},
},
This is my enumFilterFn, it does not work for arrays.
export const enumFilterFn = (row, columnId, filterValues: string[] | undefined) => {
if (!filterValues?.length) return true;
const cellValue = row.getValue(columnId);

if (Array.isArray(cellValue)) {
return cellValue.some((v) => filterValues.includes(v));
}

return filterValues.includes(cellValue);
};
export const enumFilterFn = (row, columnId, filterValues: string[] | undefined) => {
if (!filterValues?.length) return true;
const cellValue = row.getValue(columnId);

if (Array.isArray(cellValue)) {
return cellValue.some((v) => filterValues.includes(v));
}

return filterValues.includes(cellValue);
};
Markup: This is Svelte, but the logic basic and applies for all frameworks/lib.
{#each Array.from(column
.getFacetedUniqueValues()
.keys()) as uniqueValue}
<Checkbox
label={uniqueValue}
name={uniqueValue}
for={uniqueValue}
labelProps={{ class: "capitalize" }}
checked={(column.getFilterValue() ?? []).includes(
uniqueValue,
)}
onCheckedChange={(v) => {
const current: string[] = column.getFilterValue() ?? [];

const next = v
? [...current, uniqueValue] // add value if checked
: current.filter((val) => val !== uniqueValue); // remove if unchecked

column.setFilterValue(next.length ? next : undefined);
}}
/>
{/each}
{#each Array.from(column
.getFacetedUniqueValues()
.keys()) as uniqueValue}
<Checkbox
label={uniqueValue}
name={uniqueValue}
for={uniqueValue}
labelProps={{ class: "capitalize" }}
checked={(column.getFilterValue() ?? []).includes(
uniqueValue,
)}
onCheckedChange={(v) => {
const current: string[] = column.getFilterValue() ?? [];

const next = v
? [...current, uniqueValue] // add value if checked
: current.filter((val) => val !== uniqueValue); // remove if unchecked

column.setFilterValue(next.length ? next : undefined);
}}
/>
{/each}
1 Reply
rare-sapphire
rare-sapphireOP4w ago
The column.getFacetedUniqueValues() works for basic status column, but fails for arrays. A thought I had was to check if each unique was an array and then combine all the values from each array, create a Set an to get uniqueValues, but I feel like isn't the right way. There has to be something simpler. This is my table config.
filterFns: {
enum: enumFilterFn,
},
getFacetedUniqueValues: getFacetedUniqueValues(),
filterFns: {
enum: enumFilterFn,
},
getFacetedUniqueValues: getFacetedUniqueValues(),
I add on meta an attribute filterType to render correct markup. I think there is a way to make my enum case to handle arrays instead of creating an enum-array type. Maybe some way to pass a custom getFacetedUniqueValues function for my array column? This is solved

Did you find this page helpful?