I have a multi step form and I am trying to validate each step of the form (all input fields should be required)
After searching and finding a working solution for validating several inputs of an array:
$("[name^=serialNbs]").each(function() {
$(this).rules("add", {
required: true,
messages: {
required: "Il faut remplir le numéro de série"
}
});
});
I am still having a problem related to the message.
My personalised message only shows on the first input (3rd step)
Here is the snippet just select the radio options by default (Computer & Sonceboz) on the first step, give a quantity between 1 and 10 on the second step and try to go to the third step without filling the inputs
$(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>
Are you dynamically generating these additional fields? It does not work like you expect because these additional fields do not yet exist when you call the .each()
that contains the .rules()
method. You must call .rules()
on these new fields just after you create them.
The reason that they still show as required
is because you also have the required
attribute in the HTML element, which is redundant. If you are properly assigning the required
rule using a jQuery Validate method, then you do not need the inline required
attribute.
It also seems like you can pull some redundant lines out of your if/else statement, but that's up to you.
Something like:
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
Alternately, if you create all additional fields at once, then you can simply move your original .each()
loop to a point right after you create all of these additional fields.
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"
}
});
});