How to disable submit button until all input classes have class="valid"

Viewed 1098

I want to create a sign-up form. I have 6 inputs: First Name, Last Name, E-mail, Password, Password confirmation and a checkbox for user agreement. If inputs have class="valid", value is valid, otherwise invalid. I put all the classes a default class="invalid". I want to disable my submit button until all input fields have class="valid". According to my research, I saw that the button should be disabled first using the window.onload eventlistener, but I still couldn't figure out how to do it.

This is the basic form:

<form class="signup__form" action="/">
  <input class="invalid" type="text" name="fname" placeholder="name"/> </br>
  <input class="invalid" type="text" name='lname' placeholder="Last Name" /></br>
  <input class="invalid" type="email" name='email' placeholder="E-mail" /></br>
  <input class="invalid" type="password" name="password" placeholder="Password" />
  <input class="invalid" type="password" name="password" placeholder="Password Confirm" />  
  <input class="invalid" type="checkbox" /> User Agreement</br> 
  <button type="submit" >Sign Up</button>
</form>

I am controlling checkbox validation with an eventlistener:

checkbox.addEventListener('click', (e) => {
  if (e.target.checked) {
    checkbox.classList.remove('invalid');
    checkbox.classList.add('valid');
  } else {
    checkbox.classList.remove('valid');
    checkbox.classList.add('invalid');
  }
})

And for the rest, i am checking with regexs:

// Regex values
const regexs = {
  fname: /^[a-zA-Z0-9]{3,24}$/,
  lname: /^[a-zA-Z0-9]{3,24}$/,  
  email: /^([a-z\d\.-]+)@([a-z\d-]+)\.([a-z]{2,8})$/, 
  password: /^[\w@-]{8,20}$/
};

// Regex Validation
const validation = (input, regex) => {
  if (regex.test(input.value)) {
    input.classList.remove('invalid');
    input.classList.add('valid');
  } else {
    input.classList.remove('valid');
    input.classList.add('invalid');
  }
}

inputs.forEach((input) => {
  input.addEventListener('keyup', (e) => {
    validation(e.target,regexs[e.target.attributes.name.value])
  })
})
5 Answers

Something like this might come in handy.

var form = document.querySelector('.signup__form'), is_valid = false, fields, button;

form.addEventListener('change', function(){

  fields = form.querySelectorAll('input');
  button = form.querySelector('button');
  
  for (var i = fields.length - 1; i >= 0; i--) {
    if( fields[i].classList.contains('invalid') )
    {
      is_valid = false;
      break;
    }
    
    is_valid = true;
  }
  
  is_valid ? button.removeAttribute('disabled'): button.setAttribute('disabled', 'disabled');

});
<form class="signup__form" action="/">
  <input class="invalid" type="text" name="fname" placeholder="name"/> <br>
  <input class="invalid" type="text" name='lname' placeholder="Last Name" /><br>
  <input class="invalid" type="email" name='email' placeholder="E-mail" /><br>
  <input class="invalid" type="password" name="password" placeholder="Password" />
  <input class="invalid" type="password" name="password" placeholder="Password Confirm" />  
  <input class="invalid" type="checkbox" /> User Agreement<br> 
  <button type="submit" disabled>Sign Up</button>
</form>

Since you don't have all of your code, I'm adding a second example myself so that I can fully test the validation part.

But you just need to copy the above JavaScript code and set the button to disabled="disabled"in the first place.

var form = document.querySelector('.signup__form'),
  is_valid = false,
  fields, button;

form.addEventListener('change', function() {

  fields = form.querySelectorAll('input');
  button = form.querySelector('button');

  for (var i = fields.length - 1; i >= 0; i--) {

    if (fields[i].value.length) {
      fields[i].classList.remove('invalid');
    } else {
      fields[i].classList.add('invalid');
    }

    if (fields[i].classList.contains('invalid')) {
      is_valid = false;
      break;
    }

    is_valid = true;
  }

  is_valid ? button.removeAttribute('disabled') : button.setAttribute('disabled', 'disabled');

});
<form class="signup__form" action="/">
  <input class="invalid" type="text" name="fname" placeholder="name" /> <br>
  <input class="invalid" type="text" name='lname' placeholder="Last Name" /><br>
  <input class="invalid" type="email" name='email' placeholder="E-mail" /><br>
  <input class="invalid" type="password" name="password" placeholder="Password" />
  <input class="invalid" type="password" name="password" placeholder="Password Confirm" />
  <input class="invalid" type="checkbox" /> User Agreement<br>
  <button type="submit" disabled>Sign Up</button>
