最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is submit button getting enabled even when required inputs are empty? - Stack Overflow

programmeradmin1浏览0评论

I've got a form and a submit button that needs to be disabled until all required inputs are filled in. Some inputs are text, and some are dropdowns. I've read through lots of threads on how to handle this, and I think I'm doing it correctly, but for some reason the submit button gets enabled as soon as the user fills out the text input, even though the dropdown inputs are still empty.

For the text input, I'm checking whether the string length is 0. For the dropdowns, I'm checking whether the value is "select". Why does the submit button get enabled once the text input string is > 0, even when the dropdown values are still "select"? Here's a working codepen and see code below as well.

Update to original question: based on the answers here, it was clear to me that I should be using built-in form validation and then adding any javascript needed to customize the UI experience, rather than handling all form validation in javascript. Since I'm already using Bootstrap, I decided it would be best to refactor my code to use their form validation methods. If you're reading this question, and you happen to be using Bootstrap, check out their docs. Otherwise both the answers below will work for Javascript / jQuery.

// Input Variables
let createDigestModal = $("#create-digest-modal");
let createDigestFormContainer = $("#create-digest-modal-form-container");
let createDigestModalSubmitBtn = $("#create-digest-modal-btn");

// ========================================================================
// Toggle the submit button to disabled / enabled based on required inputs
// ========================================================================
const enableSubmitBtn = () => {
  // Create digest form
  $(createDigestFormContainer).on("keyup click", () => {
    let createDigestInputs = createDigestFormContainer.find(".required");
    let requiredCreateDigestInputs = true;

    for (let i = 0; i < createDigestInputs.length; i++) {
      console.log(createDigestInputs[i].value);
      if (createDigestInputs[i].value == "") {
        requiredCreateDigestInputs = false;
      }
    }

    createDigestModalSubmitBtn.prop("disabled", !requiredCreateDigestInputs);
  });
};

// Invoke Function to toggle submit button
enableSubmitBtn();
.row {
  margin-bottom: 1rem;
}

/* Required Fields */

.required-field::after {
  content: "*";
  color: red;
  margin-left: 2px;
}

.required-field-margin-left::after {
  content: "*";
  color: red;
  margin-left: -2px;
}
<script src=".7.1/jquery.min.js"></script>
<!-- Create Digest Modal -->
<div class="modal fade" id="create-digest-modal" tabindex="-1" aria-labelledby="create-digest-modal-label">

  <form id="create-digest-modal-form-container">
    <!-- Project Input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-project-input">Project</label>
      </div>
      <div>
        <select class="form-select required" id="create-digest-modal-project-input" type="select">

          <option value="select">Select</option>
          <option value="1">Project 1</option>
          <option value="2">Project 2</option>
        </select>
      </div>
    </div>
    <!-- /Project Input -->

    <!-- name input -->
    <div class="row">
      <div id="create-digest-name-input">
        <label id="create-digest-modal-name-input-label" for="create-digest-modal-name-input" class="required-field">Digest Name</label>
      </div>

      <div>
        <input name="create-digest-modal-name-input" type="text" id="create-digest-modal-name-input" class="required" />
      </div>
    </div>
    <!-- /name input -->

    <!-- Type input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-type-input">Type</label>
      </div>
      <div class="col-75 flex">
        <select class="form-select required" aria-label="create-digest-modal-type-input" id="create-digest-modal-type-input" type="select">
          <option value="select">Select</option>
          <option value="D">Daily</option>
          <option value="W">Weekly</option>
        </select>
      </div>
    </div>
    <!-- /Type input -->

    <!-- include summary input -->
    <div id="create-digest-modal-summary-input-container" class="row">
      <div class="col-40">
        <label class="form-check-label" for="create-digest-modal-summary-input">
          Include Summary
        </label>
      </div>
      <div class="col-75 flex">
        <input checked class="form-check-input" type="checkbox" id="create-digest-modal-summary-input" />
      </div>
    </div>
    <!-- /include summary input -->
  </form>

  <!-- Close/Update Buttons -->
  <div class="modal-footer">
    <button type="button" class="btn btn-secondary modal-close-btn" data-bs-dismiss="modal" id="create-modal-close-btn">
      Close
    </button>
    <button type="button" id="create-digest-modal-btn" class="btn btn-success" disabled>
      Add Digest
    </button>
  </div>

