Skip to content

Commit 5af2a3d

Browse files
committed
[Doc] Document <FilterValue>
1 parent 619c987 commit 5af2a3d

File tree

2 files changed

+232
-2
lines changed

2 files changed

+232
-2
lines changed

docs/FilterValue.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
---
2+
layout: default
3+
title: "The FilterValue Component"
4+
---
5+
6+
# `<FilterValue>`
7+
8+
`<FilterValue>` is an [Enterprise Edition](https://react-admin-ee.marmelab.com)<img class="icon" src="./img/premium.svg" alt="React Admin Enterprise Edition icon" /> component that displays the active filters as MUI Chips. Usually combined with [`<StackedFilters>`](./StackedFilters.md). It must be used inside a react-admin [`<List>`](./List.md).
9+
10+
![FilterValue](https://react-admin-ee.marmelab.com/assets/FilterValue.png)
11+
12+
## Usage
13+
14+
Put `<FilterValue>` inside the `<List>` actions, for instance in a custom toolbar. Define how each filter should be displayed by adding `<FilterValue.Field>` children.
15+
16+
{% raw %}
17+
```tsx
18+
import {
19+
BooleanField,
20+
CreateButton,
21+
DataTable,
22+
List,
23+
ReferenceArrayField,
24+
TopToolbar,
25+
} from 'react-admin';
26+
import {
27+
FilterValue,
28+
StackedFilters,
29+
FiltersConfig,
30+
booleanFilter,
31+
choicesArrayFilter,
32+
dateFilter,
33+
numberFilter,
34+
referenceFilter,
35+
textFilter,
36+
} from '@react-admin/ra-form-layout';
37+
38+
const postListFilters: FiltersConfig = {
39+
id: textFilter({ operators: ['eq', 'neq'] }),
40+
title: textFilter(),
41+
published_at: dateFilter(),
42+
is_public: booleanFilter(),
43+
tags: choicesArrayFilter({
44+
choices: [
45+
{ id: 'solid', name: 'Solid' },
46+
{ id: 'react', name: 'React' },
47+
{ id: 'vue', name: 'Vue' },
48+
{ id: 'programming', name: 'Programming' },
49+
],
50+
}),
51+
};
52+
53+
const PostListToolbar = () => (
54+
<TopToolbar sx={{ flex: 1 }}>
55+
<FilterValue sx={{ flex: 1 }}>
56+
<FilterValue.Field source="id" />
57+
<FilterValue.Field source="title" />
58+
<FilterValue.Field source="published_at" field={DateField} />
59+
<FilterValue.Field source="is_public" field={BooleanField} />
60+
<FilterValue.Field source="tags" field={TextArrayField} />
61+
</FilterValue>
62+
<CreateButton />
63+
<StackedFilters config={PostListFilters} />
64+
</TopToolbar>
65+
);
66+
67+
const PostList = () => (
68+
<List actions={<PostListToolbar />}>
69+
<DataTable>
70+
<DataTable.Col source="title" />
71+
<DataTable.NumberCol source="views" />
72+
<DataTable.Col source="tag_ids">
73+
<ReferenceArrayField tags="tags" source="tag_ids" />
74+
</DataTable.Col>
75+
<DataTable.Col source="published" field={BooleanField} />
76+
</DataTable>
77+
</List>
78+
);
79+
```
80+
{% endraw %}
81+
82+
## Props
83+
84+
| Prop | Required | Type | Default | Description |
85+
| ----------- | -------- | --------- | ------- | ------------------------------- |
86+
| `children` | Required | ReactNode | - | The `<FilterValue.Field>` children defining how each filter should be displayed. |
87+
| `operators` | Optional | string[] | All | The list of accepted operators. |
88+
89+
Additional props are passed to the underlying MUI [`<Stack>`](https://mui.com/material-ui/react-stack/) component.
90+
91+
## `children`
92+
93+
By default, `<FilterValue>` does not display any filter. You must pass [`<FilterValue.Field>`](#filtervaluefield) children to define how each filter should be displayed.
94+
95+
Foe instance, to display filters on the `firstName` and `age` fields:
96+
97+
```tsx
98+
<FilterValue direction="row" spacing={2}>
99+
<FilterValue.Field source="firstName" />
100+
<FilterValue.Field source="age" />
101+
</FilterValue>
102+
```
103+
104+
`<FilterValue.Field>` must be given a `source` prop, which is the name of the field to display. One `<FilterValue.Field>` may render multiple chips, for instance when the user has applied two filters on the same field with different operators (e.g. `age_gt=18` and `age_lt=60`).
105+
106+
As for the filter value, it renders as text by default, but you can customize its formatting by using one of the following props:
107+
108+
- `field`: A react-admin field component (e.g. `DateField`, `NumberField`, etc.) to use to display the filter value.
109+
110+
```tsx
111+
<FilterValue.Field source="age" field={NumberField} />
112+
```
113+
114+
- `children`: The field element to use to display the filter value, passed as a child.
115+
116+
```tsx
117+
<FilterValue.Field source="userId" label="User">
118+
<ReferenceField source="userId" reference="users" />
119+
</FilterValue.Field>
120+
```
121+
122+
- `render`: A function to render the filter. It receives an object with `source`, `operator`, and `value` properties.
123+
124+
```tsx
125+
<FilterValue.Field source="age" render={({ record, operator, label }) => {
126+
if (operator === 'gte') return <>{label}: {record.age} or older</>;
127+
if (operator === 'lte') return <>{label}: {record.age} or younger</>;
128+
return <>{label} = {record.age}</>;
129+
}} />
130+
```
131+
132+
Check the [`<FilterValue.Field>`](#filtervaluefield) section below for more details.
133+
134+
## `operators`
135+
136+
`<FilterValue>` needs to distinguish operators from field names containing the `_` symbol. By default, it handles all the operators added by the [`<StackedFilters>` Filter Configuration Builders](#filter-configuration-builders): `eq`, `neq`, `eq_any`, `neq_any`, `gt`, `gte`, `lt`, `lte`, `q`, `inc`, `inc_any`, `ninc_any`.
137+
138+
If your filters use other operators, or if you want to restrict the list of accepted operators, you can pass an `operators` prop to customize the list of accepted operators.
139+
140+
```tsx
141+
<FilterValue direction="row" spacing={2} operators={['eq', 'neq', 'lt', 'gt']} />
142+
```
143+
144+
## `<FilterValue.Field>`
145+
146+
Children of `<FilterValue>`, these components define how each filter should be displayed.
147+
148+
### Usage
149+
150+
Pass a source prop, and optionally a `field` component if you want to customize the display of the filter value. You can also pass the desired component as `children` or via a `render` prop.
151+
152+
```tsx
153+
<FilterValue>
154+
<FilterValue.Field source="firstName" />
155+
<FilterValue.Field source="age" field={NumberField} />
156+
<FilterValue.Field source="userId" label="User">
157+
<ReferenceField source="userId" reference="users" />
158+
</FilterValue.Field>
159+
<FilterValue.Field source="sex">
160+
<SelectField source="sex" choices={choices} />
161+
</FilterValue.Field>
162+
<FilterValue.Field source="age" render={({ record, operator, label }) => {
163+
if (operator === 'gte') return <>{label}: {record.age} or older</>;
164+
if (operator === 'lte') return <>{label}: {record.age} or younger</>;
165+
return <>{label} = {record.age}</>;
166+
}} />
167+
</FilterValue>
168+
```
169+
170+
### Props
171+
172+
| Prop | Required | Type | Default | Description |
173+
| ---------- | ------------- | ------------ | ----------- | --------------------------------------------------------------------------- |
174+
| `source` | Required | string | - | The source of the filter to display. |
175+
| `children` | Optional | ReactNode | - | The field component to use to display the filter value. |
176+
| `disableDelete` | Optional | boolean | false | If true, the user won't be able to remove this filter. |
177+
| `field` | Optional | ReactElement | `TextField` | The field component to use to display the filter value. |
178+
| `label` | Optional | string | - | The label to display for the filter. If not provided, it will be inferred from the source. |
179+
| `render` | Optional | function | - | A function to render the filter. It receives an object with `source`, `operator`, and `value` properties. |
180+
|`sx` | Optional | Object | - | An object containing the MUI style overrides to apply to the Chip component |
181+
182+
Additional props are passed to the underlying MUI [`<Chip>`](https://mui.com/material-ui/react-chip/) component.
183+
184+
### I18n
185+
186+
`<FilterValue.Field>` uses translation messages for fields and operators, so you can leverage react-admin's [i18nProvider](https://marmelab.com/react-admin/Translation.html) to translate them.
187+
188+
The following filter values:
189+
190+
```js
191+
{
192+
age_gt: 18,
193+
price_lt: 100,
194+
status_neq: 'draft',
195+
}
196+
```
197+
198+
Will render differently depending on the locale:
199+
200+
![FilterValue I18n](https://react-admin-ee.marmelab.com/assets/FilterValue_i18n.png)
201+
202+
Use the `resources.[resource].fields.[field]` key to translate field names, and the `ra-form-layout.filters.operators_shorthand.[operator]` key to translate operators.
203+
204+
```tsx
205+
const i18nProvider = polyglotI18NProvider(() =>
206+
({
207+
resources: {
208+
posts: {
209+
fields: {
210+
age: 'Âge',
211+
price: 'Prix',
212+
status: 'Statut',
213+
},
214+
},
215+
},
216+
'ra-form-layout': {
217+
filters: {
218+
operators_shorthand: {
219+
gt: 'plus grand que',
220+
lt: 'inférieur à',
221+
neq: 'autre que',
222+
},
223+
},
224+
},
225+
}),
226+
'fr'
227+
);
228+
229+
<Admin i18nProvider={i18nProvider} ... />
230+
```

docs/navigation.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
<li {% if page.path == 'FilterList.md' %} class="active" {% endif %}><a class="nav-link" href="./FilterList.html"><code>&lt;FilterList&gt;</code></a></li>
102102
<li {% if page.path == 'FilterLiveForm.md' %} class="active" {% endif %}><a class="nav-link" href="./FilterLiveForm.html"><code>&lt;FilterLiveForm&gt;</code></a></li>
103103
<li {% if page.path == 'FilterLiveSearch.md' %} class="active" {% endif %}><a class="nav-link" href="./FilterLiveSearch.html"><code>&lt;FilterLiveSearch&gt;</code></a></li>
104+
<li {% if page.path == 'FilterValue.md' %} class="active" {% endif %}><a class="nav-link" href="./FilterValue.html"><code>&lt;FilterValue&gt;</code></a></li>
104105
<li {% if page.path == 'RecordsIterator.md' %} class="active" {% endif %}><a class="nav-link" href="./RecordsIterator.html"><code>&lt;RecordsIterator&gt;</code></a></li>
105106
<li {% if page.path == 'SavedQueriesList.md' %} class="active" {% endif %}><a class="nav-link" href="./SavedQueriesList.html"><code>&lt;SavedQueriesList&gt;</code></a></li>
106107
<li {% if page.path == 'StackedFilters.md' %} class="active" {% endif %}><a class="nav-link" href="./StackedFilters.html"><code>&lt;StackedFilters&gt;</code><img class="premium" src="./img/premium.svg" /></a></li>
@@ -338,7 +339,7 @@
338339
<li {% if page.path == 'useHardDeleteMany.md' %} class="active" {% endif %}><a class="nav-link" href="./useHardDeleteMany.html"><code>useHardDeleteMany</code><img class="premium" src="./img/premium.svg" /></a></li>
339340
<li {% if page.path == 'useDeletedRecordsListController.md' %} class="active" {% endif %}><a class="nav-link" href="./useDeletedRecordsListController.html"><code>useDeletedRecordsListController</code><img class="premium" src="./img/premium.svg" /></a></li>
340341
</ul>
341-
342+
342343
<ul><div>Recipes</div>
343344
<li {% if page.path == 'Caching.md' %} class="active" {% endif %}><a class="nav-link" href="./Caching.html">Caching</a></li>
344345
<li {% if page.path == 'UnitTesting.md' %} class="active" {% endif %}><a class="nav-link" href="./UnitTesting.html">Unit Testing</a></li>
@@ -353,4 +354,3 @@
353354
<div class="beginner-mode-on" style="margin:1em;padding:1em;background:#ffffca;border-radius:4px;display:none;font-size:0.8em;opacity:0.8;text-align:center;">
354355
<a href="#beginner-mode">Beginner mode is on</a>. Turn it off to reveal more documentation for advanced components.
355356
</div>
356-

0 commit comments

Comments
 (0)