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

动态添加的Select2组件无法触发jQuery Validation验证问题

购物车表单验证失效问题

我正在开发一个支持用户添加多商品到购物车的表单,要求所有必填字段(商品选择、数量)不能为空。目前用了Select2插件、jQuery Validator和jQuery实现,但即使配置了验证规则,字段为空时表单仍能提交。

我给字段加了统一类名,希望对所有现有及新增行的商品选择框、数量输入框应用必填验证,阻止未填时提交表单。

<form name='CartForm' id='CartForm' method='post'>
<table class="table table-condensed table-bordered no-padding" id="myTable">    <thead>
    <tr role="row" class="bg-blue">
         <th class="tcenter" style="vertical-align:top; width:30%">Item #, UPC or Item Name</th>
         <th class="tcenter" style="vertical-align:top; width:7%">Quantity</th>
         <th class="tcenter" style="vertical-align:top; width:9%">PO Number</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td class="tleft">
            <select name="view_by_item[]" data-id="1" id="view_by_item1" class="form-control view_by_item" style='width: 100%'></select>
        </td>
        <td class="tcenter">
            <input type="number" name="qty[]" id="qty1" class="qty form-control" style="text-align:right">
        </td>
        <td class="tcenter">
            <input type="text" name="ponum[]" class="ponum form-control" placeholder="Optional">
        </td>
    </tr>
    <tr>
        <td class="tleft">
            <select name="view_by_item[]" data-id="2" id="view_by_item2" class="form-control view_by_item" style='width: 100%'></select>
        </td>
        <td class="tcenter">
            <input type="number" name="qty[]" id="qty2" class="qty form-control" style="text-align:right">
        </td>
        <td class="tcenter">
            <input type="text" name="ponum[]" class="ponum form-control" placeholder="Optional">
        </td>
    </tr>
    </tbody>
 </table>

<button type="button" class="btn btn-secondary plusbutton"> Add Item</button>
<button class="btn btn-primary  btn-flat" id="Place_order_btn">Place Order</button>
</form>
function formatRepo (repo) {
  if (repo.loading) {
    return repo.text;
  }

  var $container = $(
    "<div class='select2-result-repository clearfix'>" +
      "<div class='select2-result-repository__meta'>" +
        "<div class='select2-result-repository__title'></div>" +
        "</div>" +
      "</div>" +
    "</div>"
  );

  $container.find(".select2-result-repository__title").text(repo.full_name);
  return $container;
}

function formatRepoSelection (repo) {
  return repo.full_name || repo.text;
}


function attachItems(item_elt){
    
    item_elt = typeof(item_elt) == 'undefined'?'.view_by_item':item_elt;
    $(document).find(item_elt).select2({
        ajax: {
            url: "https://api.github.com/search/repositories",
            dataType: 'json',
            delay: 250,
            data: function (params) {
              return {
                q: params.term, // search term
                page: params.page
              };
            },
            processResults: function (data, params) {
              params.page = params.page || 1;

              return {
                results: data.items,
                pagination: {
                  more: (params.page * 30) < data.total_count
                }
              };
            },
            cache: true
          },
          placeholder: 'Search for a repository',
          minimumInputLength: 3,
          templateResult: formatRepo,
          templateSelection: formatRepoSelection
    });
}
var rowCount = 2;
$(document).on('click', '.plusbutton',function(e){
    e.preventDefault();
    
    rowCount++;
    
    
    var newRow = '<tr>';

    newRow += '<td class="tleft"><select name="view_by_item[]"  data-id="'+rowCount+'"  id="view_by_item'+rowCount+'" class="form-control view_by_item"  style="width: 100%"></select></td>';
    newRow += '<td class="tcenter"><input  type="number" name="qty[]" id="qty'+rowCount+'" class="qty form-control"  style="text-align:right" /></td>'; 
    newRow += '<td class="tcenter"><input type="text" name="ponum[]" class="ponum form-control"  placeholder="Optional"/></td>';    
   
    $("#myTable tbody").append(newRow);
    attachItems('#view_by_item'+rowCount);
});

attachItems();


