// defines a single step in the wizard
function Step(id, type, template) {
var self = this;
// step id
self.id = id;
// indicates wether this is a common or a specific type
self.templateType = type;
// the template name
self.template = template;
// just a helper to check whether this is a common or not
self.common = (type == 0);
}
// defines the customer properties
function Customer() {
var self = this;
self.CustomerType = ko.observable();
self.Registration = ko.observable();
self.Tax = ko.observable();
self.Name = ko.observable();
self.Contact = ko.observable();
self.Address = ko.observable();
// a simple validation method
self.IsValid = function () {
return !!self.CustomerType();
}
}
// this is our ko view model
var createCustomer = function () {
var self = this;
// create a new customer object
self.dataModel = new Customer();
// define the customer types (ideally get them from the server)
self.customerTypes = ko.observableArray([{
ID: 1,
Type: "Business"
}, {
ID: 2,
Type: "Residential"
}]);
// define the steps
self.stepModels = ko.observableArray([
new Step(1, 0, "step1Tmpl"),
new Step(2, 1, "step2Tmpl"), // should display only if customer type is a business
new Step(3, 1, "step3Tmpl"), // should display only if customer type is a business
new Step(4, 0, "step4Tmpl"),
new Step(5, 0, "step5Tmpl"),
new Step(6, 0, "step6Tmpl"),
new Step(8, 0, "step7Tmpl")]);
// set the current step to the 1st initially
self.currentStep = ko.observable(self.stepModels()[0]);
// get the current step index (0 based)
self.currentIndex = ko.computed(function () {
return self.stepModels.indexOf(self.currentStep());
});
// get current step template
self.getTemplate = function (data) {
return self.currentStep().template;
};
// check whether theres another step we can goto
self.canGoNext = ko.computed(function () {
return self.currentIndex() < self.stepModels().length - 1;
});
// check whether theres another step we can go back to
self.canGoPrevious = ko.computed(function () {
return self.currentIndex() > 0;
});
// go back one step
// here we need to take the customer type into account
self.GoBack = function () {
var d = ko.toJS(self.dataModel); // convenience
// proceed only if we can go back
if (self.canGoPrevious()) {
var prev;
if (d.CustomerType == 2) { // residential
// use underscore.js filter method
prev = _.filter(self.stepModels(), function (m) {
// get the common ones and skip the business ones
return (m.id <= self.currentIndex() + 1) && (m.templateType == 0 || m.common);
});
} else {
prev = _.filter(self.stepModels(), function (m) {
// get the common ones AND business ones.
return (m.id <= self.currentIndex() + 1) && (m.templateType == 1 || m.common);
});
}
// filtering will give us every step we have to take in this
// route upto where we are already
// so the last in the list will be the current step
// so, reverse it, get the 1st one (0th is current)
self.currentStep(prev.reverse()[1]);
}
};
self.GoNext = function () {
// run validations:
if (!self.dataModel.IsValid()) {
alert("Select customer type");
return;
}
// same logic as in GoBack()
// except we check for larger than current ids.
var d = ko.toJS(self.dataModel);
if (self.canGoNext()) {
var nxt;
if (d.CustomerType == 2) {
nxt = _.find(self.stepModels(), function (m) {
return (m.id > self.currentIndex() + 1) && (m.templateType == 0 || m.common);
});
} else {
nxt = _.find(self.stepModels(), function (m) {
return (m.id > self.currentIndex() + 1) && (m.templateType == 1 || m.common);
});
}
self.currentStep(nxt);
}
};
}
var viewModel = new createCustomer();
ko.applyBindings(viewModel, $("#demo")[0]);
<div id="demo">
<div data-bind="with: dataModel">
<div data-bind="template: { name: $parent.getTemplate }"></div>
</div>
<hr/>
<div class="footer" >
<button id="updateContactBtn" class="btn btn-primary" data-bind="click: GoBack, visible: currentIndex() > 0">Back</button>
<button id="updateContactBtn" class="btn btn-primary" data-bind="click: GoNext">Next</button>
</div>
</div>
<script type="text/html" id="step1Tmpl">
<div class="form-group ">
<label class="col-md-4 control-label" for="CustomerType">Customer Type
</label>
<div class="col-md-8">
<select id="CustomerType" name="CustomerType" class="col-md-12 form-control" data-bind="value: CustomerType, options: $parent.customerTypes, optionsText: 'Type', optionsValue: 'ID', optionsCaption: 'Please Select...'"></select>
</div>
</div>
</script>
<script type="text/html" id="step2Tmpl">
<p>Business Type - Step</p>
<div class="form-group ">
<label class="col-md-4 control-label">Registration #:
</label>
<div class="col-md-8">
<input type='text' class='form-control' data-bind="value: Registration" />
</div>
</div>
</script>
<script type="text/html" id="step3Tmpl">
<p>Business Type - Step</p>
<div class="form-group ">
<label class="col-md-4 control-label">Tax #:
</label>
<div class="col-md-8">
<input type='text' class='form-control' data-bind="value: Tax" />
</div>
</div>
</script>
<script type="text/html" id="step4Tmpl">
<p>Common Step</p>
<div class="form-group ">
<label class="col-md-4 control-label">Name:
</label>
<div class="col-md-8">
<input type='text' class='form-control' data-bind="value: Name" />
</div>
</div>
</script>
<script type="text/html" id="step5Tmpl">
<p>Common Step</p>
<div class="form-group ">
<label class="col-md-4 control-label">Contact No:
</label>
<div class="col-md-8">
<input type='text' class='form-control' data-bind="value: Contact"/>
</div>
</div>
</script>
<script type="text/html" id="step6Tmpl">
<p>Common Step</p>
<div class="form-group ">
<label class="col-md-4 control-label">Address:
</label>
<div class="col-md-8">
<input type='text' class='form-control' data-bind="value: Address"/>
</div>
</div>
</script>
<script type="text/html" id="step7Tmpl">
<p>Final Step - Thank Yo!</p>
</script>
.footer {
text-align:right
}
External resources loaded into this fiddle: