首页 > 解决方案 > jQuery Validate 插件自定义消息仅显示在输入数组的第一个输入上

问题描述

语境

我有一个多步骤表单,我正在尝试验证表单的每个步骤(所有输入字段都应该是必需的)

在搜索并找到用于验证数组的多个输入的有效解决方案后:

$("[name^=serialNbs]").each(function() {
  $(this).rules("add", {
    required: true,
    messages: {
     required: "Il faut remplir le numéro de série"
    }
  });
});

我仍然遇到与消息相关的问题。

问题

我的个性化消息仅在第一次输入时显示(第三步)

验证步骤 3

片段

这是在第一步默认选择单选选项 ( Computer & Sonceboz )的片段,在第二步中给出 1 到 10 之间的数量,然后尝试在不填写输入的情况下进入第三

$(document).ready(function() {
  var id, current_div;
  var valid = $("#add_to_stock").validate({
    rules: {
      pc_quantity: {
        required: true,
        range: [1, 10],
        digits: true
      },
      /*pc_model:{
          required: true
      },
      hard_type:{
          required: true
      },
      hard_model:{
          required: true
      },*/
      hard_quantity: {
        required: true,
        range: [1, 10],
        digits: true
      }
    },
    messages: {
      pc_quantity: "La quantité doit être entre 1 et 10",
      pc_model: "Il faut choisir un modèle",
      hard_type: "Il faut choisir un type",
      hard_model: "Il faut choisir un modèle",
      hard_quantity: "La quantité doit être entre 1 et 10"

    },
    highlight: function(element) {
      $(element).closest('.form-group').addClass('has-error');
    },
    unhighlight: function(element) {
      $(element).closest('.form-group').removeClass('has-error');
    },
    errorElement: 'span',
    errorClass: 'help-block',
    errorPlacement: function(error, element) {
      if (element.hasClass('select2')) {
        error.insertAfter(element.next('span'));
      } else {
        error.insertAfter(element);
      }
    }
  });


  $("[name^=serialNbs]").each(function() {
    $(this).rules("add", {
      required: true,
      messages: {
        required: "Il faut remplir le numéro de série"
      }
    });
  });




  $.fn.select2.defaults.set("theme", "bootstrap");
  $(".select2").select2({
    selectOnClose: true
  });

  $('.select2').on('change', function() {
    $(this).valid();
  });

  //empeche l'envoi du formulaire on tappant la touche enter
  $(document).on("keypress", "form", function(event) {
    return event.keyCode != 13;
  });

  //évenements click des buttons "suivant"
  $(".go_to_step_2").click(function() {
    var option_val = $('input[name=mat_type]:checked').val();
    //console.log(option_val);

    switch (option_val) {
      case 'computer':
        $('#step1').hide();
        $('#step2a').show();
        break;
      case 'hardware':
        $('#step1').hide();
        $('#step2b').show();
        break;
      case 'contract':
        $('#step1').hide();
        $('#step2c').show();
        break;
      default:
    }
  });

  $.ajax('./sources/computer_models.txt', {
    dataType: 'text',
    success: function(text) {

      var data = text.split("\n").map(function(item) {
        var typeIdName = item.split(':');
        return {
          'id': typeIdName[0],
          'text': typeIdName[1]
        };
      });
      //console.log(data);
      $('#pc_model').select2({
        'data': data,
        placeholder: "Selectionnez un modèle",
        allowClear: true
      });
    }
  });

  $.ajax('./sources/hardware_types.txt', {
    dataType: 'text',
    success: function(text) {

      var data = text.split("\n").map(function(item) {
        var typeIdName = item.split(':');
        return {
          'id': typeIdName[0],
          'text': typeIdName[1]
        };
      });
      //console.log(data);
      $('#hard_type').select2({
        'data': data,
        placeholder: "Selectionnez un type",
        allowClear: true
      });
    }
  });

  $("#hard_type").on("change", function() {
    var selectedType = $("#hard_type").val();
    //console.log(selectedType);
    $('#hard_model').html('').select2({
      data: [{
        id: '',
        text: ''
      }]
    });
    $.ajax('./sources/hardware_models_' + selectedType + '.txt', {
      dataType: 'text',
      success: function(text) {

        var data = text.split("\n").map(function(item) {
          var typeIdName = item.split(':');
          return {
            'id': typeIdName[0],
            'text': typeIdName[1]
          };
        });
        //console.log(data);
        $('#hard_model').select2({
          'data': data,
          placeholder: "Selectionnez un modèle",
          allowClear: true
        });
      }
    });
  });

  $(".go_to_step_3").click(function() {
    if ($('div').css('display') == 'block' && $('div').hasClass('add_mat')) {
      id = $(".add_mat:visible").attr('id');
    }
    //console.log(id);
    current_div = "#" + id;
    //console.log(current_div);
    if (valid.form()) {
      $(current_div).hide();
      $("#step3").show();
    }

    var option_val = $('input[name=mat_type]:checked').val();
    var quantity;
    switch (option_val) {
      case 'computer':
        quantity = $('input[name=pc_quantity]').val();
        //console.log(quantity);
        break;
      case 'hardware':
        quantity = $('input[name=hard_quantity]').val();
        //console.log(quantity);
        break;
      case 'contract':
        quantity = $('input[name=contr_quantity]').val();
        //console.log(quantity);
        break;
      default:
    }

    //console.log(quantity);
    var wrapper = $('.SN_wrapper');
    var labelField = '';
    var inputField = '';
    var initialInputID = $("input[name*='serialNbs']").attr('id');
    var x = parseInt(initialInputID.split("_")[1]);
    var y = x + 1;

    if (quantity != 1) {
      for (i = 0; i < quantity - 1; i++) {
        if ($("#serialNb_" + y).length == 0) {
          console.log("1: i:" + i + " ; q:" + quantity + " ; y:" + y + " ; x:" + x);
          labelField = '<label for="serialNb_' + y + ' " class="col-sm-2 control-label padding-right">' + 'Numéro de série ' + y + ' :</label>';
          inputField = '<div class="col-sm-10"><input id="serialNb_' + y + '" name="serialNbs[' + y + ']" class="form-control " type="text" value="" required/></div>';
          y++;
          $(wrapper).append(labelField, inputField);
        } else {

          y++;
          $(wrapper).append(labelField, inputField);
        }
      }
    }

  });

  $(".go_to_step_4").click(function() {
    if (valid.form()) {
      $("#step3").hide();
      $("#step4").show();
    }


    var option_val = $('input[name=mat_type]:checked').val();
    var quantity;
    var opt_site = $('input[name=stock_site]:checked').val();
    var site;
    var model;
    var type;
    var serialNbs = $("input[name*='serialNbs']");
    switch (option_val) {
      case 'computer':
        $("#type_h4").hide();
        if ($("#site").text().length == 0) {
          site = opt_site;
          $("#site").append(site);
        } else {
          if (site != opt_site) {
            $("#site").text('');
            site = opt_site;
            $("#site").append(site);
          } else {
            $("#site").append(site);
          }
        }

        if ($("#model").text().length == 0) {
          model = $('#pc_model option:selected').text();
          $("#model").append(model);
        } else {
          if (model != $('#pc_model option:selected').text()) {
            $("#model").text('');
            model = $('#pc_model option:selected').text();
            $("#model").append(model);
          } else {
            $("#model").append(model);
          }
        }

        if ($("#quant").text().length == 0) {
          quantity = $('input[name=pc_quantity]').val();
          $("#quant").append(quantity);
        } else {
          if (quantity != $('input[name=pc_quantity]').val()) {
            $("#quant").text('');
            quantity = $('input[name=pc_quantity]').val();
            $("#quant").append(quantity);
          } else {
            $("#quant").append(quantity);
          }
        }

        serialNbs.each(function() {
          var eachVal = $(this).val();
          var exists = $('#list_SN li:contains(' + eachVal + ')').length;

          if (!exists) {
            $("#list_SN").append("<li>" + eachVal + "</li>");
          }
        });
        //console.log(model + ";" + quantity);                
        break;
      case 'hardware':

        if ($("#type").text().length == 0) {
          type = $('#hard_type option:selected').text();
          $("#type").append(type);
        } else {
          if (type != $('#hard_type option:selected').text()) {
            $("#type").text('');
            type = $('#hard_type option:selected').text();
            $("#type").append(type);
          } else {
            $("#type").append(type);
          }
        }

        if ($("#model").text().length == 0) {
          model = $('#hard_model option:selected').text();
          $("#model").append(model);
        } else {
          if (model != $('#hard_model option:selected').text()) {
            $("#model").text('');
            model = $('#hard_model option:selected').text();
            $("#model").append(model);
          } else {
            $("#model").append(model);
          }
        }

        if ($("#quant").text().length == 0) {
          quantity = $('input[name=hard_quantity]').val();
          $("#quant").append(quantity);
        } else {
          if (quantity != $('input[name=hard_quantity]').val()) {
            $("#quant").text('');
            quantity = $('input[name=hard_quantity]').val();
            $("#quant").append(quantity);
          } else {
            $("#quant").append(quantity);
          }
        }

        serialNbs.each(function() {
          var eachVal = $(this).val();
          var exists = $('#list_SN li:contains(' + eachVal + ')').length;

          if (!exists) {
            $("#list_SN").append("<li>" + eachVal + "</li>");
          }
        });
        //console.log(type + ";" + model + ";" + quantity);
        break;
      case 'contract':
        quantity = $('input[name=contr_quantity]').val();
        //console.log(quantity);
        break;
      default:
    }
    //console.log(type + ";" + model + ";" + quantity);
  });

  //évenements click des buttons "précédent"

  $(".back_to_step_1").click(function() {
    if ($('div').css('display') == 'block' && $('div').hasClass('add_mat')) {
      id = $(".add_mat:visible").attr('id');
    }

    //console.log(id);
    current_div = "#" + id;
    //console.log(current_div);

    $(current_div).hide();
    $("#step1").show();
  });

  $(".back_to_step_2").click(function() {
    var option_val = $('input[name=mat_type]:checked').val();
    //console.log(option_val);
    var wrapper = $('.SN_wrapper');
    var labelField = '';
    var inputField = '';

    switch (option_val) {
      case 'computer':
        $('#step3').hide();
        $('#step2a').show();
        wrapper.text('');
        labelField = '<label for="serialNb_1 " class="col-sm-2 control-label padding-right">' + 'Numéro de série 1 :</label>';
        inputField = '<div class="col-sm-10"><input id="serialNb_1" name="serialNbs[]" class="form-control" type="text" value="" /></div>';
        $(wrapper).append(labelField, inputField);
        break;
      case 'hardware':
        $('#step3').hide();
        $('#step2b').show();
        wrapper.text('');
        labelField = '<label for="serialNb_1 " class="col-sm-2 control-label padding-right">' + 'Numéro de série 1 :</label>';
        inputField = '<div class="col-sm-10"><input id="serialNb_1" name="serialNbs[]" class="form-control" type="text" value="" /></div>';
        $(wrapper).append(labelField, inputField);
        break;
      case 'contract':
        $('#step3').hide();
        $('#step2c').show();
        wrapper.text('');
        labelField = '<label for="serialNb_1 " class="col-sm-2 control-label padding-right">' + 'Numéro de série 1 :</label>';
        inputField = '<div class="col-sm-10"><input id="serialNb_1" name="serialNbs[]" class="form-control" type="text" value="" /></div>';
        $(wrapper).append(labelField, inputField);
        break;
      default:
    }
  });

  $(".back_to_step_3").click(function() {
    $("#step4").hide();
    $("#step3").show();



  });
});
#add_to_stock fieldset:not(:first-of-type) {
  display: none;
}