</form>

Note: This example does not follow because it does not validate the Checkbox.

@Enes, 1. kod parçacığındaki JavaScript kodunu kopyalarsan çalışacaktır. 2. Kodu test edebilmen için ekledim. Bir değer girilmişse onu doğru "valid" kabul eder.

I would try to the native use of HTML properties (pattern & required) and CSS instead of giving in to javascript. Just give it a go, and see how it feels like. Do note that I excluded a pattern on your email input.

The only thing I would use javascript for is to check if the password fields are the same, but I would do that by injecting the password of the first password input into the confirming password input's pattern attribute, replacing ^[\w@-]{8,20}$.

The pink background is just there to show-case the validation rules.


By the way, you got the wrong formatting on some of the HTML tags. You don't need an ending slash on input and you should type <br/>, not </br>.

input:invalid {
  background-color: pink;
}

form:invalid button[type="submit"] {
  opacity: 0.5;
}
<form class="signup__form" action="/">
  <input type="text"     required pattern="^[a-zA-Z0-9]{3,24}$" placeholder="Name"> <br/>
  <input type="text"     required pattern="^[a-zA-Z0-9]{3,24}$" placeholder="Last Name"><br/>
  <input type="email"    required placeholder="E-mail"><br/>
  <input type="password" required pattern="^[\w@-]{8,20}$" placeholder="Password"><br/>
  <input type="password" required pattern="^[\w@-]{8,20}$" placeholder="Password Confirm"><br/>
  <input type="checkbox" required>User Agreement<br/> 
  <button type="submit" >Sign Up</button>
</form>

you can use required="required", then the submit won't be called before the field has value.

A solution which tests the number of invalid classes:

var checkbox = document.querySelector("input[type=checkbox]");
var inputs = document.querySelectorAll("input:not([type='checkbox'])");
var but = document.querySelector("button[type=submit]");
but.disabled= true;
checkbox.addEventListener('click', (e) => {
  if (e.target.checked) {
    checkbox.classList.remove('invalid');
    checkbox.classList.add('valid');
  } else {
    checkbox.classList.remove('valid');
    checkbox.classList.add('invalid');
  }
  but.disabled = !document.querySelectorAll("input.invalid").length == 0;
})



// Regex values
const regexs = {
  fname: /^[a-zA-Z0-9]{3,24}$/,
  lname: /^[a-zA-Z0-9]{3,24}$/,  
  email: /^([a-z\d\.-]+)@([a-z\d-]+)\.([a-z]{2,8})$/, 
  password: /^[\w@-]{8,20}$/
};

// Regex Validation
const validation = (input, regex) => {
  if (regex.test(input.value)) {
    input.classList.remove('invalid');
    input.classList.add('valid');
  } else {
    input.classList.remove('valid');
    input.classList.add('invalid');
  }
}

inputs.forEach((input) => {

  input.addEventListener('keyup', (e) => {
    validation(e.target,regexs[e.target.attributes.name.value]);
    but.disabled = !document.querySelectorAll("input.invalid").length == 0;
  })
})
<form class="signup__form" action="/">
  <input class="invalid" type="text" name="fname" placeholder="name"/> </br>
  <input class="invalid" type="text" name='lname' placeholder="Last Name" /></br>
  <input class="invalid" type="email" name='email' placeholder="E-mail" /></br>
  <input class="invalid" type="password" name="password" placeholder="Password" />
  <input class="invalid" type="password" name="password" placeholder="Password Confirm" />  
  <input class="invalid" type="checkbox" /> User Agreement</br> 
  <button type="submit" >Sign Up</button>
</form>

We will use couple of properties to validate the form which are required, pattern, disabled and also we will use CSS properties to control the form validation


input:invalid {
  background-color: red;
}

form:invalid input[type="submit"] {
  opacity: 0.5;
  cursor: not-allowed;
}
<form class="login__form" action="/">
  <input type="email"    required placeholder="E-mail"><br/><br/>
  <input type="password" required pattern="^[\w@-]{8,20}$" placeholder="Password"><br/><br/>
  <input type="submit" >
</form>

Related