</div>
<!-- Create Digest Modal -->

I've got a form and a submit button that needs to be disabled until all required inputs are filled in. Some inputs are text, and some are dropdowns. I've read through lots of threads on how to handle this, and I think I'm doing it correctly, but for some reason the submit button gets enabled as soon as the user fills out the text input, even though the dropdown inputs are still empty.

For the text input, I'm checking whether the string length is 0. For the dropdowns, I'm checking whether the value is "select". Why does the submit button get enabled once the text input string is > 0, even when the dropdown values are still "select"? Here's a working codepen and see code below as well.

Update to original question: based on the answers here, it was clear to me that I should be using built-in form validation and then adding any javascript needed to customize the UI experience, rather than handling all form validation in javascript. Since I'm already using Bootstrap, I decided it would be best to refactor my code to use their form validation methods. If you're reading this question, and you happen to be using Bootstrap, check out their docs. Otherwise both the answers below will work for Javascript / jQuery.

// Input Variables
let createDigestModal = $("#create-digest-modal");
let createDigestFormContainer = $("#create-digest-modal-form-container");
let createDigestModalSubmitBtn = $("#create-digest-modal-btn");

// ========================================================================
// Toggle the submit button to disabled / enabled based on required inputs
// ========================================================================
const enableSubmitBtn = () => {
  // Create digest form
  $(createDigestFormContainer).on("keyup click", () => {
    let createDigestInputs = createDigestFormContainer.find(".required");
    let requiredCreateDigestInputs = true;

    for (let i = 0; i < createDigestInputs.length; i++) {
      console.log(createDigestInputs[i].value);
      if (createDigestInputs[i].value == "") {
        requiredCreateDigestInputs = false;
      }
    }

    createDigestModalSubmitBtn.prop("disabled", !requiredCreateDigestInputs);
  });
};

// Invoke Function to toggle submit button
enableSubmitBtn();
.row {
  margin-bottom: 1rem;
}

/* Required Fields */

.required-field::after {
  content: "*";
  color: red;
  margin-left: 2px;
}

