Cansel Muti
Cansel Muti

Reputation: 608

How to get index of SimpleFormIterator

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

Answers (6)

hunain60
hunain60

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

Brandon Benedict
Brandon Benedict

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

Josh Lin
Josh Lin

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

Vlad
Vlad

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

Laurents Mohr
Laurents Mohr

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

Gildas Garcia
Gildas Garcia

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

Related Questions