0

I have the following component with a function which can dynamically add New elements in my form. I have a button and when clicking on the button, a new form field will be added. Now I need to keep this new field's value in a new state and send it to the API. To send all the new fields, I planned to set a single state as array and push new field values after enter them. After adding few new fields, I need something like this,

this.state.other [
   {
      description: "field 1 description",
      amount: "120$"
   },
   {
      description: "field 2 description",
      amount: "180$"
   },
   {
      description: "field 3 description",
      amount: "156$"
   },
]

This is what I have tried so far:

let dataId = 0;

class ClientIntakeModal extends Component {
    constructor(props) {
        super(props);

        this.allOtherCosts = [];

        this.state = {
            otherCosts: this.allOtherCosts,
            other: [],
        }
        this.otherDescInputHandle = this.otherDescInputHandle.bind(this);
    }

    appendData = () => {
        dataId = dataId + 1;
        this.allOtherCosts.push(
            <div className="halfWidth jobCostMain" key={dataId}>
                <div>
                    <div className="jobDescAdded">
                        <TextField
                            id={'costDescription'}
                            name={'description'}
                            type="text"
                            value={this.state.other.description}
                            onChange={this.otherDescInputHandle}
                        />
                    </div>
                    <div className="jobCostAdded">
                        <TextField
                            id={'costAmount'}
                            name={'amount'}
                            type="number"
                            value={this.state.other.amount}
                            onChange={this.otherDescInputHandle}
                        />
                    </div>
                </div>
            </div>
        );
        this.setState({
            otherCosts: this.allOtherCosts
        });
    }

    otherDescInputHandle(event) {
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState({
            other: [
                ...this.state.other,
                {
                    [name]:value
                },
            ]
        });
    }

    render() {
      return(
           <div>
             <div id="addNewUser" className="addNewUser" onClick={this.appendData}>
                 <span>+</span>
             </div>
             {this.allOtherCosts}
           </div>
      )
    }
}

The problem is, I'm receiving something like follows

this.state.other [
   {
      description: "f",
   },
   {
      description: "fi",
   },
   {
      description: "fie",
   },
   {
      description: "fiel",
   },
]

How can I get the correct state here?

1
  • On every key press your constantly adding the input value, you ideally need another event, maybe another button to trigger when it saves. Commented May 3, 2019 at 12:26

2 Answers 2

1

i have some considerations to your code and that will better him. otherDescInputHandle function, use desctruction, like that:

const { target, value, name } = event;

and do that:

const { other } = this.state;
/* your ideia */
this.setState({ other });

In your appendData function, in dataId get the length of array

dataId = this.allOtherCosts.length;

and in onChange of your textfield, pass the event and the dataId

onChange={e => this.otherDescInputHandle(e, dataId)}

so, in the otherDescInputHandle you have the position of the field on array, and when you go to change the value, you cand access the correctly position of array:

const { other } = this.state;
other[dataId].description = value;

Try this ideia. I guess this will solve your problem.

And please, try to use only state variables and manipulating they. Is perfectly possible to solve your problem without using this.allOtherCosts = [];

Sign up to request clarification or add additional context in comments.

Comments

1

In general I recommend the following approach to update a collection's item immutable. It is important to use id for the items, which can be a dynamically generated unique id.

class App extends React.Component {
  state = {
    someArray: [
      { id: 1, value: 'a' },
      { id: 2, value: 'b' },
      { id: 3, value: 'c' }
    ]
 }

  setValue = (id, value) => {
    this.setState(prevState => ({
      someArray: prevState.someArray.map(item => (
        id === item.id ? { ...item, value } : item
      ))
    }))
  }
  
  render(){
    return (
      <div>
        <ul>
          {this.state.someArray.map(({value}) => <li>{value}</li>)}
        </ul>
        <button onClick={() => this.setValue(2, 'foo')}>Set value</button>
      </div>
    )

  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.