How to handle multiple onChange function from multiple input fields in Reactjs - reactjs

I have a form which has 5 input text type fields and a input file type field. I used onChange function.
this is the form
<form onSubmit ={this.onSubmit.bind(this)} >
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Company Name" name="companyName" ref="companyName"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Account Name" name="AccountName" ref="AccountName" />
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Bank Name" name="bankName" ref="bankName"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Branch" name="branch" ref="branch"/>
</FormGroup>
<FormGroup bssize="sm">
<input onChange={this.handleChange} className="form-control" type="text" placeholder="Account Number" name="accountNo" ref="accountNo"/>
</FormGroup>
<FormGroup>
<span>Bank Book Copy</span>
<input style={{display :'none'}} type="file" onChange={this.fileSelectedHandler} ref={fileInput => this.fileInput = fileInput } />
<Button onClick={()=>this.fileInput.click()} >
<Icon type="upload" /> Click to upload
</Button>
</FormGroup>
<input onClick={this.fileUploadHandler} className="btn btn-primary" bsstyle="success" name="submit" type="submit" value="Submit" />
</form>
now my problem is which filed filled at last only post into my API.I used AXIOS for HTTP request.
I used storage-connector for upload images
below I mentioned my onChange function
constructor(props){
super(props);
this.state = {
companyName : '',
AccountName : '',
bankName : '' ,
bankBookCpy : '' ,
accountNo : '' ,
branch : '' ,
BankList : '',
selectedFile : null,
}
}
fileSelectedHandler = event =>{
this.setState({
selectedFile: event.target.files[0]
})
}
handleChange = event => {
this.setState({
companyName: event.target.value,
AccountName: event.target.value,
bankName: event.target.value,
accountNo: event.target.value,
branch: event.target.value
});
}
fileUploadHandler = () => {
const fd = new FormData();
fd.append('image',this.state.selectedFile, this.state.selectedFile.name )
axios.post('http://localhost:3000/api/attachmentBanks/bankBookCpy/upload',fd , {
onUploadProgress : ProgressEvent => {
console.log('Upload Progress: ' + Math.round(ProgressEvent.loaded / ProgressEvent.total *100) + '%')
}
})
.then(res => {
this.setState({
BankList: res.data.result.files.image[0].name,
});
});
}
AddMeetup(newMeetup){
axios.request({
method:'post',
url:'http://localhost:3000/api/companyBankDetails',
data : newMeetup
}).then(response => {
this.props.history.push('/');
}).catch(err => console.log(err));
onSubmit(e){
const newMeetup = {
companyName: this.state.companyName,
AccountName : this.state.AccountName,
bankName : this.state.bankName,
branch : this.state.branch,
accountNo : this.state.accountNo,
bankBookCpy : this.state.BankList
}
this.AddMeetup(newMeetup);
e.preventDefault();
}
Above functions are only stored last onChange value

You can handle it like this:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};

First change you handleChange function to the following :
handleChange = name => event => {
this.setState({ [name]: event.target.value} );
}
Then send your name argument to the onChange function :
<form onSubmit ={this.onSubmit.bind(this)} >
{
Object.entries({
"Company Name": "companyName",
"Account Name": "AccountName",
"Bank Name": "bankName",
"Branch": "branch",
"Account Number": "accountNo"
}).map(([field, name]) =>
<FormGroup bssize="sm" key={name}>
<input onChange={this.handleChange(name)} className="form-control" type="text" placeholder={field} name={name} ref={name} />
</FormGroup>)
}
<FormGroup>
You can avoid repetitions in your code by also mapping an array to create your form

Here your issue is you call same handleChange() Function on each onChange event. let's assume you change "company name" input field. When you change it you will call the handleChange() function. Then inside that function, you assign event.target.value to all of the fields(companyName, AccountName, etc). But event.target.value only give you the data from the field that you are changing to call the handleChange() method, In this case, it is "company Name" input. So this will replace all of your form data states with the text you entered in "Company Name".
So, the hard way is you can create separate functions to handle each input fields. But it is not good practice. Instead, you can do as answered by SakoBu.
that method will take state name from event.target.name and state data from event.target.value. So if you change the value of "Company Name" your state update code in the handleChange() will be the same as companyName: event.target.value, but only change CompanyName state, not other form states.
You don't need to worry about image uploading system. Because you can use your existing fileUploadHandler() method to handle the changes of the file uploading.

As answered by SakoBu, the approach would solve your problem.
One thing I noticed is you are assigning ref to each input field, you don't need to do so.
Please do remember that if input type is checkbox,radiobutton you will get corresponding value by event.taget.checked.
It's always a good practise to check event type, by event.target.type.
For more details visit :-
https://reactjs.org/docs/forms.html
Hope this Helps,
Cheers !!

Related

How to add n number of emails in react?

