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 linking two inputs example #5389

Merged
merged 1 commit into from
Oct 13, 2020
Merged
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
95 changes: 47 additions & 48 deletions docs/Inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1892,76 +1892,76 @@ const PersonEdit = props => (

Edition forms often contain linked inputs, e.g. country and city (the choices of the latter depending on the value of the former).

React-admin relies on react-final-form, so you can grab the current form values using react-final-form [useFormState](https://final-form.org/docs/react-final-form/api/useFormState) hook. Alternatively, you can use the react-admin `<FormDataConsumer>` component, which grabs the form values, and passes them to a child function.

This facilitates the implementation of linked inputs:
React-admin relies on [react-final-form](https://final-form.org/docs/react-final-form/getting-started) for form handling. You can grab the current form values using react-final-form [useFormState](https://final-form.org/docs/react-final-form/api/useFormState) hook.

```jsx
import { FormDataConsumer } from 'react-admin';
import * as React from 'react';
import { Edit, SimpleForm, SelectInput } from 'react-admin';
import { useFormState } from 'react-final-form';

const countries = ['USA', 'UK', 'France'];
const cities = {
USA: ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'],
UK: ['London', 'Birmingham', 'Glasgow', 'Liverpool', 'Bristol'],
France: ['Paris', 'Marseille', 'Lyon', 'Toulouse', 'Nice'],
};
const toChoices = items => items.map(item => ({ id: item, name: item }));

const CityInput = props => {
const { values } = useFormState();
return (
<SelectInput
choices={values.country ? toChoices(cities[values.country]) : []}
{...props}
/>
);
};

const OrderEdit = (props) => (
const OrderEdit = props => (
<Edit {...props}>
<SimpleForm>
<SelectInput source="country" choices={countries} />
<FormDataConsumer>
{({ formData, ...rest }) =>
<SelectInput
source="city"
choices={getCitiesFor(formData.country)}
{...rest}
/>
}
</FormDataConsumer>
<SelectInput source="country" choices={toChoices(countries)} />
<CityInput source="cities" />
</SimpleForm>
</Edit>
);
```

**Tip**: When using a `FormDataConsumer` inside an `ArrayInput`, the `FormDataConsumer` will provide three additional properties to its children function:

- `scopedFormData`: an object containing the current values of the currently rendered item from the `ArrayInput`
- `getSource`: a function which will translate the source into a valid one for the `ArrayInput`
export default OrderEdit;
```

Would you need to update an input when another one changes, use the [`useForm`](https://final-form.org/docs/react-final-form/api/useForm) hook from `react-final-form`. For example, a country input that resets a city input on change.
Alternatively, you can use the react-admin `<FormDataConsumer>` component, which grabs the form values, and passes them to a child function. As `<FormDataConsumer>` uses the render props pattern, you can avoid creating an intermediate component like the `<CityInput>` component above:

```jsx
import * as React from 'react';
import { Fragment } from 'react';
import { useForm } from 'react-final-form';
import { Edit, SimpleForm, SelectInput, FormDataConsumer } from 'react-admin';

const OrderOrigin = ({ formData, ...rest }) => {
const form = useForm();

return (
<Fragment>
<SelectInput
source="country"
choices={countries}
onChange={value => form.change('city', null)}
{...rest}
/>
<SelectInput
source="city"
choices={getCitiesFor(formData.country)}
{...rest}
/>
</Fragment>
);
};

const OrderEdit = (props) => (
const OrderEdit = props => (
<Edit {...props}>
<SimpleForm>
<SelectInput source="country" choices={toChoices(countries)} />
<FormDataConsumer>
{formDataProps => (
<OrderOrigin {...formDataProps} />
{({ formData, ...rest }) => (
<SelectInput
source="cities"
choices={
formData.country
? toChoices(cities[formData.country])
: []
}
{...rest}
/>
)}
</FormDataConsumer>
</SimpleForm>
</Edit>
);
```

**Tip**: When using a `FormDataConsumer` inside an `ArrayInput`, the `FormDataConsumer` will provide three additional properties to its children function:

- `scopedFormData`: an object containing the current values of the currently rendered item from the `ArrayInput`
- `getSource`: a function which will translate the source into a valid one for the `ArrayInput`

And here is an example usage for `getSource` inside `<ArrayInput>`:

```jsx
Expand All @@ -1973,7 +1973,6 @@ const PostEdit = (props) => (
<ArrayInput source="authors">
<SimpleFormIterator>
<TextInput source="name" />

<FormDataConsumer>
{({
formData, // The whole form data
Expand Down Expand Up @@ -2039,4 +2038,4 @@ import { FormDataConsumer } from 'react-admin';
</Edit>
);
```
{% endraw %}
{% endraw %}