How to implement a dynamic form with controlled components in ReactJS?
Solution 1:
How adding/removing input elements dynamically possible?
Yes, it is possible, you can add/remove input
elements dynamically
, But for that you need to take care of few things:
1- Proper binding of events.
2- Array to store the values of each input element separately.
3- When user fill value in any input element then updating only that specific value in state.
Logic:
Maintain an array inside state, that will store the values. Use #array.map to create ui (input element) for each array values. while creating the fields, use a remove button
with each field, and pass the index of field in that function
, it will help you to identify which field you wants to delete, do the same thing for onChange
also.
Check this example:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { values: [] };
this.handleSubmit = this.handleSubmit.bind(this);
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i}>
<input type="text" value={el||''} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
)
}
handleChange(i, event) {
let values = [...this.state.values];
values[i] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, '']}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.values.join(', '));
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='container'/>
Check the working jsfiddle
: https://jsfiddle.net/mayankshukla5031/ezdxg224/
Solution 2:
How adding/removing input elements dynamically with functional components?
The same component from the selected answer reviewed and rewrited as a functional component.
import React from 'react';
import { useState } from 'react';
function DynamicInput() {
const [values, setValues] = useState({ val: []});
function createInputs() {
return values.val.map((el, i) =>
<div key={i}>
<input type="text" value={el||''} onChange={handleChange.bind(i)} />
<input type='button' value='remove' name={i} onClick={removeClick.bind(i)} />
</div>
);
}
function handleChange(event) {
let vals = [...values.val];
vals[this] = event.target.value;
setValues({ val: vals });
}
const addClick = () => {
setValues({ val: [...values.val, '']})
}
const removeClick = (event) => {
let vals = [...values.val];
let index = Number(event.target.name);
vals.splice(index, 1);
setValues({ val: vals });
}
const handleSubmit = event => {
alert('A name was submitted: ' + values.val.join(', '));
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
{createInputs()}
<input type='button' value='add more' onClick={addClick} />
<input type="submit" value="Submit" />
</form>
);
}
export default DynamicInput;
Solution 3:
If you want to use an object because you have many input field you can do this :
class App extends React.Component {
constructor(props) {
super(props);
this.state = { values: [] };
this.handleSubmit = this.handleSubmit.bind(this);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { values: [{question: '',response: ''}] };
this.handleSubmit = this.handleSubmit.bind(this);
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i}>
<input type="text" value={el.question} onChange={this.handleChange.bind(this, i)} />
<textarea type="text" value={el.response} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
)
}
handleChange (i,event) {
let values = [...this.state.values];
values[i][event.target.id] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
handleSubmit(event) {
event.preventDefault();
alert(this.state.values.map(objet=> "{"+ " " + "'question' :" + " " + objet.question + " " + "'response' :" + " " + objet.response +" " + "}") );
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!-- begin snippet: js hide: false console: true babel: false -->
<input type="text" value={el.response} onChange={this.handleChange.bind(this, i)} id="response" a />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
)
}
handleChange (i,event) {
let values = [...this.state.values];
values[i][event.target.id] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, {question: '',response: '',}]}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
handleSubmit(event) {
event.preventDefault();
alert(this.state.values.map(objet=> "{"+ " " + "'question' :" + " " + objet.question + " " + "'response' :" + " " + objet.response +" " + "}") );
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<div className="d-flex justify-content-end">
<KamaminiButton onClick={this.addClick.bind(this)} text='Ajouter une autre question' />
</div>
<input type="submit" value="Submit" />
</form>
);
}
}
<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='container'/>