Skip to content

Commit

Permalink
feat: add filter function to column headers (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
katharinawuensche committed Nov 5, 2024
1 parent 0a6ae86 commit 89df575
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 1 deletion.
38 changes: 38 additions & 0 deletions components/data-table/data-table-faceted-filter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<script setup lang="ts">
import type { Column } from "@tanstack/vue-table";
import { Filter } from "lucide-vue-next";
const props = defineProps<{
column: Column<never, unknown>;
}>();
const facets = computed(() => props.column?.getFacetedUniqueValues());
const selectedValues = computed(() => new Set(props.column?.getFilterValue() as Array<string>));
</script>

<template>
<DropdownMenu>
<DropdownMenuTrigger class="group p-1 align-middle"
><Filter class="size-4 group-hover:scale-125"></Filter
></DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuCheckboxItem
v-for="facet in facets"
:key="facet[0]"
:checked="selectedValues.has(facet[0])"
@update:checked="
(checked) => {
if (!checked) {
selectedValues.delete(facet[0]);
} else {
selectedValues.add(facet[0]);
}
column?.setFilterValue([...selectedValues]);
}
"
>
{{ facet[0] }}
<Badge class="ml-2" variant="outline">{{ facet[1] }}</Badge>
</DropdownMenuCheckboxItem>
</DropdownMenuContent>
</DropdownMenu>
</template>
11 changes: 11 additions & 0 deletions components/data-table/data-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ import {
type ColumnFiltersState,
FlexRender,
getCoreRowModel,
getFacetedRowModel,
getFilteredRowModel,
getPaginationRowModel,
useVueTable,
} from "@tanstack/vue-table";
import customFacetedUniqueValues from "@/utils/customFacetedUniqueValues";
const emit = defineEmits(["table-ready", "columnFiltersChange", "globalFilterChange"]);
interface Props {
items: Array<never>;
columns: Array<ColumnDef<never>>;
minHeaderDepth?: number;
enableFilterOnColumns?: boolean;
}
const props = defineProps<Props>();
Expand Down Expand Up @@ -63,6 +67,8 @@ const table = useVueTable({
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: customFacetedUniqueValues,
});
onMounted(() => {
Expand All @@ -78,9 +84,14 @@ onMounted(() => {
.getHeaderGroups()
.filter((header) => header.depth >= (props.minHeaderDepth ?? 0))"
:key="headerGroup.id"
class="hover:bg-primary"
>
<TableHead v-for="header in headerGroup.headers" :key="header.id">
{{ header.column.columnDef.header }}
<DataTableFacetedFilter
v-if="enableFilterOnColumns"
:column="header.column"
></DataTableFacetedFilter>
</TableHead>
</TableRow>
</TableHeader>
Expand Down
2 changes: 1 addition & 1 deletion components/geo-map.client.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const addNearbyDataPopup = function (marker: LeafletMarker) {
if (nearbyMarkerData.length > 1) {
const markers = nearbyMarkerData.sort((a, b) => {
return a.properties!.label.localeCompare(b.properties!.label);
return a.properties!.label?.localeCompare(b.properties!.label);
});
// @todo determine whether grouping is needed based on the number of
Expand Down
1 change: 1 addition & 0 deletions components/geojson-table-window-content.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const columns = computed(() => {
);
},
filterFn: (row, columnId, filterValue) => {
if (Object.keys(filterValue).length === 0) return true;
const filter = Object.values(filterValue).some((val) =>
(row.getValue(columnId) as Array<string>).includes(String(val)),
);
Expand Down
37 changes: 37 additions & 0 deletions utils/customFacetedUniqueValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { memo, type Table } from "@tanstack/vue-table";

const customFacetedUniqueValues = (table: Table<never>, columnId: string) => {
return memo(
() => [table.getColumn(columnId)?.getFacetedRowModel()],
(facetedRowModel) => {
if (!facetedRowModel) return new Map();

const facetedUniqueValues = new Map<unknown, number>();

for (const row of facetedRowModel.flatRows) {
const values = row.getUniqueValues<number>(columnId);

for (const val of values) {
let wrappedValue = [val];
if (Array.isArray(val)) {
wrappedValue = val;
}
for (const value of wrappedValue) {
if (facetedUniqueValues.has(value)) {
facetedUniqueValues.set(value, (facetedUniqueValues.get(value) ?? 0) + 1);
} else {
facetedUniqueValues.set(value, 1);
}
}
}
}

return facetedUniqueValues;
},
{
key: `getFacetedUniqueValues_${columnId}`,
},
);
};

export default customFacetedUniqueValues;

0 comments on commit 89df575

Please sign in to comment.