urlreader
urlreader

Reputation: 6615

Avoid user click submit button more than once?

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

Answers (1)

dale landry
dale landry

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

Related Questions