You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

jQuery表单验证优化:解决重复提示及添加单选/复选/下拉框验证

Great question! Let's fix both issues you're facing: the duplicate error messages and adding validation for radio buttons, checkboxes, and select menus. Here's how to do it step by step:

1. Fixing Duplicate Error Messages

The root cause is that every form submission adds new error elements without clearing old ones. We'll add cleanup logic at the start of validation to reset previous errors.

2. Adding Validation for Radio, Checkbox, and Select

These elements need unique validation logic since their value handling differs from text inputs:

  • Radio Buttons: Verify at least one option in the group is selected
  • Checkboxes: Ensure at least one option in the group is checked
  • Select Menus: Confirm a non-default (non-empty value) option is chosen

Here's the complete updated code:

JavaScript

var Validator = function(formObject) {
  this.form = $(formObject);

  var Elements = {
    name: {
      reg: /^[a-zA-Z]{2,20}$/,
      error: "Not a valid name.",
    },
    email: {
      reg: /^[a-z0-9_+.-]+\@([a-z0-9-]+\.)+[a-z0-9]{2,7}$/i,
      error: "Not a valid e-mail address.",
    },
    message: {
      reg: /^(?!\s*$).+/,
      error: "Message field cannot be empty.",
    },
    radio: {
      error: "Please select an option.",
    },
    checkbox: {
      error: "Please select at least one option.",
    },
    select: {
      error: "Please select an option.",
    }
  };

  var handleError = function(element, message) {
    // Add error class to input elements (or group parent for radio/checkbox)
    if (element.is('input[type="radio"], input[type="checkbox"]')) {
      element.addClass('input-error');
    } else {
      element.addClass('input-error');
    }

    var $errContainer = element.is('div') ? element : element.parent('div');
    var $error = $errContainer.find('.error');

    // Only create a new error element if none exists
    if ($error.length === 0) {
      $error = $('<div class="error"></div>').text(message);
      $error.appendTo($errContainer);
    } else {
      $error.text(message).show(); // Update text and show if hidden
    }

    // Bind appropriate event to clear error on user input
    if (element.is('input[type="text"], input[type="email"], textarea')) {
      element.off('keyup').on('keyup', function() {
        $error.fadeOut(1000, function() {
          element.removeClass('input-error');
        });
      });
    } else if (element.is('input[type="radio"], input[type="checkbox"]')) {
      element.off('change').on('change', function() {
        $error.fadeOut(1000, function() {
          element.removeClass('input-error');
        });
      });
    } else if (element.is('select')) {
      element.off('change').on('change', function() {
        $error.fadeOut(1000, function() {
          element.removeClass('input-error');
        });
      });
    }
  };

  this.validate = function() {
    // Clear all existing errors before validating
    this.form.find(".error").remove();
    this.form.find(".input-error").removeClass("input-error");

    var errorCount = 0;
    this.form.find("input, textarea, select").each(function(index, field) {
      var $field = $(field);
      var type = $field.data("validation");
      var validation = Elements[type];

      if (validation) {
        let isValid = true;

        switch(type) {
          case 'radio':
            // Check if any radio in the group is selected
            isValid = this.form.find(`input[name="${$field.attr('name')}"]:checked`).length > 0;
            break;
          case 'checkbox':
            // Check if any checkbox in the group is checked
            isValid = this.form.find(`input[name="${$field.attr('name')}"]:checked`).length > 0;
            break;
          case 'select':
            // Check if select has a non-empty value
            isValid = $field.val() !== "";
            break;
          default:
            // Default validation for text inputs
            isValid = validation.reg.test($field.val());
            break;
        }

        if (!isValid) {
          errorCount++;
          // For radio/checkbox groups, target the parent container for error placement
          const targetElement = (type === 'radio' || type === 'checkbox') ? $field.closest('div') : $field;
          handleError(targetElement, validation.error);
        }
      }
    }.bind(this)); // Bind 'this' to access the form object inside the each loop

    return errorCount === 0;
  };
};

$(function(){
  $("form#test").on("submit", function(event){
    event.preventDefault(); // Prevent default form submission to test validation
    const isValid = new Validator(this).validate();
    if (isValid) {
      console.log("Form is valid! Submitting...");
      this.submit(); // Uncomment to submit form if valid
    }
  })
})

CSS

body { 
  background: #fff; 
  color: #333; 
  font: 76% Verdana, sans-serif; 
}
form { 
  margin: 1em 0 0 2em; 
  width: 90%; 
}
fieldset { 
  margin: 0; 
  border: 1px solid #ccc; 
  padding-bottom: 1em; 
}
legend { 
  font-weight: bold; 
  text-transform: uppercase; 
}
label { 
  float: left; 
  width: 5em; 
  padding-right: 2em; 
  font-weight: bold; 
}
div { 
  margin-bottom: 30px; 
}
input { 
  font: 1em Verdana, sans-serif; 
}
fieldset ul li input { 
  float: left; 
  width: 120px; 
  border: 1px solid #ccc; 
}
textarea { 
  width: 300px; 
  height: 200px; 
  border: 1px solid #ccc; 
  font: 1em Verdana, sans-serif; 
}
form p { 
  margin: 0; 
  padding: 0.4em 0 0 7em; 
}
form p input { 
  background: #666; 
  color: #fff; 
  font-weight: bold; 
}
div.error { 
  clear: left; 
  margin-left: 5.3em; 
  color: red; 
  padding-right: 1.3em; 
  height: 100%; 
  padding-bottom: 0.3em; 
  line-height: 1.3; 
}
.input-error { 
  background: #ff9; 
  border: 1px solid red; 
}

HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post" id="test">
  <fieldset>
    <legend>Contact information</legend>
    <div>
      <label for="firstname">Firstname:</label>
      <input type="text" name="firstname" id="firstname" data-validation="name" />
    </div>
    <div>
      <label for="lastname">Lastname:</label>
      <input type="text" name="lastname" id="lastname" data-validation="name" />
    </div>
    <div>
      <label for="email">Email:</label>
      <input type="email" name="email" id="email" data-validation="email"/>
    </div>
    <div>
      <label>Gender:</label>
      <input type="radio" name="gender" data-validation="radio" value="male"> Male
      <input type="radio" name="gender" data-validation="radio" value="female"> Female
    </div>
    <div>
      <label>Hobbies:</label>
      <input type="checkbox" name="hobbies" data-validation="checkbox" value="reading"> Reading
      <input type="checkbox" name="hobbies" data-validation="checkbox" value="sports"> Sports
      <input type="checkbox" name="hobbies" data-validation="checkbox" value="music"> Music
    </div>
    <div>
      <label for="country">Country:</label>
      <select id="country" name="country" data-validation="select">
        <option value="">Select a country</option>
        <option value="usa">USA</option>
        <option value="canada">Canada</option>
        <option value="uk">UK</option>
      </select>
    </div>
    <div>
      <label for="message">Message:</label>
      <textarea id="message" name="message" cols="30" rows="15" data-validation="message"></textarea>
    </div>
    <p><input type="submit" name="send" id="send" value="Send" /></p>
  </fieldset>
</form>

Key Improvements:

  • Error Cleanup: We clear all existing errors before running validation to prevent duplicates.
  • Group Validation: For radio and checkbox groups, we check the entire group using their shared name attribute.
  • Event Handling: Bound appropriate events (keyup for text inputs, change for radio/checkbox/select) to clear errors when the user corrects their input.
  • Error Element Reuse: Instead of creating new error elements every time, we reuse existing ones if they exist.

内容的提问来源于stack exchange,提问作者Husna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 09:08:43