Reputation: 339
I am trying to update form with double input, every time users click 'add' button and mutate state with their values & I want that 2 input to be "connected" for it. It would be more understandable if I show with graphic what I am trying to do:
[input] [second input] [remove button]
[input] [second input] [remove button]
[input] [second input] [remove button] ...
It is much easier when I am trying to generate only one input dynamically, currently I even have not full code because I have no idea how to do that but I have some part, here is it:
state:
stuff: {
item: [],
quantity: []
},
and this was the code for only adding one input field dynamically:
// i mapped stuff because before i only had one array and like this-> stuff: []
return this.state.stuff.map((element, index) =>
<div key={index}>
<input type="text" value={element||''} onChange={this.handleChange.bind(this, index)} />
<input type='button' value='remove' onClick={this.removeInput.bind(this, index)}/>
</div>
)
handleChange(index, event) {
let stuff = [...this.state.stuff];
stuff[index] = event.target.value;
this.setState({ stuff });
}
add(){
this.setState(previousState => ({ stuff: [...previousState.stuff,'']}))
}
removeInput(index){
let stuff = [...this.state.stuff];
stuff.splice(index,1);
this.setState({ stuff });
}
To be honest I was just trying every idea and in add() function I can not get completely how adding ''
to stuff array makes code work, if anyone explains this and give me the solution for what I want to do I will be thankful.
Upvotes: 0
Views: 44
Reputation: 138235
I can not get completely how adding '' to
stuff
array makes code work
If you look into your render()
method, you'll see this.state.stuff.map(...)
so you basically map every value in the stuff
array to the related input. Therefore if you add another value to stuff
, the component does rerender and a new input gets mapped.
Now to add two inputs for each row, you could keep two arrays, but that makes it more difficult to manage the data later on. Instead I'd use an array of objects, containing an item and quantity property. For that, inside the add()
method add new objects:
this.setState(({ stuff }) => ({ stuff: [...stuff, { item: "", quantity: 0 }));
Then you have to change your mapping inside render()
to show those objects:
this.state.stuff.map(({ item, quantity }, index) => (
<div>
Item: <input value={item} onChange={e => this.update(index, "item", e.target.value)} />
Quantity: <input value={quantity} onChange={e => this.update(index, "quantity", e.target.value)} />
</div>
));
Now the only thing thats left is an update method, that not only takes an index but also the key to change:
update(index, key, value) {
this.setState(({ stuff }) => ({ stuff: stuff.map((it, i) => i === index ? { ...it, [key]: value }, it)) }));
}
Upvotes: 2