.add_mat {
  position: relative;
  min-height: 200px;
}

.container-decisions {
  position: relative;
}

.container-decisions #step1,
#step2,
#step2a,
#step2b,
#step2c,
#step3,
#step4 {
  display: none;
}

.container-decisions #step1 {
  display: block;
}

.no_margin {
  margin: 0;
  padding: 0;
}

.btn {
  min-width: 120px;
}

.label-info {
  font-size: 90%;
}

.has-error input[type="text"],
.has-error input[type="number"],
.has-error select {
  border: 1px solid #a94442;
}

.has-error .select2-selection {
  border-color: rgb(185, 74, 72) !important;
}
<!DOCTYPE html>

<html>

<head>
  <meta charset="UTF-8">
  <title>Gestion du stock</title>
  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <!-- jQuery library -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <!-- Latest compiled JavaScript -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  <!-- Select2 plugin-->
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.css" rel="stylesheet" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.js"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2-bootstrap-theme/0.1.0-beta.10/select2-bootstrap.min.css" rel="stylesheet" />

  <!--JQuery Validator-->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script>

  <!-- js et css perso-->
  <script type="text/javascript" src="js/stock.js"></script>
  <link rel="stylesheet" type="text/css" href="css/stock.css">

</head>

<body>
  <div class="container">
    <div class="panel-group">
      <div class="panel panel-default">
        <div class="panel-heading">
          <h3>Ajout de nouveau matériel</h3>
        </div>
        <div class="panel-body">
          <div class="container-decisions">
            <form id="add_to_stock" class="form-horizontal" name="add_to_stock" method="post" action="./result.php">

              <div id="step1" class="add_mat">

                <legend>Step 1 of 4</legend>
                <div class="form-group col-sm-12">
                  <label class="control-label">Type de Matériel</label>
                  <div class="radio">
                    <label><input type="radio" name="mat_type" value="computer" checked>Ordinateur</label>
                  </div>
                  <div class="radio">
                    <label><input type="radio" name="mat_type" value="hardware">Hardware</label>
                  </div>
                  <div class="radio disabled">
                    <label><input type="radio" name="mat_type" value="contract" disabled>Contrat</label>
                  </div>
                  <div class="form-group col-sm-12">
                    <label class="control-label">Site du Stock</label>
                    <div class="radio">
                      <label><input type="radio" name="stock_site" value="Sonceboz" checked>Sonceboz</label>
                    </div>
                    <div class="radio">
                      <label><input type="radio" name="stock_site" value="Boncourt">Boncourt</label>
                    </div>
                  </div>
                  <div class="form-group col-sm-12">
                    <div class="col-sm-5 pull-right">
                      <button class="btn btn-success pull-right go_to_step_2" type="button">
                                                    Suivant <span class="glyphicon glyphicon-chevron-right"></span>
                                                </button>
                    </div>
                  </div>
                </div>
              </div>


              <div id="step2a" class="add_mat">
                <legend>Step 2 of 4</legend>
                <div class="form-group col-sm-12 ">
                  <h4 class="text-muted text-uppercase "><strong>Ajouter un ordinateur</strong></h4>

                  <div class="alert alert-warning"><span class="glyphicon glyphicon-warning-sign"></span><strong> Attention :</strong> Il faut remplir tous les champs ! La quantité doit être entre 1 et 10.</div>

                  <div class="form-group">
                    <label class="col-sm-2 control-label" for="pc_model">Modèle :</label>
                    <div class="col-sm-10">
                      <select id="pc_model" name="pc_model" class="select2 form-control" style="width: 100%">
                        <option></option>
                      </select>
                    </div>
                  </div>

                  <div class="form-group no_margin">
                    <div class="col-sm-10">
                      <input id="pc_deploymentState" name="pc_deploymentState" class="form-control" type="hidden" value="Stock new">
                    </div>
                  </div>

                  <div class="form-group no_margin">
                    <div class="col-sm-10">
                      <input id="pc_incidentState" name="pc_incidentState" class="form-control" type="hidden" value="Operational">
                    </div>
                  </div>

                  <div class="form-group cont-quant">
                    <label class="col-sm-2 control-label" for="pc_quantity">Quantité :</label>
                    <div class="col-sm-10">
                      <input id="pc_quantity" name="pc_quantity" class="form-control quantity" type="number" min="1" max="10" value="" required>
                    </div>
                  </div>

                  <div class="form-group col-sm-12">
                    <div class="col-sm-1"></div>
                    <div class="col-sm-5">
                      <button class="btn btn-warning pull-left back_to_step_1" type="button">
                                                    <span class="glyphicon glyphicon-chevron-left"></span> Précédent 
                                                </button>
                    </div>
                    <div class="col-sm-6">
                      <button class="btn btn-success pull-right go_to_step_3" type="button">
                                                    Suivant <span class="glyphicon glyphicon-chevron-right"></span>
                                                </button>
                    </div>
                  </div>
                </div>
              </div>
              <div id="step2b" class="add_mat">

                <legend>Step 2 of 4</legend>
                <div class="form-group col-sm-12">
                  <label class="control-label">Ajouter du hardware</label>

                  <div class="form-group">
                    <label class="col-sm-2 control-label" for="hard_type">Type :</label>
                    <div class="col-sm-10">
                      <select id="hard_type" name="hard_type" class="select2 form-control" style="width: 100%" required>
                        <option></option>
                      </select>
                    </div>
                  </div>

                  <div class="form-group">
                    <label class="col-sm-2 control-label" for="hard_model">Model :</label>

                    <div class="col-sm-10">
                      <select id="hard_model" name="hard_model" class="select2 form-control" style="width: 100%" required>
                        <option></option>
                      </select>
                    </div>
                  </div>

                  <div class="form-group no_margin">
                    <div class="col-sm-10">
                      <input id="hard_deploymentState" name="hard_deploymentState" class="form-control" type="hidden" value="Stock new">
                    </div>
                  </div>

                  <div class="form-group no_margin">
                    <div class="col-sm-10">
                      <input id="hard_incidentState" name="hard_incidentState" class="form-control" type="hidden" value="Operational">
                    </div>
                  </div>

                  <div class="form-group cont-quant">
                    <label class="col-sm-2 control-label" for="hard_quantity">Quantité :</label>
                    <div class="col-sm-10">
                      <input id="hard_quantity" name="hard_quantity" class="form-control quantity" type="number" min="1" max="10" value="" required>
                    </div>
                  </div>

                  <div class="form-group col-sm-12">
                    <div class="col-sm-1"></div>
                    <div class="col-sm-5">
                      <button class="btn btn-warning pull-left back_to_step_1" type="button">
                                                    <span class="glyphicon glyphicon-chevron-left"></span> Précédent 
                                                </button>
                    </div>
                    <div class="col-sm-6">
                      <button class="btn btn-success pull-right go_to_step_3" type="button">
                                                    Suivant <span class="glyphicon glyphicon-chevron-right"></span>
                                                </button>
                    </div>
                  </div>
                </div>

              </div>
              <div id="step2c" class="add_mat">
                <legend>Step 2 of 4</legend>
                <div class="form-group col-sm-12">
                  <label class="control-label">Contract</label>

                  <div class="form-group col-sm-12">
                    <div class="col-sm-1"></div>
                    <div class="col-sm-5">
                      <button class="btn btn-warning pull-left back_to_step_1" type="button">
                                                    <span class="glyphicon glyphicon-chevron-left"></span> Précédent 
                                                </button>
                    </div>
                    <div class="col-sm-6">
                      <button class="btn btn-success pull-right go_to_step_3" type="button">
                                                    Suivant <span class="glyphicon glyphicon-chevron-right"></span>
                                                </button>
                    </div>
                  </div>
                </div>
              </div>

              <div id="step3" class="add_mat">

                <legend>Step 3 of 4</legend>
                <div class="form-group col-sm-12">
                  <label class="control-label">Ajout des numéros de série</label>

                  <div class="SN_wrapper form-group">
                    <label class="col-sm-2 control-label padding-right" for="serialNb_1">Numéro de série 1 :</label>
                    <div class="col-sm-10">
                      <input id="serialNb_1" name="serialNbs[1]" class="form-control" type="text" value="" required>
                    </div>
                  </div>

                  <div class="form-group col-sm-12">
                    <div class="col-sm-1"></div>
                    <div class="col-sm-5">
                      <button class="btn btn-warning pull-left back_to_step_2" type="button">
                                                        <span class="glyphicon glyphicon-chevron-left"></span> Précédent 
                                                    </button>
                    </div>
                    <div class="col-sm-6">
                      <button class="btn btn-success pull-right go_to_step_4" type="button">
                                                        Suivant <span class="glyphicon glyphicon-chevron-right"></span>
                                                    </button>
                    </div>
                  </div>
                </div>
              </div>
              <div id="step4" class="add_mat">


                <legend>Step 4 of 4</legend>
                <div id="recap" class="container">
                  <h3>Récapitulation</h3>
                  <h4 id="site_h4"><span class="label label-info">Site :</span> <span id="site"></span></h4>
                  <h4 id="type_h4"><span class="label label-info">Type :</span> <span id="type"></span></h4>
                  <h4 id="model_h4"><span class="label label-info">Modèle :</span> <span id="model"></span></h4>
                  <h4 id="quant_h4"><span class="label label-info">Quantité :</span> <span id="quant"></span></h4>
                  <div class="">
                    <h4><span class="label label-info">Numéros de série : </span></h4>
                    <ol id="list_SN">

                    </ol>
                  </div>
                </div>
                <div class="form-group col-sm-12">
                  <div class="form-group col-sm-12">
                    <div class="col-sm-1"></div>
                    <div class="col-lg-5">
                      <button class="btn btn-warning pull-left back_to_step_3" type="button">
                                                    <span class="glyphicon glyphicon-chevron-left"></span> Précédent 
                                                </button>
                    </div>
                    <div class="col-lg-6">
                      <button id="add_new_mat" class="btn btn-primary pull-right" type="submit">
                                                    Ajouter
                                                </button>
                    </div>
                  </div>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

