AbsoluteBeginner
AbsoluteBeginner

Reputation: 2255

Disable form submit button until all input/textarea fields are filled, without using for loop (no jQuery)

I have the following contact form:

<form id="post">
  <label for="name">Name</label>
  <input id="name" name="name" type="text">
  <label for="surname">Surname</label>
  <input id="surname" name="surname" type="text">
  <label for="email">E-mail</label>
  <input id="email" name="email" type="text">
  <label for="subject">Object</label>
  <input id="subject" name="subject" type="text">
  <label for="text">Text</label>
  <textarea id="text" name="text"></textarea>
  <button type="submit" disabled>Submit</button>
  <!-- Honeypot -->
  <div style="position:absolute;left:-5000px" aria-hidden="true">
    <input type="text" name="ijdssliouhois8ds8989sd" tabindex="-1" value="">
  </div>
  <!-- /Honeypot -->
</form>

In order to disable submit button until all input/textarea fields are filled, I'm using the following code:

post.oninput = function() {
  var empty = false;
  for (var i = 0; i < 5; i++) {
    if (post[i].value.trim() === "") {
      empty = true;
    }
  }
  if (empty) {
    post[5].disabled = true;
  } else {
    post[5].disabled = false;
  }
};

It works perfectly.

post.oninput = function() {
  var empty = false;
  for (var i = 0; i < 5; i++) {
    if (post[i].value.trim() === "") {
      empty = true;
    }
  }
  if (empty) {
    post[5].disabled = true;
  } else {
    post[5].disabled = false;
  }
};
<form id="post">
  <label for="name">Name</label>
  <input id="name" name="name" type="text">
  <label for="surname">Surname</label>
  <input id="surname" name="surname" type="text">
  <label for="email">E-mail</label>
  <input id="email" name="email" type="text">
  <label for="subject">Object</label>
  <input id="subject" name="subject" type="text">
  <label for="text">Text</label>
  <textarea id="text" name="text"></textarea>
  <button type="submit" disabled>Submit</button>
  <!-- Honeypot -->
  <div style="position:absolute;left:-5000px" aria-hidden="true">
    <input type="text" name="ijdssliouhois8ds8989sd" tabindex="-1" value="">
  </div>
  <!-- /Honeypot -->
</form>

But I would like to achieve the same result using methods such .filter, .find, .map or .some - if possible (the best one in terms of performance).

Would you give me some suggestions?

Upvotes: 0

Views: 838

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 370879

Use the :scope > [name] query string to select children of the form which are input-like, and if .some of them aren't filled, disable the button:

const post = document.querySelector('form');
post.oninput = function() {
  post.querySelector('button').disabled = [...post.querySelectorAll(':scope > [name]')]
    .some(input => !input.value.trim())
};
<form id="post">
  <label for="name">Name</label>
  <input id="name" name="name" type="text">
  <label for="surname">Surname</label>
  <input id="surname" name="surname" type="text">
  <label for="email">E-mail</label>
  <input id="email" name="email" type="text">
  <label for="subject">Object</label>
  <input id="subject" name="subject" type="text">
  <label for="text">Text</label>
  <textarea id="text" name="text"></textarea>
  <button type="submit" disabled>Submit</button>
  <!-- Honeypot -->
  <div style="position:absolute;left:-5000px" aria-hidden="true">
    <input type="text" name="ijdssliouhois8ds8989sd" tabindex="-1" value="">
  </div>
  <!-- /Honeypot -->
</form>

You could also use the required attribute, if it'll suit your needs, though the button won't appear disabled - rather, it'll redirect the user to the next required field:

<form id="post">
  <label for="name">Name</label>
  <input required id="name" name="name" type="text">
  <label for="surname">Surname</label>
  <input required id="surname" name="surname" type="text">
  <label for="email">E-mail</label>
  <input required id="email" name="email" type="text">
  <label for="subject">Object</label>
  <input required id="subject" name="subject" type="text">
  <label for="text">Text</label>
  <textarea required id="text" name="text"></textarea>
  <button type="submit">Submit</button>
  <!-- Honeypot -->
  <div style="position:absolute;left:-5000px" aria-hidden="true">
    <input type="text" name="ijdssliouhois8ds8989sd" tabindex="-1" value="">
  </div>
  <!-- /Honeypot -->
</form>

Upvotes: 1

Related Questions