Skip to content

Commit d225443

Browse files
committed
changed to msf:viewChanged alert, refactor methods, and provided progress bar example
1 parent 8f59137 commit d225443

File tree

3 files changed

+87
-37
lines changed

3 files changed

+87
-37
lines changed

README.md

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Multi-Step-Form-Js
2-
Multi Step Form with jQuery validation
2+
**Multi Step Form with jQuery validation**
3+
4+
* utilizes jquery validation (with or without jquery unobtrusive validation) to validate the form at each step.
5+
* contains customizable header step classes to distinguish between active, complete, and incomplete steps.
6+
* triggers custom change events with relevant step data for custom processing (e.g. updating progress bars)
37

48
## Download
59

@@ -11,7 +15,10 @@ npm install multi-step-form-js
1115

1216
## Demo
1317

14-
View a [jsfiddle here](http://jsfiddle.net/mgildea/ez94n125/17/show/)
18+
The following demo contains examples for listening to the 'msf:viewChanged' event to update a progress bar as well as defined header step classes to distinguish the current and completed steps.<br><br>
19+
View a [jsfiddle here](http://jsfiddle.net/mgildea/ez94n125/25/show/)
20+
21+
1522

1623
## Setup
1724

@@ -23,7 +30,10 @@ and uses optional:<br>
2330
2. an *.msf-header* element with N required *.msf-step* elements<br>
2431
3. an *.msf-navigation* element with *.msf-nav-button* buttons; if buttons are not defined they will be generated <br>
2532

26-
Example Html element with multi-step-from (msf) classes.
33+
34+
35+
Example Html element with multi-step-form (msf) classes. <br>
36+
As progress is made through each step the 'msf-step-active' and 'msf-step-complete' classes will be added to the element of 'msf-step' class.
2737

2838
```html
2939
<head>
@@ -120,7 +130,23 @@ Example Multi-Step-Form-Js initialization using unobtrusive validation
120130
```
121131

122132

133+
134+
Example jquery event listener to update some progress bar with object parameter containing properties: 'currentIndex', 'previousIndex', and 'totalSteps'
135+
136+
137+
```html
138+
<script type="text/javascript">
139+
$(document).on("msf:viewChanged", function(event, data){
140+
var progress = Math.round((data.currentIndex / data.totalSteps)*100);
141+
$(".progress-bar").css("width", progress + "%").attr('aria-valuenow', progress);
142+
});
143+
144+
</script>
145+
```
146+
147+
123148
## Release History
149+
* 0.0.9 trigger 'msf:viewChanged' event when displaying a new view
124150
* 0.0.8 block form submit on enter if nonfinal view
125151
* 0.0.6 documentation updates
126152
* 0.0.4 allow parameters for non unobtrusive validation

example/index.html

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
<div id="wrapper">
2424

2525
<div id="container body-content">
26+
27+
<div class="progress">
28+
<div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
29+
<span class="sr-only">0% Complete</span>
30+
</div>
31+
</div>
2632
<form class="form-horizontal msf">
2733
<div class="msf-header">
2834
<div class="row text-center">
@@ -108,17 +114,20 @@
108114
</div>
109115

110116
<div class="row">
111-
<div class="col-md- col-md-offset-3">
117+
<div class="col-md-6 col-md-offset-3">
112118
<div class="form-group">
113119
<input id="additional" name="additional" type="text" class="form-control" placeholder="Additional Details" data-val="true" data-val-required="name is required">
114120
</div>
115121
</div>
116122
</div>
123+
117124

118125

119126
</div>
120127
</div>
121128

129+
130+
122131
<div class="msf-navigation">
123132
<div class="row">
124133
<div class="col-md-3">
@@ -176,8 +185,17 @@
176185

177186
ko.applyBindings(viewModel);
178187

188+
$(document).on("msf:viewChanged", function(event, data){
189+
190+
var progress = Math.round((data.currentIndex / data.totalSteps)*100);
191+
192+
$(".progress-bar").css("width", progress + "%").attr('aria-valuenow', progress); ;
193+
});
194+
195+
196+
$(".msf:first").multiStepForm();
179197

180-
$(".msf:first").multiStepForm({});
198+
181199

182200
</script>
183201

src/multi-step-form.js

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
factory(jQuery);
1717
}
1818
}(function ($) {
19-
20-
"use strict";
19+
'use strict';
2120

2221
const msfCssClasses = {
2322
header: "msf-header",
@@ -28,15 +27,18 @@
2827
view: "msf-view",
2928
navigation: "msf-navigation",
3029
navButton: "msf-nav-button"
31-
3230
};
3331

3432
const msfNavTypes = {
3533
back: "back",
3634
next: "next",
3735
submit: "submit"
3836

39-
}
37+
};
38+
39+
const msfEventTypes = {
40+
viewChanged : "msf:viewChanged"
41+
};
4042

4143
$.fn.multiStepForm = function (options) {
4244
var form = this;
@@ -48,22 +50,43 @@
4850

4951
var settings = $.extend({}, defaults, options);
5052

53+
//find the msf-content object
5154
form.content = this.find("." + msfCssClasses.content).first();
5255

5356
if (form.content.length === 0) {
5457
throw new Error('Multi-Step Form requires a child element of class \'' + msfCssClasses.content + '\'');
5558
}
5659

60+
//find the msf-views within the content object
5761
form.views = $(this.content).find("." + msfCssClasses.view);
5862

5963
if (form.views.length === 0) {
6064
throw new Error('Multi-Step Form\'s element of class \'' + msfCssClasses.content + '\' requires n elements of class \'' + msfCssClasses.view + '\'');
6165
}
6266

6367
form.header = this.find("." + msfCssClasses.header).first();
68+
form.navigation = this.find("." + msfCssClasses.navigation).first();
6469
form.steps = [];
6570

66-
form.navigation = this.find("." + msfCssClasses.navigation).first();
71+
form.getActiveView = function() {
72+
return form.views.filter(function () { return this.style && this.style.display !== '' && this.style.display !== 'none' });
73+
};
74+
75+
form.setActiveView = function(index) {
76+
var view = form.getActiveView();
77+
var previousIndex = form.views.index(view);
78+
79+
view = form.views.eq(index);
80+
view.show();
81+
view.find(':input').first().focus();
82+
83+
//trigger the 'view has changed' event
84+
form.trigger(msfEventTypes.viewChanged, {
85+
currentIndex : index,
86+
previousIndex : previousIndex,
87+
totalSteps : form.steps.length
88+
});
89+
}
6790

6891
form.init = function () {
6992

@@ -133,17 +156,14 @@
133156
var view = element,
134157
$view = $(element);
135158

136-
view.init = function () {
137-
if (index === settings.activeIndex) {
138-
$view.show();
139-
}
140-
};
141-
142-
143159
$view.on('show', function (e) {
144160
if (this !== e.target)
145161
return;
146162

163+
//hide whichever view is currently showing
164+
form.getActiveView().hide();
165+
166+
//choose which navigation buttons should be displayed based on index of view
147167
if (index > 0) {
148168
form.backNavButton.show();
149169
}
@@ -156,6 +176,7 @@
156176
form.submitNavButton.hide();
157177
form.nextNavButton.show();
158178

179+
//if this is not the last view do not allow the enter key to submit the form as it is not completed yet
159180
$(this).find(':input').keypress(function (e) {
160181
if (e.which == 13) // Enter key = keycode 13
161182
{
@@ -165,7 +186,7 @@
165186
});
166187
}
167188

168-
189+
//determine if each step is completed or active based in index
169190
$.each(form.steps, function (i, element) {
170191
if (i < index) {
171192
$(element).removeClass(msfCssClasses.stepActive);
@@ -175,8 +196,6 @@
175196
else if (i === index) {
176197
$(element).removeClass(msfCssClasses.stepComplete);
177198
$(element).addClass(msfCssClasses.stepActive);
178-
var currentProgress = Math.round((i / form.steps.length)*100);
179-
$(document).trigger('msf:updateProgress', [currentProgress]); // Trigger an event to notify the progress has changed
180199
}
181200
else {
182201
$(element).removeClass(msfCssClasses.stepComplete);
@@ -189,35 +208,22 @@
189208
if (this !== e.target)
190209
return;
191210

211+
//hide all navigation buttons, display choices will be set on show event
192212
form.backNavButton.hide();
193213
form.nextNavButton.hide();
194214
form.submitNavButton.hide();
195215
});
196-
197-
view.init();
198216
});
199217

218+
form.setActiveView(settings.activeIndex);
200219
};
201220

202221
form.init();
203222

204-
form.getActiveView = function() {
205-
return form.views.filter(function () { return this.style && this.style.display !== '' && this.style.display !== 'none' });
206-
};
207-
208-
form.setActiveView = function(index) {
209-
var view = form.getActiveView();
210-
211-
// var view = (currentView) ? currentView : form.getActiveView();
212-
213-
view.hide();
214-
form.views.eq(index).show();
215-
form.views.eq(index).find(':input').first().focus();
216-
}
217-
218223
form.nextNavButton.click(function () {
219224
var view = form.getActiveView();
220225

226+
//validate the input in the current view
221227
if (form.validate(settings.validate).subset(view)) {
222228
var i = form.views.index(view);
223229

@@ -228,7 +234,7 @@
228234
form.backNavButton.click(function () {
229235
var view = form.getActiveView();
230236
var i = form.views.index(view);
231-
237+
232238
form.setActiveView(i-1);
233239
});
234240

0 commit comments

Comments
 (0)