Skip to content

Commit a84475b

Browse files
feat: refactor features option to include row models and fns (#6318)
* feat: refactor features option to include row models and fns * ci: apply automated fixes * fix column/global filtering feature relationship in types * fix TData in custom filterFns --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 1022914 commit a84475b

698 files changed

Lines changed: 7414 additions & 6961 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/devtools.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ The devtools identify each table by the `key` table option. Registration require
6161
const table = useTable({
6262
key: 'users-table', // needed for devtools, omit if you don't want to use the devtools
6363
features,
64-
rowModels: {},
6564
columns,
6665
data,
6766
})

docs/framework/angular/guide/column-faceting.md

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,21 @@ Want to skip to the implementation? Check out these Angular examples:
1414
import { signal } from '@angular/core'
1515
import { injectTable, tableFeatures, columnFacetingFeature, columnFilteringFeature, createFacetedRowModel, createFacetedUniqueValues, createFacetedMinMaxValues, createFilteredRowModel, filterFns } from '@tanstack/angular-table'
1616

17-
const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })
17+
const features = tableFeatures({
18+
columnFacetingFeature,
19+
columnFilteringFeature,
20+
filteredRowModel: createFilteredRowModel(),
21+
facetedRowModel: createFacetedRowModel(),
22+
facetedUniqueValues: createFacetedUniqueValues(),
23+
facetedMinMaxValues: createFacetedMinMaxValues(),
24+
filterFns,
25+
})
1826

