Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Doc] Fix tutorial about sanitizing empty values #8156

Merged
merged 3 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/Create.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,20 @@ The `transform` function can also return a `Promise`, which allows you to do all

**Tip**: If you want to have different transformations based on the button clicked by the user (e.g. if the creation form displays two submit buttons, one to "save", and another to "save and notify other admins"), you can set the `transform` prop on [the `<SaveButton>` component](./SaveButton.md), too.

**Tip**: A frequent usage of the `transform` function is to stripe empty string values returned by the form.
## Cleaning Up Empty Strings

As a reminder, HTML form inputs always return strings, even for numbers and booleans. So the empty value for a text input is the empty string, not `null` or `undefined`. This means that the data sent to `dataProvider.create()` will contain empty strings:

```js
{
title: '',
average_note: '',
body: '',
// etc.
}
```

If you prefer to have `null` values, or to omit the key for empty values, use [the `transform` prop](#transform) to sanitize the form data before submission:

```jsx
export const UserCreate = (props) => {
Expand Down
17 changes: 16 additions & 1 deletion docs/Edit.md
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,20 @@ export const UserEdit = (props) => {
}
```

**Tip**: A frequent usage of the `transform` function is to stripe empty string values returned by the form.
## Cleaning Up Empty Strings

As a reminder, HTML form inputs always return strings, even for numbers and booleans. So the empty value for a text input is the empty string, not `null` or `undefined`. This means that the data sent to `dataProvider.update()` will contain empty strings:

```js
{
title: '',
average_note: '',
body: '',
// etc.
}
```

If you prefer to have `null` values, or to omit the key for empty values, use [the `transform` prop](#transform) to sanitize the form data before submission:

```jsx
export const UserEdit = (props) => {
Expand All @@ -559,6 +572,8 @@ export const UserEdit = (props) => {
}
```

As an alternative, you can clean up empty values at the input level, using [the `parse` prop](./Inputs.md#transforming-input-value-tofrom-record).

## Adding `meta` To The DataProvider Call

You can pass a custom `meta` to the `dataProvider` call, using either `queryOptions`, or `mutationOptions`:
Expand Down
34 changes: 16 additions & 18 deletions docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,22 @@ Mnemonic for the two functions:
- `parse()`: input -> record
- `format()`: record -> input

Say the user would like to input values of 0-100 to a percentage field but your API (hence record) expects 0-1.0. You can use simple `parse()` and `format()` functions to archive the transform:
A common usage for this feature is to strip empty strings from the record before saving it to the API. As a reminder, HTML form inputs always return strings, even for numbers and booleans. So the empty value for a text input is the empty string, not `null` or `undefined`. Leveraging `parse` allows you to transform the empty string to `null` before saving the record.

```jsx
import { TextInput } from 'react-admin';

const TextInputWithNullEmptyValue = props => (
<TextInput
{...props}
parse={ v => typeof v === 'string' && v.length === 0 ? null : v }
/>
);

export default TextInputWithNullEmptyValue;
```

Let's look at another usage example. Say the user would like to input values of 0-100 to a percentage field but your API (hence record) expects 0-1.0. You can use simple `parse()` and `format()` functions to archive the transform:

```jsx
<NumberInput source="percent" format={v => v * 100} parse={v => parseFloat(v) / 100} label="Formatted number" />
Expand Down Expand Up @@ -376,23 +391,6 @@ const dateParser = value => {
<DateInput source="isodate" format={dateFormatter} parse={dateParser} defaultValue={new Date()} />
```

**Tip:** To spread a conversion behaviour to your whole application, you can import a `react-admin`component then re-export them with their `format` and/or `parse` props set.

```jsx
import * as React from 'react';
import { TextInput } from 'react-admin';

const FilledOrNullTextInput = props => {
return (
<TextInput
{...props}
format={ v => typeof v === 'string' && v.length === 0 ? null : v }
/>
);
};
export default FilledOrNullTextInput;
```

## Linking Two Inputs

Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former).
Expand Down
37 changes: 37 additions & 0 deletions docs/SimpleForm.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,43 @@ export const TagEdit = () => (
);
```

## Cleaning Up Empty Strings

As a reminder, HTML form inputs always return strings, even for numbers and booleans. So the empty value for a text input is the empty string, not `null` or `undefined`. This means that the data sent to the form handler will contain empty strings:

```js
{
title: '',
average_note: '',
body: '',
// etc.
}
```

If you prefer to have `null` values, or to omit the key for empty values, use `transform` prop of the parent component ([`<Edit>`](./Edit.md#transform) or [`<Create>`](./Create.md#transform)) to sanitize the form data before passing it to the `dataProvider`:

```jsx
export const UserEdit = (props) => {
const transform = (data) => {
const sanitizedData = {};
for (const key in data) {
if (typeof data[key] === "string" && data[key].trim().length === 0) continue;
sanitizedData[key] = data[key];
}
return sanitizedData;
};
return (
<Edit {...props} transform={transform}>
<SimpleForm>
...
</SimpleForm>
</Edit>
);
}
```

As an alternative, you can clean up empty values at the input level, using [the `parse` prop](./Inputs.md#transforming-input-value-tofrom-record).

## Using Fields As Children

The basic usage of `<SimpleForm>` is to pass [Input components](./Inputs.md) as children. For non-editable fields, you can pass `disabled` inputs, or even [Field components](./Fields.md). But since `<Field>` components have no label by default, you'll have to wrap your inputs in a `<Labeled>` component in that case:
Expand Down
35 changes: 35 additions & 0 deletions docs/TabbedForm.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,41 @@ const ProductEdit = () => (

**Tip**: React-admin renders each tab *twice*: once to get the tab header, and once to get the tab content. If you use a custom component instead of a `<FormTab>`, make sure that it accepts an `intent` prop, and renders differently when the value of that prop is 'header' or 'content'.

## Cleaning Up Empty Strings

As a reminder, HTML form inputs always return strings, even for numbers and booleans. So the empty value for a text input is the empty string, not `null` or `undefined`. This means that the data sent to the form handler will contain empty strings:

```js
{
title: '',
average_note: '',
body: '',
// etc.
}
```

If you prefer to have `null` values, or to omit the key for empty values, use `transform` prop of the parent component ([`<Edit>`](./Edit.md#transform) or [`<Create>`](./Create.md#transform)) to sanitize the form data before passing it to the `dataProvider`:

```jsx
export const UserEdit = (props) => {
const transform = (data) => {
const sanitizedData = {};
for (const key in data) {
if (typeof data[key] === "string" && data[key].trim().length === 0) continue;
sanitizedData[key] = data[key];
}
return sanitizedData;
};
return (
<Edit {...props} transform={transform}>
<TabbedForm>
...
</TabbedForm>
</Edit>
);
}
```

## Using Fields As FormTab Children

The basic usage of `<TabbedForm>` is to pass [Input components](./Inputs.md) as children of `<FormTab>`. For non-editable fields, you can pass `disabled` inputs, or even [Field components](./Fields.md). But since `<Field>` components have no label by default, you'll have to wrap your inputs in a `<Labeled>` component in that case:
Expand Down