Skip to content

Instantly share code, notes, and snippets.

@tomsihap
Last active February 5, 2018 14:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomsihap/58763d54259cc888b4df377c1ba2cd69 to your computer and use it in GitHub Desktop.
Save tomsihap/58763d54259cc888b4df377c1ba2cd69 to your computer and use it in GitHub Desktop.
Step by step form with jQuery & Bootstrap -- v0.1
<script src="steps.js"></script>
<link href="steps.css" rel="stylesheet">
<div class="container container-flex">
<ul id="steps" class="list-inline">
<li class="list-inline-item">
<label data-role='change' data-step="1" data-complete="1" data-currentstep="1" class="btn btn-sm">1</label>
</li>
<li class="list-inline-item">
<label data-role='change' data-step="2" data-complete="0" data-currentstep="0" class="btn btn-sm">2</label>
</li>
<li class="list-inline-item">
<label data-role='change' data-step="3" data-complete="0" data-currentstep="0" class="btn btn-sm">3</label>
</li>
<li class="list-inline-item">
<label data-role='change' data-step="4" data-complete="0" data-currentstep="0" class="btn btn-sm">4</label>
</li>
<li class="list-inline-item">
<label data-role='change' data-step="5" data-complete="0" data-currentstep="0" class="btn btn-sm">5</label>
</li>
<li class="list-inline-item">
<label data-role='change' data-step="6" data-complete="0" data-currentstep="0" class="btn btn-sm">Done !</label>
</li>
</ul>
<div id="stepalert" class="alert alert-danger alert-dismissible fade show" role="alert" style="display:none;">
<strong>Oups !</strong> An alert when you click on a step before completing the previous ones.
<button id="closealert" type="button" class="close" aria-label="Close"> <span aria-hidden="true">&times;</span> </button>
</div>
<div id="form-steps">
<form id="form">
<!-- STEP 1-->
<div data-step="1" class="card step" style="display:none;">
<div class="card-body">
<h5 class="card-title">First step!</h5>
<p class="card-text">Nice text to introduce your form.</p>
</div>
<div class="card-footer">
<a data-step="1" data-role="next" href="#" class="btn btn-primary pull-right">Call to action! <i class="fa fa-arrow-right" aria-hidden="true"></i></a>
</div>
</div>
<!-- STEP 2-->
<div data-step="2" class="card step" style="display:none;">
<div class="card-body">
<h5 class="card-title">Nice second step</h5>
<label for="short_description">Name</label>
<input type="text" class="form-control form-control-sm">
<small class="form-text text-muted">Little explanation on why your name is an important one.</small>
<label for="name">Mon nom complet</label>
<input type="text" name="name" id="name" class="form-control form-control-sm">
<label for="birthdate">My birthdate</label>
<input type="date" class="form-control form-control-sm">
</div>
<div class="card-footer">
<a data-step="2" data-role="prev" href="#" class="btn btn-success"><i class="fa fa-arrow-left" aria-hidden="true"></i> Previous page</a>
<a data-step="2" data-role="next" href="#" class="btn btn-success pull-right">Next page <i class="fa fa-arrow-right" aria-hidden="true"></i></a>
</div>
</div>
...
<!-- LAST STEP -->
<div data-step="5" class="card step" style="display:none;">
<div class="card-body">
<h5 class="card-title">Mes documents</h5>
<div class="form-check">
<input class="form-check-input" type="checkbox" required>
<label class="form-check-label" for="">
I've read the terms & conditions, etc.
</label>
</div>
</div>
<div class="card-footer">
<a data-step="5" data-role="prev" href="#" class="btn btn-success"><i class="fa fa-arrow-left" aria-hidden="true"></i> Previous page</a>
<button type="submit" class="btn btn-primary pull-right">Done ! <i class="fa fa-arrow-right" aria-hidden="true"></i></button>
</div>
</div>
</form>
</div>
</div>
@media screen and (min-width: 992px) {
.container-flex {
max-width: 40%;
}
}
label {
margin-top: 8px;
margin-bottom: 0px;
}
$(function () {
// Onclick sur next !
$('a[data-role=\'next\']').each(function () {
$(this).on('click', function () {
nextStepFrom($(this).data('step'));
});
});
// Onclick sur prev !
$('a[data-role=\'prev\']').each(function () {
$(this).on('click', function () {
prevStepFrom($(this).data('step'));
});
});
// Onclick sur label de step ! Uniquement si le data-complete = 1 du currentstep ou si data-current = 1
$('label[data-role=\'change\']').each(function () {
$(this).on('click', function () {
console.log('this data step : ' + $(this).data('step'));
// Si data-complete = 1 OU data-current = 1, sinon trigger Error
if ($('label[data-step=' + $(this).data('step') + ']').data('complete') == 1 || $('label[data-step=' + (parseInt($(this).data('step') - 1)) + ']').data('complete') == 1) {
prevStep($(this).data('step'));
}
else { alertIncomplete(); }
});
});
// Onclick sur nextstepfrom (ou prevstep afin de prévenir une modif après un retour sur un ancien form), on vérifie que tous les autres forms sont complete
var checkCompleteBeforeNext = function (requestedStep) {
let completes = [];
// On teste les labels
$('label[data-complete]').each(function () {
// On teste uniquement les labels précédents à celui qu'on requête
if ($(this).data('step') < requestedStep) {
if ($(this).data('complete') == 1) { completes.push(true); }
else { completes.push(false); }
}
});
// S'il y a un false dans l'array c'est qu'un des champ n'est pas complete
if ($.inArray(completes, false) > -1) {
console.log(completes);
alertIncomplete();
return false;
}
else {
return true;
}
}
// click sur suivant
var nextStepFrom = function (currentStep) {
let current = currentStep;
let next = currentStep + 1;
checkAndSetComplete(current);
if (checkCompleteBeforeNext(next)) {
$('label[data-step=' + current + ']').data('currentstep', 0);
$('label[data-step=' + next + ']').data('currentstep', 1);
checkCompletedForm();
}
}
// click sur précédent
var prevStepFrom = function (currentStep) {
let current = currentStep;
let prev = currentStep - 1;
$('label[data-step=' + current + ']').data('currentstep', 0);
$('label[data-step=' + prev + ']').data('currentstep', 1);
checkCompletedForm();
}
// click sur un label de step
var prevStep = function (step) {
if (checkCompleteBeforeNext(step)) {
$('label[data-step]').each(function () {
$(this).data('currentstep', 0);
});
$('label[data-step=' + step + ']').data('currentstep', 1);
checkCompletedForm();
}
}
var setDisabled = function (el) {
el.attr('disabled', true).removeClass('btn-primary').removeClass('btn-success').addClass('btn-disabled');
}
var setCurrent = function (el) {
el.attr('disabled', false).removeClass('btn-success').removeClass('btn-disabled').addClass('btn-primary');
}
var setComplete = function (el) {
el.attr('disabled', false).removeClass('btn-primary').removeClass('btn-disabled').addClass('btn-success');
}
// Affichage du step en cours
var showCurrentForm = function () {
$('div[data-step]').each(function () {
// Si c'est le current-step
if ($('label[data-step=' + $(this).data('step') + ']').data('currentstep') == 1) { $(this).show(); }
else { $(this).hide(); }
})
}
var checkAndSetComplete = function (stepId) {
$('label[data-step=' + stepId + ']').data('complete', 1);
}
// Vérifie l'état des forms pour affichage des labels - appelé onload et onclick sur prev, next, change
var checkCompletedForm = function () {
$('label[data-step]').each(function () {
// Si c'est le current-step
if ($(this).data('currentstep') == 1) { setCurrent($(this)); }
// Sinon il est soit avant soit après
else {
if ($(this).data('complete') == 1) { setComplete($(this)); }
// Sinon il est incomplet c'est une nextstep
else { setDisabled($(this)); }
}
});
// On cache l'alerte si elle s'était trigger
$('#stepalert').hide();
showCurrentForm();
}
// Appelée dans checkCompleteBeforeNext() si suivant erroné, et dans le onclick label change
var alertIncomplete = function () {
$('#stepalert').show();
$('#closealert').on('click', function () {
$('#stepalert').hide();
});
}
// On check une première fois tous les forms
checkCompletedForm();
});
@tomsihap
Copy link
Author

tomsihap commented Feb 5, 2018

2018_02_05_15_55_01

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment