Reputation: 1554
Clicking on Submit invokes my onSubmit
function where it does 2 things:
formValidity
(bool)The issue is that it fails on first click and only submits on the second time. I understand this is coming from eval that submits even though it doesn't yet have the states set and fails on first run.
I would like onSubmit to preform setStates and only then preform eval for sending the mail in one click.
Please note: I've tried splitting the function and that had the same result.
I'm assuming a callback would be in place here yet I don't know how to apply this correctly with ES6.
<button onClick={(event) => this.onSubmit(event)}>Submit</button>
onSubmit = (event) => {
event.preventDefault();
if (!validator.isEmail(this.state.email)) {
this.setState({
errorType: this.state.formErrors["email"],
formValidity: false
})
} else {
this.setState({
formValidity: true
})
}
if (!validator.isAlpha(this.state.fName) || !validator.isAlpha(this.state.lName)) {
this.setState({
errorType: this.state.formErrors["name"],
formValidity: false
})
} else {
this.setState({
formValidity: true
})
}
if (this.state.formValidity === true) {
console.log('mail sent!');
} else {
console.log('One of the inputs is erroneous');
}
}
Just to iterate to make sure I explained this well, I would like if (this.state.formValidity === true)
to run **only after ** all the other conditionals eval'd and stay in the same function scope.
thanks, Bud
Upvotes: 0
Views: 112
Reputation: 853
Remove the event handler from the button and add it to your form element: <form onSubmit={this.handleOnSubmit}>
and bind this.handleOnSubmit
in the constructor.
Regarding your checkups, I would advise you to perform your check for each of the input fields upon their change event and update the state accordingly. For example:
<input name="email" onChange={this.validateEmail}>
And this (binded) function can perform your check for the email
field, if it’s valid and if the name
field is valid, simply update the this.formValidity
state to true.
Then, in your handleOnSubmit
function, remove everything except for your form validation checkup.
EDIT:
Change all your inputs' onChange
handlers to contain a reference to a specific function that will perform a validation for certain input field (and update the corresponding field's value - if you are already using that). For example (referring to the input field from before):
validateEmail() {
// Update input's state value
// Perform validation for email input and update corresponding state
}
Now the thing is, I would advise you to create additional state properties (one for each input field) to track individual field's validity state, like so:
this.state = {
...,
fNameValid: false,
lNameValid: false,
emailValid: false,
telValid: false,
}
Now your specific validation functions will only update the state that is concerned with the specific field, not the whole form (and your errorType):
validateEmail() {
// Update input's state value
if (!validator.isEmail(this.state.email)) {
this.setState({
emailValid: false,
errorType: this.state.formErrors["email"],
})
} else {
this.setState({
emailValid: true
})
}
}
Finally, have your onSubmit
event handler perform the checkup for all fields:
handleOnSubmit() {
let isFormValid = this.state.fNameValid
&& this.state.lNameValid
&& this.state.emailValid
&& this.state.telValid;
if (isFormValid) {
console.log('mail sent!');
} else {
console.log('One of the inputs is erroneous');
}
}
State's formValidity
property becomes redundant in the end.
Upvotes: 2
Reputation: 114
Do you need to test formValidity
's value from state? If not, if (this.state.formValidity === true)
is overkill, and you can restructure your logic so that the async nature of setState
is easier to account for — something like:
onSubmit = event => {
event.preventDefault()
let formValidity = true
let errorType = undefined
if (!validator.isEmail(this.state.email)) {
formValidity = false
errorType = this.state.formErrors.email
} else if (!validator.isAlpha(this.state.fName) || !validator.isAlpha(this.state.lName)) {
formValidity = false
errorType = this.state.formErrors.name
}
if (!formValidity) {
this.setState({
formValidity,
errorType
}, () => console.log('Form is invalid'))
} else {
this.setState({
formValidity,
errorType
}, () => console.log('Form is valid'))
}
}
You'll also see I take advantage of setState
's callback, which can be safely assumed to run only after the state has been set.
Upvotes: 1
Reputation: 1475
setState is an async function,you could add the mail sent code or any such code dependent on formValidity=true as a callback to the setState function so there should be no need of the last if-else block.Always avoid the last if-else block since setState runs in an async manner.
this.setState({
formValidity: true
},function(){
console.log("mail sent");
//or any other code dependent on formValidity set to true.
});
Upvotes: 0