I have a form in which I am generating form fields dynamically . Now Issue is fields which are not dynamically generated are getting input and those field which are dynamically generated are not taking input in fields. name='name'
and name='age'
fields are not getting input I cant insert data in them . while first two fields owner and description are working fine
import React from "react";
class Form extends React.Component {
state = {
cats: [{ name: "", age: "" }],
owner: "",
description: ""
};
handleChange = e => {
alert('inot');
if (["name", "age"].includes(e.target.className)) {
let cats = [...this.state.cats];
cats[e.target.dataset.id][
e.target.className
] = e.target.value.toUpperCase();
this.setState({ cats }, () => console.log(this.state.cats));
} else {
this.setState({ [e.target.name]: e.target.value.toUpperCase() });
}
};
addCat = e => {
this.setState(prevState => ({
cats: [...prevState.cats, { name: "", age: "" }]
}));
};
handleSubmit = e => {
e.preventDefault();
};
handleClick = e => document.getElementById(e.target.id).remove();
// changeOption =(e) => {
// this.setState.cats(e.target.value);
// }
render() {
let { owner, description, cats } = this.state;
return (
<form onSubmit={this.handleSubmit} onChange={this.handleChange}>
<div className='row mt-5'>
<div className='col-md-12 mb-5'>
<h3 className='text-center text-primary'>Create Products Option</h3>
</div>
<div className='col-md-3'></div>
<div className='col-md-3'>
<label htmlFor='name'>
<b>Owner</b>
</label>
<input
type='text'
className='form-control'
name='owner'
id='owner'
value={owner}
/>
</div>
<div className='col-md-3'>
<label htmlFor='description'>
<b>Description</b>
</label>
<input
type='text'
className='form-control'
name='description'
id='description'
value={description}
/>
<button
className='btn btn-success rounded-0 w-25 float-right mt-2 shadow-none'
onClick={this.addCat}
>
+
</button>
</div>
<div className='col-md-3'></div>
</div>
{cats.map((val, idx) => {
let catId = `cat-${idx}`,
ageId = `age-${idx}`;
return (
<form onSubmit={this.handleSubmit} onChange={this.handleChange}>
<div id={ageId} key={idx}>
<div className='row mt-5'>
<div className='col-md-3'></div>
<div className='col-md-3'>
<label htmlFor={catId}>
<b>{`Cat #${idx + 1}`}</b>
</label>
<input
type='text'
name='name'
data-id={idx}
id={catId}
value={cats[idx].name}
className='name form-control'
/>
</div>
<div className='col-md-3'>
<label htmlFor={ageId}>
<b>Age</b>
</label>
<input
type='text'
name='age'
data-id={idx}
id={ageId}
value={cats[idx].age}
className='age form-control'
/>
<button
className='btn btn-success rounded-0 w-25 float-right mt-2 shadow-none'
onClick={this.addCat}
>
+
</button>
<input
type='button'
name={ageId}
data-id={idx}
id={ageId}
value={"-"}
className='age float-right mt-2 mr-3 btn btn-danger w-25 rounded-0 w-25 shadow-none'
onClick={this.handleClick}
/>
</div>
<div className='col-md-3'></div>
</div>
</div>
</form>
);
})}
<div className='row mt-3'>
<div className='col-md-3'></div>
<div className='col-md-3'>
<label htmlFor='name'>
<b>Min Selection</b>
</label>
<input
type='text'
className='form-control'
name='min'
id='min'
value={""}
/>
</div>
<div className='col-md-3'>
<label htmlFor='description'>
<b>Max Selection</b>
</label>
<input
type='text'
className='form-control'
name='max'
id='max'
value={""}
/>
<input
className='float-right btn btn-success mt-3'
type='submit'
value='Submit'
/>
{/* <button className="float-right" onClick={this.addCat}>Add new cat</button> */}
</div>
<div className='col-md-3'></div>
</div>
</form>
);
}
}
export default Form;
Codesandbox here. Looks like you should be seeing some errors in your console that might provide some explanation:
Warning: Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
Working Sandbox here. There are a few things wrong here:
handleChange
function needs to changeYour function is looking at className
which won't work. Your inputs return form-control name
for example. Instead try using the element's name
.
Updated function:
handleChange = e => {
if (["name", "age"].includes(e.target.name)) {
let cats = [...this.state.cats];
cats[e.target.dataset.id][e.target.name] = e.target.value.toUpperCase();
this.setState({ cats }, () => console.log(this.state.cats));
} else {
this.setState({ [e.target.name]: e.target.value.toUpperCase() });
}
};
Do not render <form>
elements in other <form>
elements.
Don't do this. You don't need another form here. Just remove that.
// Line 76-80:
{cats.map((val, idx) => {
let catId = `cat-${idx}`,
ageId = `age-${idx}`;
return (
<form onSubmit={this.handleSubmit} onChange={this.handleChange}>
// ...