I have created a user registration form which contains of firstname,lastname,email etc.
Here a user can add n number of emails.For this,I have created a button and onClick it should open the input field.
<--Here is the code -->
const [formData, setFormData] = useState({
firstname: "",
lastname: "",
email: "",
})
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
const newStudent = {
firstname,
lastname,
email,
}
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify(newStudent);
await axios.post(`http://localhost:5000/student`, body, config);
}
const handleClick = () => {
return <Input type="email" name="email" value={email} onChange={handleChange} />
};
return (
<Form className={classes.root} onSubmit={handleSubmit}>
<div>
<Input
id="standard-multiline-flexible"
label="First Name"
multiline
name="firstname"
value={firstname}
onChange={handleChange}
/>
</div>
<div>
<Input
id="standard-multiline-flexible"
label="Last Name"
name="lastname"
value={lastname}
onChange={handleChange}
multiline
/>
</div>
<div>
<Input
id="standard-multiline-static"
type="email"
label="Email"
name="email"
onChange={handleChange}
value={email}
multiline
/>
<button className="btn btn-primary" onClick={handleClick}>
Add
</button>
<PrimaryButton>Submit</PrimaryButton>
</Form>
)
Can anyone tell me how should I define the handleClick() so that whenever I click the add button,it renders a new Input field?
Another way you could achieve this if you want the user to see their input emails remove them etc is to do the following:
Create an emails state array.
Add an email text field with an add button next to it.
When the user enters an email and presses add, add that email to the array.
You can then map the array to show the added emails as a list with the option to delete the emails if the user decides to.
At the end of handle click
Instead of doing this
return <Input type="email" name="email" value={email} onChange={handleChange} />
Do this ->
setFormData({firstname: "",lastname: "",email: ""});
Edits
You can display the emails via a list after making the API call
You can have a delete button to delete that email from the list.
"There are n ways to implement. Please be more specific"

React Boostrap input form doesn't give any value

Hi everybody Tring to make a form with Form provided by bootstap but it doesn't work.
If I insert value it doesn't let me type, without value I digit but I can't get the value.
(I have also a Gatsby theme activated)
const StandAdd = () => {
const [item, setItem] = useState({
title: "",
kindof: "",
website: "",
image01: "",
image02: "",
image03: "",
})
const { title, kindof, website, image01, image02, image03 } = item
const handleInputChange = event => {
event.preventDefault()
setItem({ ...item, [event.target.name]: event.target.value })
}
const handleSubmit = event => {
event.preventDefault()
alert(`${title} ${item} ${website}`) // always empty I gat get anything
}
return (
<Layout>
<form onSubmit={handleSubmit}>
<Form>
<Form.Group controlId="title">
{/* <Form.Label>Email address</Form.Label> */}
<Form.Control
value={titlet} // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</form>
</Layout>
)
}
export default StandAdd
Any idea?
The issue is here:
<Form.Control
value="title" // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
here you have to provide the name attribute so that your code:
setItem({ ...item, [event.target.name]: event.target.value })
will get some value in event.target.name.
So after adding name the code will be like:
<Form.Control
type="text"
name="title" <---- name added here
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
And don't provide a hard-coded value to input like this:
value="title"
instead use defaultValue for providing an initial value.
I think you need to provide name attribute to <Form.Control> component.

I can't type in input text using reactjs

