Logic For The Next Button For The Questionnaire?
Solution 1:
You could create a multi-step form (also known as Wizard). For this purpose why not using Angular ui-router as suggested in this post:
https://scotch.io/tutorials/angularjs-multi-step-form-using-ui-router
which is a tutorial guiding to create a Wizard and has a working example (a Plunker).
There are also other Angular modules which aim to do the same:
- https://github.com/troch/angular-multi-step-form (demos and docs here)
- https://github.com/mgonto/angular-wizard (demo here)
And in conclusion another tutorial with working demo:
But if you "google" for "multi-step form angular" you can find some more examples.
Also on StackOverflow you can find suggestions on how to create a multi-step form (for example see AngularJS multi-step form validation).
Solution 2:
You could save your showDiv booleans in an array, and keep the corresponding index in memory. So something like this:
$scope.currentState = 0;
//ordered representation of possible states
$scope.stateArray = [true, false, false, false, false];
$scope.next = function(){
//on to the next showDiv
currentState++;
stateArray.forEach(function(index, state){
//hide everything else.
if(index != currentState){
state = false;
}
else{
state = true;
}
}
}
Then, in your html, do ng-show="stateArray[currentState]"
You'll inadvertently gain a "previous" function from this if you choose by decrementing the currentState instead.
Solution 3:
I would create three custom directives that can be used to build a multi-part form:
myMultiPartForm
directive would wrap the form and keep track of which part is visiblemyFormPart
directive would be used multiple times as a wrapper for each form sectionmyFormPartSubmit
would be used on the submit button in each form part, to advance to the next part
Here is a working example: JSFiddle
Example
index.html
In this file, I am using MyViewController
as the view, which will expose a part
variable for keeping track of which form part is currently being displayed, as well as a save
method that each form part can call when it is submitted.
<div ng-app="myApp" ng-controller="MyViewController as view">
<my-multi-part-form part="{{view.part}}">
<my-form-part on-submit="view.save(data)">
<label>
Name:
<input type="text" ng-model="formPart.data.name">
</label>
<button my-form-part-submit>
Next
</button>
</my-form-part>
<my-form-part on-submit="view.save(data)">
<label>
Age:
<input type="number" ng-model="formPart.data.age">
</label>
<button my-form-part-submit>
Next
</button>
</my-form-part>
<my-form-part on-submit="view.save(data)">
<label>
Gender:
<select ng-model="formPart.data.gender">
<option value="male">Male</option>
<option value="female">Female</option>
</select>
</label>
<button my-form-part-submit>
Done
</button>
</my-form-part>
</my-multi-part-form>
<div ng-if="view.part > 2">
Complete!
</div>
</div>
view.controller.js
The view controller initializes the part
variable at zero, which is the index of the first form part (form parts are stored in an array, in MultiPartFormController
).
angular.module('myApp')
.controller('MyViewController', MyViewController)
;
function MyViewController($http) {
var view = this;
view.part = 0;
view.save = function(data) {
$http({
method : 'POST',
url : 'https://example.com',
data : data
}).then(function success(res) {
/** handle success **/
view.part++;
}).catch(function error(err) {
/** handle error **/
});
};
}
multi-part-form.directive.js
Here, I define the myMultiPartForm
directive and observe the part
attribute, which is the interpolated value of view.part
. Whenever that value changes (i.e. on success after view.save
is called), it will hide all form parts except the one that view.part
now references.
angular.module('myApp')
.directive('myMultiPartForm', myMultiPartFormDirective)
.controller('MultiPartFormController', MultiPartFormController)
;
function myMultiPartFormDirective() {
return {
controller : 'MultiPartFormController',
controllerAs: 'multiPartForm',
link : postLink
};
function postLink(scope, iElement, iAttrs, multiPartForm) {
iAttrs.$observe('part', function (newValue) {
angular.forEach(multiPartForm.parts, function (part, index) {
if (index == newValue) part.show();
else part.hide();
});
});
}
}
function MultiPartFormController() {
var multiPartForm = this;
multiPartForm.parts = [];
}
form-part.directive.js
Here's where it gets cool. Each myFormPart
directive adds show
and hide
methods to its controller during the post-link phase, then adds a reference to its controller to the parts
array of the myMultiPartForm
controller. This enables myMultiPartForm
to manipulate the DOM element of each myFormPart
without needing to traverse the DOM tree using jQuery or jqLite.
angular.module('myApp')
.directive('myFormPart', myFormPartDirective)
.controller('FormPartController', FormPartController)
;
function myFormPartDirective() {
return {
bindToController: {
onSubmit: '&'
},
controller : 'FormPartController',
controllerAs : 'formPart',
link : postLink,
require : ['myFormPart', '^myMultiPartForm'],
scope : true,
template : '<ng-transclude></ng-transclude>',
transclude : true
};
function postLink(scope, iElement, iAttrs, controllers) {
var formPart = controllers[0];
var multiPartForm = controllers[1];
formPart.hide = function () {
iElement.css({display: 'none'});
};
formPart.show = function () {
iElement.css({display: 'block'});
};
multiPartForm.parts.push(formPart);
}
}
function FormPartController() {
var formPart = this;
formPart.data = {};
}
form-part-submit.directive.js
Finally, this directive adds a click handler to whatever element it is applied to that will call myFormPart.onSubmit
, which in this example is always the view.save
method (but could be a different function for each form part).
angular.module('myApp')
.directive('myFormPartSubmit', myFormPartSubmitDirective)
;
function myFormPartSubmitDirective() {
return {
link: postLink,
require: '^myFormPart'
};
function postLink(scope, iElement, iAttrs, formPart) {
iElement.on('click', function() {
if (typeof formPart.onSubmit === 'function') {
formPart.onSubmit({data: formPart.data});
}
});
}
}
Order of Operations
To understand how all of this works, you need to understand the order in which things happen. Here is an outline:
- multiPartForm controller instantiated
- formPart A controller instantiated
- formPartSubmit A DOM element linked
- formPart A DOM element linked
- formPart B controller instantiated
- formPartSubmit B DOM element linked
- formPart B DOM element linked
- formPart C controller instantiated
- formPartSubmit C DOM element linked
- formPart C DOM element linked
- multiPartForm DOM element linked
The multiPartForm
controller is instantiated first, but linked last. That means by the time its postLink function is called, its controller has all of the information it needs about each formPart. Then, the part
value gets interpolated and the first $observe callback is fired.
Post a Comment for "Logic For The Next Button For The Questionnaire?"