diff --git a/docs/Inputs.md b/docs/Inputs.md index 4881cfaa485..4137e567248 100644 --- a/docs/Inputs.md +++ b/docs/Inputs.md @@ -1211,6 +1211,19 @@ import { ArrayInput, SimpleFormIterator, DateInput, TextInput } from 'react-admi ``` +Furthermore, if you want to customize the label displayed for each item, you can pass a function to `SimpleFormIterator` via the `getItemLabel` prop. + +```jsx +import { ArrayInput, SimpleFormIterator, DateInput, TextInput } from 'react-admin'; + + + `${index + 1}. link`}> + + + + +``` + **Note**: `SimpleFormIterator` only accepts `Input` components as children. If you want to use some `Fields` instead, you have to use a `` to get the correct source, as follows: ```jsx diff --git a/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx b/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx index 35b6a9c2009..dffb7747cb0 100644 --- a/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx +++ b/packages/ra-ui-materialui/src/form/SimpleFormIterator.spec.tsx @@ -1,15 +1,14 @@ -import { fireEvent, waitFor, getByText } from '@testing-library/react'; -import * as React from 'react'; +import { ThemeProvider } from '@material-ui/core'; +import { createMuiTheme } from '@material-ui/core/styles'; +import { fireEvent, getByText, waitFor } from '@testing-library/react'; import expect from 'expect'; import { SaveContextProvider, SideEffectContextProvider } from 'ra-core'; import { renderWithRedux } from 'ra-test'; -import { ThemeProvider } from '@material-ui/core'; -import { createMuiTheme } from '@material-ui/core/styles'; - -import SimpleFormIterator from './SimpleFormIterator'; -import TextInput from '../input/TextInput'; +import * as React from 'react'; import { ArrayInput } from '../input'; +import TextInput from '../input/TextInput'; import SimpleForm from './SimpleForm'; +import SimpleFormIterator from './SimpleFormIterator'; const theme = createMuiTheme(); @@ -499,6 +498,34 @@ describe('', () => { expect(getByText('Custom Remove Button')).not.toBeNull(); }); + it('should display custom row label', () => { + const { getByText } = renderWithRedux( + + + + + + `3.${index}`} + > + + + + + + + + ); + + expect(getByText('3.0')).toBeDefined(); + expect(getByText('3.1')).toBeDefined(); + }); + it('should call the onClick method when the custom add button is clicked', async () => { const onClick = jest.fn(); const { getByText } = renderWithRedux( diff --git a/packages/ra-ui-materialui/src/form/SimpleFormIterator.tsx b/packages/ra-ui-materialui/src/form/SimpleFormIterator.tsx index 1cce3872a7b..f6f9a8a5051 100644 --- a/packages/ra-ui-materialui/src/form/SimpleFormIterator.tsx +++ b/packages/ra-ui-materialui/src/form/SimpleFormIterator.tsx @@ -1,27 +1,26 @@ +import Button from '@material-ui/core/Button'; +import FormHelperText from '@material-ui/core/FormHelperText'; +import { makeStyles } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; +import AddIcon from '@material-ui/icons/AddCircleOutline'; +import CloseIcon from '@material-ui/icons/RemoveCircleOutline'; +import classNames from 'classnames'; +import get from 'lodash/get'; +import PropTypes from 'prop-types'; +import { Record, useTranslate, ValidationError } from 'ra-core'; import * as React from 'react'; import { Children, cloneElement, + FC, isValidElement, - useRef, ReactElement, - FC, + useRef, } from 'react'; -import PropTypes from 'prop-types'; -import { CSSTransition, TransitionGroup } from 'react-transition-group'; -import get from 'lodash/get'; -import Typography from '@material-ui/core/Typography'; -import Button from '@material-ui/core/Button'; -import FormHelperText from '@material-ui/core/FormHelperText'; -import { makeStyles } from '@material-ui/core/styles'; -import CloseIcon from '@material-ui/icons/RemoveCircleOutline'; -import AddIcon from '@material-ui/icons/AddCircleOutline'; -import { useTranslate, ValidationError, Record } from 'ra-core'; -import classNames from 'classnames'; import { FieldArrayRenderProps } from 'react-final-form-arrays'; - -import FormInput from './FormInput'; +import { CSSTransition, TransitionGroup } from 'react-transition-group'; import { ClassesOverride } from '../types'; +import FormInput from './FormInput'; const useStyles = makeStyles( theme => ({ @@ -83,6 +82,8 @@ const DefaultAddButton = props => { ); }; +const DefaultLabelFn = index => index + 1; + const DefaultRemoveButton = props => { const classes = useStyles(props); const translate = useTranslate(); @@ -113,6 +114,7 @@ const SimpleFormIterator: FC = props => { margin, TransitionProps, defaultValue, + getItemLabel = DefaultLabelFn, } = props; const classes = useStyles(props); const nodeRef = useRef(null); @@ -197,7 +199,7 @@ const SimpleFormIterator: FC = props => { variant="body1" className={classes.index} > - {index + 1} + {getItemLabel(index)}
{Children.map( @@ -326,6 +328,7 @@ export interface SimpleFormIteratorProps disabled?: boolean; disableAdd?: boolean; disableRemove?: boolean | DisableRemoveFunction; + getItemLabel?: (index: number) => string; margin?: 'none' | 'normal' | 'dense'; meta?: { // the type defined in FieldArrayRenderProps says error is boolean, which is wrong.