i can't change text when typing in input text !
This is my fontend code :
constructor(props) {
super(props);
this.state = {
items: [],
acc_email: '',
acc_nom: '',
acc_prenom: '',
acc_tel: '',
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
the value of input comes from DB using fetch :
componentDidMount(){
const token = localStorage.getItem('toktok');
fetch(`${API}/api/account`,{
method: 'GET',
headers :{
'authorization': `Bearer ${token}`,
}
})
.then(results => {
return results.json();
})
.then(data => {
this.setState({ items: data.result });
console.log("account: ",data.result);
// localStorage.setItem('mymy', "fiss");
// console.log(items);
// console.log(items.length);
})
.catch(err => {
console.log("erroooor : ",err);
});
}
i don't know what's wrong in this function :
handleInputChange = e => {
const name = e.target.name;
const value = e.target.value;
this.setState({[name]: value});
this.setState({ [e.target.name]: e.target.value });
}
and finally, this's the render() that conains all inputs:
<div key={items._id}>
<input type="text" value={items.email} name="acc_email" onChange={this.handleInputChange} />
<input type="text" value={items.nom} name="acc_nom" onChange={this.handleInputChange} />
<input type="text" value={items.prenom} name="acc_prenom" onChange={this.handleInputChange} />
<input type="text" value={items.tel} name="acc_tel" onChange={this.handleInputChange} />
<a className="admin-btn-update" href={`/updateaccount/${items._id}`}>Modifier</a>
</div>
change value to defaultValue as follows.
<input type="text" defaultValue={items.email} name="acc_email" onChange={this.handleInputChange} />
You are explicitly setting the values of the inputs to be items.email, items.nom.. which makes them controlled inputs, which basically means that it's the component responsibility to control what happens to those inputs.
Since you already implemented the part that updates the component state, all you need to do is to make the inputs values reflect this state:
<input type="text" value={this.state.acc_email} name="acc_email" onChange={this.handleInputChange} />
<input type="text" value={this.state.acc_nom} name="acc_nom" onChange={this.handleInputChange} />
<input type="text" value={this.state.acc_prenom} name="acc_prenom" onChange={this.handleInputChange} />
<input type="text" value={this.state.acc_tel} name="acc_tel" onChange={this.handleInputChange} />

how to perform crud operation in react with firebase database

I am trying on trial and error basis. I tried to insert username and password in the database using reactjs by event handling, but whenever I enter the username and the password both fields get the same value. For example, if I put 'ABC' as username and 123 as password then the username and password will get same value 123 in the database.
1.trying to insert data using event handling.
class Login extends Component{
ref = firebase.firestore().collection('login');
state = {
username: '',
password: ''
};
handleChange = (event) => {
const state = this.state
state.username = event.target.value;
state.password=event.target.value;
//console.log(state[event.target.username]);
//console.log(state[event.target.password]);
this.setState({username:state.username,
password:state.password });
console.log(state.username);
console.log(state.password);
}
onSubmit = (event) => {
event.preventDefault();
const { username,password } = this.state;
this.ref.add({
username,
password
}).then((docRef) => {
this.setState({
username: '',
password:''
});
this.props.history.push("/")
})
.catch((error) => {
console.error("Error adding document: ", error);
});
}
render()
{
return(
<form onSubmit={this.onSubmit}>
<div className="container mt-5 w-50">
<div className="form-group">
<label for= "user name" className="">User Name:</label>
<input type="text" name="userName" placeholder="UserName" className="form-control w-50" onChange={this.handleChange.bind(this)}/><br/>
<label for="password" className="">Password:</label>
<input type="password" name="password" placeholder="password" className="form-control w-50" onChange={this.handleChange.bind(this)}/><br/>
<button name="Login" className="btn btn-success w-50 mb-3">Login</button><br/>
{/* Don't Have an Account? SignUp */}
<Link to="/signup">Don't Have an Account? SignUp</Link>
</div>
</div>
</form>
);
}
}
export default Login;
username and password should get their actual values.
I believe this is because you are setting the state of both to the same value (event.target.value) in your event handler. You're also mutating state which is not a good thing to do in any situation.
in your handleChange function you are changing username AND password state values to the value of event.target.value which will happen when onChange fires in whichever input you are using handleChange as a listener.
change your handleChange function to this:
handleChange = event => {
let {name, value} = event.target;
this.setState({
[name]: value
});
}
by using {[name]: value} when the event fires in an input with name="password" the password value in your component's state will update
Your render function is a bit confusing but I am going to assume you're rendering a form with labels for username and password...
then in your input within your form (which I can't see in your markdown above, but I'm assuming is in the Login component):
<input name="username" value={this.state.username} onChange={this.handleChange} />
<input name="password" value={this.state.password} onChange={this.handleChange} />

How to display EditText details below Labels in React js?

Im try to display what user input below edit text but its not working all text fields link together
How can I make it work I need to display what user enter in below Label
class ComposedTextField extends React.Component {
state = {
name: '',
title: '',
email: '',
experience: ''
};
handleChange = event => {
this.setState({
name: event.target.value,
title: event.target.value,
email: event.target.value,
experience: event.target.value
});
};
render() {
const { classes } = this.props;
return (
<div className={classes.container}>
<Typography variant="headline">Header Info</Typography>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="name-simple">Name</InputLabel>
<Input id="name-simple" value={this.state.name} onChange={this.handleChange}/>
<p>{this.state.name}</p>
</FormControl>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="title-simple">Title</InputLabel>
<Input id="title-simple" value={this.state.title} onChange={this.handleChange}/>
<p>{this.state.title}</p>
</FormControl>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="email-simple">Email</InputLabel>
<Input id="email-simple" value={this.state.email} onChange={this.handleChange}/>
<p>{this.state.email}</p>
</FormControl>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="experience-simple">Experience</InputLabel>
<Input id="experience-simple" value={this.state.experience} onChange={this.handleChange}/>
<p>{this.state.experience}</p>
</FormControl>
</div>
);
}
}
How can I make this work please help me Im newbie
Change handleChange method to this
handleChange = event => {
this.setState({ [event.target.name]:event.target.value });
};
And decorate your input text elements with name attribute i.e.
<Input name="name" id="name-simple" value={this.state.name} onChange={this.handleChange}/>
<Input name="email" id="email-simple" value={this.state.email} onChange={this.handleChange}/>
Similarly you can do it for rest of the elements.
Now when you input something in the textboxes it will be set in state with current target's name and value
Use your handle change method like as follows. This will fix yours
handleChange = event => {
const { name, value } = event.target
this.setState({ [name]: value });
};

Resources