How to get index of SimpleFormIterator
Asked Answered
T

6

7

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>
Turnspit answered 8/6, 2018 at 8:29 Comment(0)
I
1

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

Interphone answered 8/6, 2018 at 9:52 Comment(1)
Have you successfully created a component using SimpleFormIterator? If so, would you have an example? I can't get it to work.Bandolier
C
1

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+)\]\./.

Cleaner answered 31/7, 2023 at 4:57 Comment(0)
T
0

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.

Thermosetting answered 23/10, 2018 at 10:17 Comment(0)
K
0

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} >
Kalpak answered 16/1, 2020 at 18:18 Comment(0)
R
0

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>
Rosenblast answered 13/3, 2023 at 6:48 Comment(0)
U
0

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

Utile answered 27/3, 2023 at 20:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.