Reputation: 608
I want to access index of simpleFormIterator. How can I do that? I have a code something like that I'm trying to access it in the SelectInput component
<ArrayInput source='services'>
<SimpleFormIterator>
<TextInput source='id' label="Service Name" validate={this.RequiredAndRegex} />
<FormDataConsumer>
{({ formData, ...rest }) =>
<ArrayInput source='parametervalues'>
<SimpleFormIterator>
<TextInput source='id' label="Parameter Values" validate={this.RequiredAndRegex} />
<SelectInput label="Paramater Type"
source="id"
choices={this.getParameters(formData.services[index].servicetype)}
optionText={optionRenderer}
optionValue="id" />
</SimpleFormIterator>
</ArrayInput>
}
</FormDataConsumer>
</SimpleFormIterator>
</ArrayInput>
Upvotes: 7
Views: 3730
Reputation: 337
After much research i found it's not possible to get the index of SimpleFormIterator directly. However there's a workaround for that if you've a <FormDataConsumer>
inside the <SimpleFormIterator>
. Considering the name of your array is cars
<SimpleFormIterator disableReordering inline>
<FormDataConsumer>
{({ getSource, formData }) => {
const regex = /cars\[(\d+)\]\./;
const match = getSource('').match(regex);
const index = parseInt(match[1]);
return (
<label>{index}</label>
);
}}
<FormDataConsumer/>
</SimpleFormIterator>
In the above code getSource('')
will return a string like cars[0].
for first array element. You can extract the array index part by matching the string to the regex /cars\[(\d+)\]\./
.
Upvotes: 1
Reputation: 1
In case anyone else comes across this, how I ended up solving a similar problem.
A FunctionField
gets the record and source in the render prop.
For arrays, the source looks like books.0
and books.1
<SimpleFormIterator>
<FunctionField render={(record, source) => {
const lastPeriodBreak = source.lastIndexOf('.') + 1;
const index = Number(source.substring(lastPeriodBreak));
return index;
}} />
</SimpleFormIterator>
EDIT: Just noticed there's also a new getItemLabel
on SimpleFormIterator
https://marmelab.com/react-admin/SimpleFormIterator.html#getitemlabel
Upvotes: 0
Reputation: 2437
I face the same problem, and I see no document about this, but there is clue inside the source code, and tested this works
<ArrayInput ...>
<SimpleFormIterator ... >
<SimpleFormIteratorItemContext.Consumer>{({ index }) => {
return <div>index:{index}</div>
}}</SimpleFormIteratorItemContext.Consumer>
Upvotes: 0
Reputation: 1
You can make a Decorator and extract index of your input there.
// Make Decorator
const withDynamicChoices = BaseComponent => {
return class extends Component {
getChoices = () => {
// console.log(this.props);
// grab your index here...
const formData = this.props.formData;
return formData.services[this.props.index].servicetype;
}
render() {
return <BaseComponent
{...this.props}
choices={ this.getChoices() }
/>;
}
}
}
// Decorate original Input
const SelectInputW = withDynamicChoices(SelectInput);
// Use original input as <SelectInputW formData={formData} >
Upvotes: 0
Reputation: 78
SimpleFormIterator is actually passing the index in line 137. (https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/form/SimpleFormIterator.js).
However, you won't be able to access it from without the child, like you are trying in your example.
If you want to access it, you will have to create a custom child (SelectInput in your case).
I usually write a complete custom form using redux-form and material-ui and then dispatch the values to the dataProvider.
Upvotes: 0
Reputation: 7066
That's not possible with the SimpleFormIterator
. You'll have to write your own. I suggest using it as a base (https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/form/SimpleFormIterator.js) and passing the index when cloning the input at L114
Upvotes: 1