$('#CartForm').validate({
    ignore: [],
    rules:{
        '.view_by_item':{required: true},
        '.qty': {required: true}
        },
    submitHandler: function() {
        alert('No errors');
        return false;
        }   
});

问题分析与修复方案

核心问题

jQuery Validator的rules配置不支持直接用类名作为键,必须针对表单元素的name属性,或者通过rules('add')方法动态绑定规则。另外,Select2会隐藏原生select元素,需确保Validator不忽略隐藏元素,同时要处理动态新增行的验证绑定。

修复步骤

  1. 改用rules('add')方法遍历元素添加验证规则,替代初始化时的类名配置
  2. 给Select2绑定change事件,选择后触发验证状态更新
  3. 新增行后,立即为新元素绑定验证规则

修改后的完整JavaScript代码

function formatRepo (repo) {
  if (repo.loading) {
    return repo.text;
  }

  var $container = $(
    "<div class='select2-result-repository clearfix'>" +
      "<div class='select2-result-repository__meta'>" +
        "<div class='select2-result-repository__title'></div>" +
        "</div>" +
      "</div>" +
    "</div>"
  );

  $container.find(".select2-result-repository__title").text(repo.full_name);
  return $container;
}

function formatRepoSelection (repo) {
  return repo.full_name || repo.text;
}

function attachItems(item_elt){
    item_elt = typeof(item_elt) == 'undefined'?'.view_by_item':item_elt;
    $(document).find(item_elt).select2({
        ajax: {
            url: "https://api.github.com/search/repositories",
            dataType: 'json',
            delay: 250,
            data: function (params) {
              return {
                q: params.term,
                page: params.page
              };
            },
            processResults: function (data, params) {
              params.page = params.page || 1;

              return {
                results: data.items,
                pagination: {
                  more: (params.page * 30) < data.total_count
                }
              };
            },
            cache: true
          },
          placeholder: 'Search for a repository',
          minimumInputLength: 3,
          templateResult: formatRepo,
          templateSelection: formatRepoSelection
    }).on('change', function() {
        // Select2选择变化时触发验证
        $(this).valid();
    });
}

// 为元素添加验证规则
function addValidationRules() {
    // 商品选择框必填规则
    $('.view_by_item').each(function() {
        $(this).rules('add', {
            required: true,
            messages: {
                required: '请选择商品'
            }
        });
    });
    // 数量输入框必填规则
    $('.qty').each(function() {
        $(this).rules('add', {
            required: true,
            messages: {
                required: '请输入数量'
            }
        });
    });
}

var rowCount = 2;
$(document).on('click', '.plusbutton',function(e){
    e.preventDefault();
    rowCount++;
    
    var newRow = '<tr>';
    newRow += '<td class="tleft"><select name="view_by_item[]"  data-id="'+rowCount+'"  id="view_by_item'+rowCount+'" class="form-control view_by_item"  style="width: 100%"></select></td>';
    newRow += '<td class="tcenter"><input  type="number" name="qty[]" id="qty'+rowCount+'" class="qty form-control"  style="text-align:right" /></td>'; 
    newRow += '<td class="tcenter"><input type="text" name="ponum[]" class="ponum form-control"  placeholder="Optional"/></td>';    
   
    $("#myTable tbody").append(newRow);
    // 初始化新的Select2
    attachItems('#view_by_item'+rowCount);
    // 为新元素绑定验证规则
    addValidationRules();
});

// 初始化表单验证
$('#CartForm').validate({
    ignore: [], // 不忽略隐藏元素,适配Select2
    submitHandler: function(form) {
        alert('验证通过,可提交表单');
        // 此处可添加实际提交逻辑,如form.submit();
        return false;
    }   
});

// 初始化Select2和验证规则
attachItems();
addValidationRules();

关键修改说明

  • 验证规则绑定:用rules('add')替代初始化时的类名配置,解决Validator无法识别类名规则的问题
  • Select2联动验证:通过change事件触发valid(),确保选择操作能同步验证状态
  • 动态行处理:新增行后立即调用addValidationRules(),保证新元素也能被纳入验证范围

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:58:13