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

[RFR] SimpleForm/TabbedForm - deprecate defaultValue #3756

Merged
merged 1 commit into from
Oct 1, 2019
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
29 changes: 29 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,35 @@ const PostFilter = props =>
</Filter>;
```

## Form prop `defaultValue` was renamed to `initialValues`

This is actually to be consistent with the underlying form library ([final-form](https://final-form.org/docs/react-final-form))

```diff
// for SimpleForm
const PostEdit = props =>
<Edit {...props}>
<SimpleForm
- defaultValue={{ stock: 0 }}
+ initialValues={{ stock: 0 }}
>
// ...
</SimpleForm>
</Edit>;
// for TabbedForm
const PostEdit = props =>
<Edit {...props}>
<TabbedForm
- defaultValue={{ stock: 0 }}
+ initialValues={{ stock: 0 }}
>
<FormTab label="Identity>
// ...
</FormTab>
</TabbedForm>
</Edit>;
```

## Complete rewrite of the AutocompleteInput and AutocompleteArrayInput components

We rewrote the `<AutocompleteInput>` and `<AutocompleteArrayInput>` components from scratch using [`downshift`](https://github.com/downshift-js/downshift), while the previous version was based on [react-autosuggest](http://react-autosuggest.js.org/). The new components are more robust and more future-proof, and their API didn't change.
Expand Down
22 changes: 12 additions & 10 deletions docs/CreateEdit.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ to change this behaviour you can pass `false` for the `submitOnEnter` property,

Here are all the props accepted by the `<SimpleForm>` component:

* [`defaultValue`](#default-values)
* [`initialValues`](#default-values)
* [`validate`](#validation)
* [`submitOnEnter`](#submit-on-enter)
* [`redirect`](#redirection-after-submission)
Expand Down Expand Up @@ -391,7 +391,7 @@ to change this behaviour you can pass `false` for the `submitOnEnter` property.

Here are all the props accepted by the `<TabbedForm>` component:

* [`defaultValue`](#default-values)
* [`initialValues`](#default-values)
* [`validate`](#validation)
* [`submitOnEnter`](#submit-on-enter)
* [`redirect`](#redirection-after-submission)
Expand Down Expand Up @@ -467,17 +467,19 @@ export const PostEdit = (props) => (

## Default Values

To define default values, you can add a `defaultValue` prop to form components (`<SimpleForm>`, `<Tabbedform>`, etc.), or add a `defaultValue` to individual input components. Let's see each of these options.
To define default values, you can add a `initialValues` prop to form components (`<SimpleForm>`, `<Tabbedform>`, etc.), or add a `defaultValue` to individual input components. Let's see each of these options.

**Note**: on RA v2 the `initialValues` used to be named `defaultValue`

### Global Default Value

The value of the form `defaultValue` prop can be an object, or a function returning an object, specifying default values for the created record. For instance:
The value of the form `initialValues` prop is an object, or a function returning an object, specifying default values for the created record. For instance:

```jsx
const postDefaultValue = { created_at: new Date(), nb_views: 0 };
export const PostCreate = (props) => (
<Create {...props}>
<SimpleForm defaultValue={postDefaultValue}>
<SimpleForm initialValues={postDefaultValue}>
<TextInput source="title" />
<RichTextInput source="body" />
<NumberInput source="nb_views" />
Expand All @@ -486,11 +488,11 @@ export const PostCreate = (props) => (
);
```

**Tip**: You can include properties in the form `defaultValue` that are not listed as input components, like the `created_at` property in the previous example.
**Tip**: You can include properties in the form `initialValues` that are not listed as input components, like the `created_at` property in the previous example.

### Per Input Default Value

Alternatively, you can specify a `defaultValue` prop directly in `<Input>` components. Just like for form-level default values, an input-level default value can be a scalar, or a function returning a scalar. React-admin will merge the input default values with the form default value (input > form):
Alternatively, you can specify a `defaultValue` prop directly in `<Input>` components. Default value can be a scalar, or a function returning a scalar. React-admin will merge the input default values with the form default value (input > form):

```jsx
export const PostCreate = (props) => (
Expand Down Expand Up @@ -630,7 +632,7 @@ const validateStock = [required(), number(), minValue(0)];

export const ProductEdit = ({ ...props }) => (
<Edit {...props}>
<SimpleForm defaultValue={{ stock: 0 }}>
<SimpleForm initialValues={{ stock: 0 }}>
...
{/* do this */}
<NumberInput source="stock" validate={validateStock} />
Expand Down Expand Up @@ -914,7 +916,7 @@ export const UserCreate = ({ permissions, ...props }) =>
<Create {...props}>
<SimpleForm
toolbar={<UserCreateToolbar permissions={permissions} />}
defaultValue={{ role: 'user' }}
initialValues={{ role: 'user' }}
>
<TextInput source="name" validate={[required()]} />
{permissions === 'admin' &&
Expand All @@ -932,7 +934,7 @@ This also works inside an `Edition` view with a `TabbedForm`, and you can hide a
```jsx
export const UserEdit = ({ permissions, ...props }) =>
<Edit title={<UserTitle />} {...props}>
<TabbedForm defaultValue={{ role: 'user' }}>
<TabbedForm initialValues={{ role: 'user' }}>
<FormTab label="user.form.summary">
{permissions === 'admin' && <TextInput disabled source="id" />}
<TextInput source="name" validate={required()} />
Expand Down
17 changes: 9 additions & 8 deletions packages/ra-ui-materialui/src/form/SimpleForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import arrayMutators from 'final-form-arrays';
import classnames from 'classnames';
import { useTranslate, useInitializeFormWithRecord } from 'ra-core';

import getFormInitialValues from './getFormInitialValues';
import FormInput from './FormInput';
import Toolbar from './Toolbar';
import CardContentInner from '../layout/CardContentInner';

const SimpleForm = ({ initialValues, saving, ...props }) => {
const SimpleForm = ({ initialValues, defaultValue, saving, ...props }) => {
let redirect = useRef(props.redirect);
// We don't use state here for two reasons:
// 1. There no way to execute code only after the state has been updated
Expand All @@ -25,15 +26,14 @@ const SimpleForm = ({ initialValues, saving, ...props }) => {
props.save(values, finalRedirect);
};

const finalInitialValues = {
...initialValues,
...props.record,
};

return (
<Form
key={props.version}
initialValues={finalInitialValues}
initialValues={getFormInitialValues(
initialValues,
defaultValue,
props.record
)}
onSubmit={submit}
mutators={{ ...arrayMutators }}
keepDirtyOnReinitialize
Expand Down Expand Up @@ -132,7 +132,8 @@ SimpleFormView.propTypes = {
basePath: PropTypes.string,
children: PropTypes.node,
className: PropTypes.string,
defaultValue: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
defaultValue: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), // @deprecated
initialValues: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
handleSubmit: PropTypes.func, // passed by react-final-form
invalid: PropTypes.bool,
pristine: PropTypes.bool,
Expand Down
17 changes: 9 additions & 8 deletions packages/ra-ui-materialui/src/form/TabbedForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Divider from '@material-ui/core/Divider';
import { makeStyles } from '@material-ui/core/styles';
import { useTranslate, useInitializeFormWithRecord } from 'ra-core';

import getFormInitialValues from './getFormInitialValues';
import Toolbar from './Toolbar';
import TabbedFormTabs, { getTabFullPath } from './TabbedFormTabs';
import { useRouteMatch, useLocation } from 'react-router';
Expand All @@ -21,7 +22,7 @@ const useStyles = makeStyles(theme => ({
},
}));

const TabbedForm = ({ initialValues, saving, ...props }) => {
const TabbedForm = ({ initialValues, defaultValue, saving, ...props }) => {
let redirect = useRef(props.redirect);
// We don't use state here for two reasons:
// 1. There no way to execute code only after the state has been updated
Expand All @@ -39,15 +40,14 @@ const TabbedForm = ({ initialValues, saving, ...props }) => {
props.save(values, finalRedirect);
};

const finalInitialValues = {
...initialValues,
...props.record,
};

return (
<Form
key={props.version}
initialValues={finalInitialValues}
initialValues={getFormInitialValues(
initialValues,
defaultValue,
props.record
)}
onSubmit={submit}
mutators={{ ...arrayMutators }}
setRedirect={setRedirect}
Expand Down Expand Up @@ -185,7 +185,8 @@ TabbedFormView.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
classes: PropTypes.object,
defaultValue: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
defaultValue: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), // @deprecated
initialValues: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
handleSubmit: PropTypes.func, // passed by react-final-form
invalid: PropTypes.bool,
location: PropTypes.object,
Expand Down
30 changes: 30 additions & 0 deletions packages/ra-ui-materialui/src/form/getFormInitialValues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export default function getFormInitialValues(
initialValues,
defaultValue,
record
) {
let finalInitialValues = {
...initialValues,
...record,
};

if (typeof defaultValue !== 'undefined') {
console.warn(
'"defaultValue" is deprecated, please use "initialValues" instead'
);
}

if (typeof defaultValue === 'object') {
finalInitialValues = {
...defaultValue,
...finalInitialValues,
};
} else if (typeof defaultValue === 'function') {
finalInitialValues = {
...defaultValue(record),
...finalInitialValues,
};
}

return finalInitialValues;
}
2 changes: 2 additions & 0 deletions packages/ra-ui-materialui/src/form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SimpleFormIterator from './SimpleFormIterator';
import TabbedForm from './TabbedForm';
import TabbedFormTabs from './TabbedFormTabs';
import Toolbar from './Toolbar';
import getFormInitialValues from './getFormInitialValues';

export {
FormInput,
Expand All @@ -14,4 +15,5 @@ export {
TabbedForm,
TabbedFormTabs,
Toolbar,
getFormInitialValues,
};