.required-field-margin-left::after {
  content: "*";
  color: red;
  margin-left: -2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Create Digest Modal -->
<div class="modal fade" id="create-digest-modal" tabindex="-1" aria-labelledby="create-digest-modal-label">

  <form id="create-digest-modal-form-container">
    <!-- Project Input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-project-input">Project</label>
      </div>
      <div>
        <select class="form-select required" id="create-digest-modal-project-input" type="select">

          <option value="select">Select</option>
          <option value="1">Project 1</option>
          <option value="2">Project 2</option>
        </select>
      </div>
    </div>
    <!-- /Project Input -->

    <!-- name input -->
    <div class="row">
      <div id="create-digest-name-input">
        <label id="create-digest-modal-name-input-label" for="create-digest-modal-name-input" class="required-field">Digest Name</label>
      </div>

      <div>
        <input name="create-digest-modal-name-input" type="text" id="create-digest-modal-name-input" class="required" />
      </div>
    </div>
    <!-- /name input -->

    <!-- Type input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-type-input">Type</label>
      </div>
      <div class="col-75 flex">
        <select class="form-select required" aria-label="create-digest-modal-type-input" id="create-digest-modal-type-input" type="select">
          <option value="select">Select</option>
          <option value="D">Daily</option>
          <option value="W">Weekly</option>
        </select>
      </div>
    </div>
    <!-- /Type input -->

    <!-- include summary input -->
    <div id="create-digest-modal-summary-input-container" class="row">
      <div class="col-40">
        <label class="form-check-label" for="create-digest-modal-summary-input">
          Include Summary
        </label>
      </div>
      <div class="col-75 flex">
        <input checked class="form-check-input" type="checkbox" id="create-digest-modal-summary-input" />
      </div>
    </div>
    <!-- /include summary input -->
  </form>

  <!-- Close/Update Buttons -->
  <div class="modal-footer">
    <button type="button" class="btn btn-secondary modal-close-btn" data-bs-dismiss="modal" id="create-modal-close-btn">
      Close
    </button>
    <button type="button" id="create-digest-modal-btn" class="btn btn-success" disabled>
      Add Digest
    </button>
  </div>

</div>
<!-- Create Digest Modal -->

Share Improve this question edited 2 days ago Mickey Vershbow asked Feb 7 at 21:55 Mickey VershbowMickey Vershbow 3097 silver badges24 bronze badges 7
  • createDigestInputs[i].value.length == "" will never be true for the dropdowns, since the value is select. – Barmar Commented Feb 7 at 22:04
  • Use an empty string for the value of the default option, not select. – Barmar Commented Feb 7 at 22:05
  • you could use || instead of && in the condition. But then if the user enters select into the text box they won't be able to submit. – Barmar Commented Feb 7 at 22:06
  • 2 Why are you comparing length with a string, not 0? It happens to "work" because the empty string is converted to a number, which results in 0. – Barmar Commented Feb 7 at 22:08
  • 2 No need to write so much code, use the attribute required it also exists <dialog> and .showModal() see doc here – Mister Jojo Commented Feb 7 at 22:30
 |  Show 2 more comments

2 Answers 2

Reset to default 1

When the value is select, the condition createDigestInputs[i].value.length == "" fails. Since you're combining the conditions with &&, they both have to be true to disable the button, but that can't happen.

The usual solution is to use an empty value for the unselected option, so it's consistent with text inputs.

Rather than using the click event, use change to detect changes in a dropdown.

Checking for an empty input value should be done with .value == "", not .value.length == "". The only reason the latter works is because comparing a number to a string automatically converts the string to a number, and the empty string converts to 0.

You can break out of the for loop once you find an unset input.

You don't need to put createDigestFormContainer and createDigestModalSubmitBtn inside $(). They're already jQuery objects.

// Input Variables
let createDigestModal = $("#create-digest-modal");
let createDigestFormContainer = $("#create-digest-modal-form-container");
let createDigestModalSubmitBtn = $("#create-digest-modal-btn");

// ========================================================================
// Toggle the submit button to disabled / enabled based on required inputs
// ========================================================================
const enableSubmitBtn = () => {
  // Create digest form
  createDigestFormContainer.on("keyup change", () => {
    let createDigestInputs = createDigestFormContainer.find(".required");
    let requiredCreateDigestInputs = true;

    for (let i = 0; i < createDigestInputs.length; i++) {
      console.log(createDigestInputs[i].value);
      if (
        createDigestInputs[i].value == ""
      ) {
        requiredCreateDigestInputs = false;
        break;
      }
    }

    createDigestModalSubmitBtn.attr("disabled", !requiredCreateDigestInputs);

  });
};

// Invoke Function to toggle submit button
enableSubmitBtn();
.row {
  margin-bottom: 1rem;
}

/* Required Fields */

.required-field::after {
  content: "*";
  color: red;
  margin-left: 2px;
}

.required-field-margin-left::after {
  content: "*";
  color: red;
  margin-left: -2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Create Digest Modal -->
<div class="modal fade" id="create-digest-modal" tabindex="-1" aria-labelledby="create-digest-modal-label">

  <form id="create-digest-modal-form-container">
    <!-- Project Input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-project-input">Project</label>
      </div>
      <div>
        <select class="form-select required" id="create-digest-modal-project-input" type="select">

          <option value="">Select</option>
          <option value="1">Project 1</option>
          <option value="2">Project 2</option>
        </select>
      </div>
    </div>
    <!-- /Project Input -->

    <!-- name input -->
    <div class="row">
      <div id="create-digest-name-input">
        <label id="create-digest-modal-name-input-label" for="create-digest-modal-name-input" class="required-field">Digest Name</label>
      </div>

      <div>
        <input name="create-digest-modal-name-input" type="text" id="create-digest-modal-name-input" class="required" />
      </div>
    </div>
    <!-- /name input -->

    <!-- Type input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-type-input">Type</label>
      </div>
      <div class="col-75 flex">
        <select class="form-select required" aria-label="create-digest-modal-type-input" id="create-digest-modal-type-input" type="select">
          <option value="">Select</option>
          <option value="D">Daily</option>
          <option value="W">Weekly</option>
        </select>
      </div>
    </div>
    <!-- /Type input -->

    <!-- include summary input -->
    <div id="create-digest-modal-summary-input-container" class="row">
      <div class="col-40">
        <label class="form-check-label" for="create-digest-modal-summary-input">
          Include Summary
        </label>
      </div>
      <div class="col-75 flex">
        <input checked class="form-check-input" type="checkbox" id="create-digest-modal-summary-input" />
      </div>
    </div>
    <!-- /include summary input -->
  </form>

  <!-- Close/Update Buttons -->
  <div class="modal-footer">
    <button type="button" class="btn btn-secondary modal-close-btn" data-bs-dismiss="modal" id="create-modal-close-btn">
      Close
    </button>
    <button type="button" id="create-digest-modal-btn" class="btn btn-success" disabled>
      Add Digest
    </button>
  </div>

</div>
<!-- Create Digest Modal -->

If you use the build-in form validation you can use the method reportValidity() on the form to test if the button should be enabled. Give each of the required fields the attibute required, and if you don't like the validity message on each of the fields you can disable this by listening for the invalid event and then call preventDefault() on that event.

Btw. use the name attribute on all form fields and buttons. And use underscore _ instead of hyphen - for names so that you can use the dot syntax to get the elements (like form.create_digest_modal_btn).

const form01 = document.forms['create-digest-modal-form-container'];

form01.addEventListener('input', e => {
  let form = e.target.form;
  form.create_digest_modal_btn.disabled = !form.reportValidity();
});

form01.addEventListener('invalid', e => {
  e.preventDefault();
}, true);
.row {
  margin-bottom: 1rem;
}

/* Required Fields */

.required-field::after {
  content: "*";
  color: red;
  margin-left: 2px;
}

.required-field-margin-left::after {
  content: "*";
  color: red;
  margin-left: -2px;
}
<!-- Create Digest Modal -->
<div class="modal fade" id="create-digest-modal" tabindex="-1" aria-labelledby="create-digest-modal-label">

  <form id="create-digest-modal-form-container">
    <!-- Project Input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-project-input">Project</label>
      </div>
      <div>
        <select class="form-select" id="create-digest-modal-project-input" type="select" required>

          <option value="">Select</option>
          <option value="1">Project 1</option>
          <option value="2">Project 2</option>
        </select>
      </div>
    </div>
    <!-- /Project Input -->

    <!-- name input -->
    <div class="row">
      <div id="create-digest-name-input">
        <label id="create-digest-modal-name-input-label" for="create-digest-modal-name-input" class="required-field">Digest Name</label>
      </div>

      <div>
        <input name="create-digest-modal-name-input" type="text" id="create-digest-modal-name-input" required>
      </div>
    </div>
    <!-- /name input -->

    <!-- Type input -->
    <div class="row">
      <div class="col-40">
        <label class="required-field" for="create-digest-modal-type-input">Type</label>
      </div>
      <div class="col-75 flex">
        <select class="form-select" aria-label="create-digest-modal-type-input" id="create-digest-modal-type-input" type="select" required>
          <option value="">Select</option>
          <option value="D">Daily</option>
          <option value="W">Weekly</option>
        </select>
      </div>
    </div>
    <!-- /Type input -->

    <!-- include summary input -->
    <div id="create-digest-modal-summary-input-container" class="row">
      <div class="col-40">
        <label class="form-check-label" for="create-digest-modal-summary-input">
          Include Summary
        </label>
      </div>
      <div class="col-75 flex">
        <input checked class="form-check-input" type="checkbox" id="create-digest-modal-summary-input">
      </div>
    </div>
    <!-- /include summary input -->

    <!-- Close/Update Buttons -->
    <div class="modal-footer">
      <button type="button" class="btn btn-secondary modal-close-btn" data-bs-dismiss="modal" id="create-modal-close-btn">
      Close
    </button>
      <button type="button" name="create_digest_modal_btn" class="btn btn-success" disabled>
      Add Digest
    </button>
    </div>
  </form>


</div>
<!-- Create Digest Modal -->

发布评论

评论列表(0)

  1. 暂无评论