</html>

标签: jqueryarraysinputjquery-validate

解决方案


您是否动态生成这些附加字段?它不像您期望的那样工作,因为当您调用.each()包含该.rules()方法的 时,这些附加字段还不存在。您必须.rules()在创建这些新字段立即调用它们。

它们仍然显示的原因required是因为您required在 HTML 元素中也有该属性,这是多余的。如果您required使用 jQuery Validate 方法正确分配规则,则不需要 inlinerequired属性。

您似乎也可以从 if/else 语句中提取一些多余的行,但这取决于您。

就像是:

if (quantity != 1) {

  for (i = 0; i < quantity - 1; i++) {

    if ($("#serialNb_" + y).length == 0) {
      console.log("1: i:" + i + " ; q:" + quantity + " ; y:" + y + " ; x:" + x);
      labelField = '<label for="serialNb_' + y + ' " class="col-sm-2 control-label padding-right">' + 'Numéro de série ' + y + ' :</label>';
      inputField = '<div class="col-sm-10"><input id="serialNb_' + y + '" name="serialNbs[' + y + ']" class="form-control " type="text" value="" /></div>'; 
    }

    // redundant lines on both sides of if/else??
    y++;
    $(wrapper).append(labelField, inputField);

    // assign the rules/messages right here, just after a new field is inserted
    $('#serialNb_' + y).rules("add", {
        required: true,
        messages: {
            required: "Il faut remplir le numéro de série"
        }
    });

  }  // end for loop

}  // end if

或者,如果您一次创建所有附加字段,那么您可以.each()在创建所有这些附加字段后立即将原始循环移动到某个点。

if (quantity != 1) {
    // create all fields
    ....
}

// all additional fields exist now
$("[name^=serialNbs]").each(function() {
    $(this).rules("add", {
        required: true,
        messages: {
            required: "Il faut remplir le numéro de série"
        }
    });
});

推荐阅读