Reputation: 6615
I'm working on a asp.net MVC project. On one page, it has many controls and features. When user clicks 'submit' button, it will do many validations in the controller for the input. If something is not right, it will show the error on the page. Otherwise, will save the data in the database with a Guid, and go to the next page.
The problem is: the validation takes some time, user may accidentally click the submit button more than once which results in saving data to the database with the same Guid, which throws an error since Guid has to be unique for each data.
Is there a way to prevent user clicking more than once? We can not simply disable the button after click. If the validation has issue, then user can not submit again since the button is disabled.
Upvotes: 0
Views: 65
Reputation: 8610
You can disable the submit button until all the validation has been completed. Set an object entry for each conditional that returns true when the validation for that section of the form is complete or false if it is not validated. Then check each of these object entries at the end to make sure each one is set to true. If they are all true set to true then set the submit.disabled
to false.
NOTE: You can do this with each input as well, disabling each input until the previous input has been properly validated.
EDIT: See newer snipit for updated version.
const submit = document.getElementById('submit')
const fname = document.getElementById('fname')
const lname = document.getElementById('lname')
const email = document.getElementById('email')
const inputs = document.querySelectorAll('.input')
function emailIsValid(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
}
function nameIsValid(name) {
return name.match(/^[A-Za-z]+$/)
}
function validate(fname, lname, email, submit) {
// the validation variables to check at end to set submit.disabled to false
let fnameCheck = false,
lnameCheck = false,
emailCheck = false;
// check first name field
if (fname.value !== '' && fname.value.length > 1 && nameIsValid(fname.value)) {
fname.style.background = 'lightgreen'
fname.previousSibling.previousSibling.style.background = 'green'
fnameCheck = true
} else {
// JIC they delete reset to false
fnameCheck = false
fname.style.background = 'pink'
}
if (lname.value !== '' && lname.value.length > 2 && nameIsValid(fname.value)) {
lnameCheck = true
lname.style.background = 'lightgreen'
} else {
lnameCheck = false
lname.style.background = 'pink'
}
if (emailIsValid(email.value)) {
emailCheck = true
email.style.background = 'lightgreen'
} else {
emailCheck = false
email.style.background = 'pink'
}
// log for visual inspection of check-variable values
console.log(lnameCheck, fnameCheck, emailCheck)
// make sure all check-variables are set to true
if (fnameCheck === true && lnameCheck === true && emailCheck === true) {
submit.disabled = false
}
}
// event listener for each input on input field run the validate function
// and pass in our inputs and submit button for manipulation.
inputs.forEach(input =>
input.addEventListener('input', () => validate(fname, lname, email, submit))
)
<form action="#">
<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname" class="input"><br>
<label for="lname">Last name:</label><br>
<input type="text" id="lname" name="lname" class="input"><br>
<label for="email">email:</label><br>
<input type="text" id="email" name="email" class="input"><br>
<input type="submit" id="submit" value="Submit" disabled>
</form>
Newer snipit with notes in code
// query the input elements using their class name
const inputs = document.querySelectorAll('.input');
// an empty object to hold the validation booleans
const checkObj = {};
// email validation function
function emailIsValid(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// name validation function
function nameIsValid(name) {
// check the length,
// return if out of thresh hold
if (name.value.length < 2) {
// handle error here
return;
} else {
// else return the results of the regex match
return name.value.match(/^[A-Za-z]+$/);
}
}
// validation function
// adds/removes classes to prompt user of success or error
// adds validation boolean to checkObj
function validate(node) {
// check firstname and lastname validation
if (nameIsValid(node) && (node.id === 'fname' || node.id === 'lname')) {
// set checkObj boolean values
checkObj[node.id] = true;
// toggle classList to success
node.classList.add('success');
node.classList.remove('error');
// check email validation
} else if (emailIsValid(node.value) && node.id === 'email') {
// set checkObj boolean values
checkObj[node.id] = true;
// toggle classList to success
node.classList.add('success');
node.classList.remove('error');
} else {
// set checkObj boolean values
checkObj[node.id] = false;
// toggle classList to error
node.classList.add('error');
node.classList.remove('success');
}
// conditional to check for all
// checkObj values to evaluate to true
checkObj['fname'] === true &&
checkObj['lname'] === true &&
checkObj['email'] === true ?
// if all evaluate to true then set disabled
// attribute on submit button to false
document.getElementById('submit').disabled = false :
// else set disabled attribute on submit button to true
document.getElementById('submit').disabled = true;
}
// event listener for each input node
// pass the node into the validate function
[...inputs].forEach(input => input.addEventListener('input', () => validate(input)));
.success {
box-shadow: 0px 0px 6px 3px darkgreen;
}
.error {
box-shadow: 0px 0px 6px 3px red;
}
label {
margin-top: 1rem;
}
<form action="#">
<fieldset>
<legend for="fname">First name:</legend>
<input type="text" id="fname" name="fname" class="input">
</fieldset>
<fieldset>
<legend for="lname">Last name:</legend>
<input type="text" id="lname" name="lname" class="input"></fieldset>
<fieldset>
<legend for="email">email:</legend>
<input type="text" id="email" name="email" class="input"></fieldset>
<input type="submit" id="submit" value="Submit" disabled>
</form>
Upvotes: 1