1927
export class App {
2028
readonly data = signal(defaultData)
2129

2230
readonly table = injectTable(() => ({
2331
features,
24-
rowModels: {
25-
filteredRowModel: createFilteredRowModel(filterFns),
26-
facetedRowModel: createFacetedRowModel(),
27-
facetedUniqueValues: createFacetedUniqueValues(),
28-
facetedMinMaxValues: createFacetedMinMaxValues(),
29-
},
3032
columns,
3133
data: this.data(),
3234
}))
@@ -39,7 +41,7 @@ Faceting is a feature that generates lists of values from your table's data, eit
3941

4042
### Column Faceting Row Models
4143

42-
In order to use any of the column faceting features, add the `columnFacetingFeature` to your features and the appropriate faceted row models to `rowModels`. Faceting exists to power filter UIs, so in practice you will also register the `columnFilteringFeature` and a `filteredRowModel`. Without a filtered row model, the faceted row models fall back to the pre-filtered rows and the facet values will not react to other columns' filters.
44+
In order to use any of the column faceting features, add the `columnFacetingFeature` and the appropriate faceted row model factories to your features. Faceting exists to power filter UIs, so in practice you will also register the `columnFilteringFeature` and a `filteredRowModel`. Without a filtered row model, the faceted row models fall back to the pre-filtered rows and the facet values will not react to other columns' filters.
4345

4446
```ts
4547
import {
@@ -54,16 +56,18 @@ import {
5456
filterFns,
5557
} from '@tanstack/angular-table'
5658

57-
const features = tableFeatures({ columnFacetingFeature, columnFilteringFeature })
59+
const features = tableFeatures({
60+
columnFacetingFeature,
61+
columnFilteringFeature,
62+
filteredRowModel: createFilteredRowModel(), // facet values react to other columns' filters
63+
facetedRowModel: createFacetedRowModel(), // required for faceting (other faceted row models depend on this)
64+
facetedMinMaxValues: createFacetedMinMaxValues(), // if you need min/max values
65+
facetedUniqueValues: createFacetedUniqueValues(), // if you need a list of unique values
66+
filterFns,
67+
})
5868

5969
readonly table = injectTable(() => ({
6070
features,
61-
rowModels: {
62-
filteredRowModel: createFilteredRowModel(filterFns), // facet values react to other columns' filters
63-
facetedRowModel: createFacetedRowModel(), // required for faceting (other faceted row models depend on this)
64-
facetedMinMaxValues: createFacetedMinMaxValues(), // if you need min/max values
65-
facetedUniqueValues: createFacetedUniqueValues(), // if you need a list of unique values
66-
},
6771
columns,
6872
data,
6973
}))
@@ -113,39 +117,46 @@ const [min, max] = table.getGlobalFacetedMinMaxValues() ?? [0, 1];
113117

114118
### Custom (Server-Side) Faceting
115119

116-
Instead of using the built-in client-side faceting features, you can implement your own faceting logic on the server-side and pass the faceted values to the client-side. Supply custom `rowModels.facetedUniqueValues` and `rowModels.facetedMinMaxValues` factories. Each factory receives the table and a column ID and returns a thunk that resolves the faceted values. The column instance APIs (`column.getFacetedUniqueValues()` and `column.getFacetedMinMaxValues()`) will then return your server-provided values.
120+
Instead of using the built-in client-side faceting features, you can implement your own faceting logic on the server-side and pass the faceted values to the client-side. Supply custom `facetedUniqueValues` and `facetedMinMaxValues` factories in the `features` object. Each factory receives the table and a column ID and returns a thunk that resolves the faceted values. The column instance APIs (`column.getFacetedUniqueValues()` and `column.getFacetedMinMaxValues()`) will then return your server-provided values.
117121

118122
```ts
119123
readonly facetingQuery = injectQuery(() => ({
120124
//...
121125
}))
122126

127+
const features = tableFeatures({
128+
columnFacetingFeature,
129+
columnFilteringFeature,
130+
facetedUniqueValues: (_table, columnId) => () => {
131+
const uniqueValueMap = new Map<string, number>()
132+
//... populate from facetingQuery data for this columnId
133+
return uniqueValueMap
134+
},
135+
facetedMinMaxValues: (_table, columnId) => () => {
136+
//... read from facetingQuery data for this columnId
137+
return [min, max]
138+
},
139+
})
140+
123141
readonly table = injectTable(() => ({
124142
features,
125-
rowModels: {
126-
facetedUniqueValues: (_table, columnId) => () => {
127-
const uniqueValueMap = new Map<string, number>()
128-
//... populate from facetingQuery data for this columnId
129-
return uniqueValueMap
130-
},
131-
facetedMinMaxValues: (_table, columnId) => () => {
132-
//... read from facetingQuery data for this columnId
133-
return [min, max]
134-
},
135-
},
136143
columns,
137144
data,
138145
//...
139146
}))
140147
```
141148

142-
The same factories also serve global faceting. Global faceting requests values with the internal `__global__` column ID, so you can branch on it inside the same `facetedUniqueValues` and `facetedMinMaxValues` factories to return table-wide facet values:
149+
The same factories also serve global faceting. Global faceting requests values with the internal `__global__` column ID, so you can branch on it inside the same `facetedUniqueValues` and `facetedMinMaxValues` factory functions to return table-wide facet values:
143150

144151
```ts
145-
facetedUniqueValues: (_table, columnId) => () => {
146-
if (columnId !== '__global__') return new Map() // per-column facets
147-
return new Map(globalFacets.uniqueValues) // global facets
148-
},
152+
const features = tableFeatures({
153+
columnFacetingFeature,
154+
columnFilteringFeature,
155+
facetedUniqueValues: (_table, columnId) => () => {
156+
if (columnId !== '__global__') return new Map() // per-column facets
157+
return new Map(globalFacets.uniqueValues) // global facets
158+
},
159+
})
149160
```
150161

151162
Alternatively, you don't have to put any of your faceting logic through the TanStack Table APIs at all. Just fetch your lists and pass them to your filter components directly.

docs/framework/angular/guide/column-filtering.md

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ Want to skip to the implementation? Check out these Angular examples:
1616
import { signal } from '@angular/core'
1717
import { injectTable, tableFeatures, columnFilteringFeature, createFilteredRowModel, filterFns } from '@tanstack/angular-table'
1818

19-
const features = tableFeatures({ columnFilteringFeature })
19+
const features = tableFeatures({
20+
columnFilteringFeature,
21+
filteredRowModel: createFilteredRowModel(),
22+
filterFns,
23+
})
2024

2125
export class App {
2226
readonly data = signal(defaultData)
2327

2428
readonly table = injectTable(() => ({
2529
features,
26-
rowModels: {
27-
filteredRowModel: createFilteredRowModel(filterFns),
28-
},
2930
columns,
3031
data: this.data(),
3132
}))
@@ -60,14 +61,13 @@ If you're not sure, you can always start with client-side filtering and paginati
6061

6162
If you have decided that you need to implement server-side filtering instead of using the built-in client-side filtering, here's how you do that.
6263

63-
No `filteredRowModel` is needed for manual server-side filtering. Instead, the `data` that you pass to the table should already be filtered. However, if you have added a `filteredRowModel` to `rowModels`, you can tell the table to skip it by setting the `manualFiltering` option to `true`.
64+
No `filteredRowModel` is needed for manual server-side filtering. Instead, the `data` that you pass to the table should already be filtered. However, if you have added a `filteredRowModel` to features, you can tell the table to skip it by setting the `manualFiltering` option to `true`.
6465

6566
```ts
6667
const features = tableFeatures({ columnFilteringFeature })
6768

6869
readonly table = injectTable(() => ({
6970
features,
70-
rowModels: {}, // no filteredRowModel needed for manual server-side filtering
7171
data,
7272
columns,
7373
manualFiltering: true,
@@ -78,7 +78,7 @@ readonly table = injectTable(() => ({
7878
7979
### Client-Side Filtering
8080

81-
If you are using the built-in client-side filtering features, add the `columnFilteringFeature` to your features and the `filteredRowModel` to your row models. Import `createFilteredRowModel` and `filterFns` from TanStack Table:
81+
If you are using the built-in client-side filtering features, add the `columnFilteringFeature` and the `filteredRowModel` factory to your features. Import `createFilteredRowModel` and `filterFns` from TanStack Table:
8282

8383
```ts
8484
import {
@@ -89,13 +89,14 @@ import {
8989
filterFns,
9090
} from '@tanstack/angular-table'
9191

92-
const features = tableFeatures({ columnFilteringFeature })
92+
const features = tableFeatures({
93+
columnFilteringFeature,
94+
filteredRowModel: createFilteredRowModel(),
95+
filterFns,
96+
})
9397

9498
readonly table = injectTable(() => ({
9599
features,
96-
rowModels: {
97-
filteredRowModel: createFilteredRowModel(filterFns),
98-
},
99100
data,
100101
columns,
101102
}))
@@ -124,7 +125,6 @@ You can access the column filter state from the table instance with `table.atoms
124125
```ts
125126
readonly table = injectTable(() => ({
126127
features,
127-
rowModels: { filteredRowModel: createFilteredRowModel(filterFns) },
128128
columns,
129129
data,
130130
//...
@@ -148,7 +148,6 @@ export class App {
148148

149149
readonly table = injectTable(() => ({
150150
features,
151-
rowModels: { filteredRowModel: createFilteredRowModel(filterFns) },
152151
columns,
153152
data: this.data(),
154153
//...
@@ -169,7 +168,6 @@ readonly columnFilters = signal<ColumnFiltersState>([])
169168
//...
170169
readonly table = injectTable(() => ({
171170
features,
172-
rowModels: { filteredRowModel: createFilteredRowModel(filterFns) },
173171
columns,
174172
data: this.data(),
175173
//...
@@ -190,7 +188,6 @@ If you do not need to control the column filter state in your own state manageme
190188
```ts
191189
readonly table = injectTable(() => ({
192190
features,
193-
rowModels: { filteredRowModel: createFilteredRowModel(filterFns) },
194191
columns,
195192
data,
196193
//...
@@ -278,33 +275,26 @@ const columns = [
278275
}
279276
]
280277
//...
278+
const features = tableFeatures({
279+
columnFilteringFeature,
280+
filteredRowModel: createFilteredRowModel(),
281+
filterFns: {
282+
...filterFns,
283+
myCustomFilterFn: (row, columnId, filterValue) => {
284+
return // true or false based on your custom logic
285+
},
286+
startsWith: startsWithFilterFn, // defined elsewhere
287+
},
288+
})
289+
281290
readonly table = injectTable(() => ({
282291
features,
283-
rowModels: {
284-
filteredRowModel: createFilteredRowModel({
285-
...filterFns,
286-
myCustomFilterFn: (row, columnId, filterValue) => {
287-
return // true or false based on your custom logic
288-
},
289-
startsWith: startsWithFilterFn, // defined elsewhere
290-
}),
291-
},
292292
columns,
293293
data,
294294
}))
295295
```
296296

297-
> **TypeScript Note:** For `filterFn: 'myCustomFilterFn'` string references to typecheck, augment the `FilterFns` interface with a `declare module` block:
298-
>
299-
> ```ts
300-
> declare module '@tanstack/angular-table' {
301-
> interface FilterFns {
302-
> myCustomFilterFn: FilterFn<typeof features, MyData>
303-
> }
304-
> }
305-
> ```
306-
>
307-
> Alternatively, skip the registry and the augmentation entirely by passing the function directly to the `filterFn` column option. See the [Fuzzy Search example](../examples/filters-fuzzy) for a complete registration with module augmentation.
297+
> **TypeScript Note:** For `filterFn: 'myCustomFilterFn'` string references to typecheck, register the function in the `filterFns` slot on `tableFeatures` (as shown above). Alternatively, skip the registry entirely by passing the function directly to the `filterFn` column option. See the [Fuzzy Search example](../examples/filters-fuzzy) for a complete registration example.
308298
309299
##### Customize Filter Function Behavior
310300

@@ -356,7 +346,6 @@ const columns = [
356346
//...
357347
readonly table = injectTable(() => ({
358348
features,
359-
rowModels: { filteredRowModel: createFilteredRowModel(filterFns) },
360349
columns,
361350
data,
362351
enableColumnFilters: false, // disable column filtering for all columns
@@ -374,14 +363,16 @@ By default, filtering is done from parent rows down, so if a parent row is filte
374363
However, if you want to allow sub-rows to be filtered and searched through, regardless of whether the parent row is filtered out, you can set the `filterFromLeafRows` table option to `true`. Setting this option to `true` will cause filtering to be done from leaf rows up, which means parent rows will be included so long as one of their child or grand-child rows is also included.
375364

376365
```ts
377-
const features = tableFeatures({ columnFilteringFeature, rowExpandingFeature })
366+
const features = tableFeatures({
367+
columnFilteringFeature,
368+
rowExpandingFeature,
369+
filteredRowModel: createFilteredRowModel(),
370+
expandedRowModel: createExpandedRowModel(),
371+
filterFns,
372+
})
378373

379374
readonly table = injectTable(() => ({
380375
features,
381-
rowModels: {
382-
filteredRowModel: createFilteredRowModel(filterFns),
383-
expandedRowModel: createExpandedRowModel(),
384-
},
385376
columns,
386377
data,
387378
filterFromLeafRows: true, // filter and search through sub-rows
@@ -395,14 +386,16 @@ By default, filtering is done for all rows in a tree, no matter if they are root
395386
Use `maxLeafRowFilterDepth: 0` if you want to preserve a parent row's sub-rows from being filtered out while the parent row is passing the filter.
396387

397388
```ts
398-
const features = tableFeatures({ columnFilteringFeature, rowExpandingFeature })
389+
const features = tableFeatures({
390+
columnFilteringFeature,
391+
rowExpandingFeature,
392+
filteredRowModel: createFilteredRowModel(),
393+
expandedRowModel: createExpandedRowModel(),
394+
filterFns,
395+
})
399396

400397
readonly table = injectTable(() => ({
401398
features,
402-
rowModels: {
403-
filteredRowModel: createFilteredRowModel(filterFns),
404-
expandedRowModel: createExpandedRowModel(),
405-
},
406399
columns,
407400
data,
408401
maxLeafRowFilterDepth: 0, // only filter root level parent rows out

docs/framework/angular/guide/column-ordering.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export class App {
2121

2222
readonly table = injectTable(() => ({
2323
features,
24-
rowModels: {},
2524
columns,
2625
data: this.data(),
2726
}))
@@ -55,7 +54,6 @@ const features = tableFeatures({ columnOrderingFeature })
5554

5655
readonly table = injectTable(() => ({
5756
features,
58-
rowModels: {},
5957
//...
6058
initialState: {
6159
columnOrder: ['columnId1', 'columnId2', 'columnId3'],
@@ -88,7 +86,6 @@ export class App {
8886

8987
readonly table = injectTable(() => ({
9088
features,
91-
rowModels: {},
9289
//...
9390
atoms: {
9491
columnOrder: this.columnOrderAtom,
@@ -109,7 +106,6 @@ readonly columnOrder = signal<ColumnOrderState>(['columnId1', 'columnId2', 'colu
109106
//...
110107
readonly table = injectTable(() => ({
111108
features,
112-
rowModels: {},
113109
//...
114110
state: {
115111
columnOrder: this.columnOrder(),
@@ -138,7 +134,6 @@ const features = tableFeatures({ columnOrderingFeature })
138134
export class App {
139135
readonly table = injectTable(() => ({
140136
features,
141-
rowModels: {},
142137
columns,
143138
data: this.data(),
144139
initialState: {

0 commit comments

Comments
 (0)