Knockout Step (Wizard) Navigation

THE PROBLEM: You've got a single page that processes a lot of information and you need to break it into small, digestible steps for users.

Knockout's bindings are pretty easy to understand. One of the best parts about knockout are its computed observables. In this code example I've used ko.computed to enable the navigation buttons depending on the current step.

This example goes a step further in making the function reusable through the APP object literal. With this you can easily define your steps and get on with building awesome stuff.

THE HTML

There isn't anything special about the HTML. I'm using Bootstrap 3 panels and peppering in some knockout data-binding. You will notice an array is used for the visible data-binding on panel one and panel two.

<br/>
<div class="container">

<div class="panel panel-default"> <div class="panel-heading"><span class="h4">Tools</span></div> <div class="panel-body"> <div class="row"> <div class="col-md-9"> </div> <div class="col-md-3"> <button type="button" class="btn btn-primary" data-bind="enable: canGoBack, click: prevStep"><span class="glyphicon glyphicon-chevron-left"></span></button> <button type="button" class="btn btn-primary" data-bind="enable: canGoFwd, click: nextStep"><span class="glyphicon glyphicon-chevron-right"></span> </div> </div> </div> </div>

<div class="panel panel-default" data-bind="visible: steps[0].IsVisible"> <div class="panel-heading"><span class="h4">Panel One</span></div> <div class="panel-body"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet est magni non omnis maiores? Eum quibusdam inventore consequuntur iusto est fugiat nam deleniti totam voluptatum ipsa earum harum odit ut!</p> </div> </div>

<div class="panel panel-default" data-bind="visible: steps[1].IsVisible"> <div class="panel-heading"><span class="h4">Panel Two</span></div> <div class="panel-body"> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eligendi sequi impedit reiciendis tempora saepe deserunt iste molestias quidem illum minus nihil maiores sunt quae enim vitae quia expedita. Minima sit.</p> </div> </div> </div>

See the Pen Knockout Page Navigator by Ken Howard (@kenhowardpdx) on CodePen.

THE JAVASCRIPT

The magic of the approach here is that you can reuse this code anywhere in your app. Place the window.APP in a main javascript file you use everywhere and then instantiate the function when you need it. It takes two parameters: A view model (viewModel) and the number of steps your viewModel requires.

window.APP = {
  setupKnockoutSteps: function(viewModel, numberOfSteps) {
    var self = viewModel;
    self.steps = [];
    self.currentStep = ko.observable(0);

for(var i = 0; i &lt; numberOfSteps; i++) {
  var visible = (self.currentStep() === i) ? true : false
  self.steps[i] = { IsVisible: ko.observable(visible) };
}

self.nextStep = function() {
  self.currentStep(self.currentStep() + 1);
  if (self.currentStep() &lt;= (numberOfSteps - 1 )) {
    self.hideSteps();
    self.steps[self.currentStep()].IsVisible(true);
  } else {
    self.currentStep(numberOfSteps - 1);
  }
}

self.prevStep = function() {
  self.currentStep(self.currentStep() - 1);
  if(self.currentStep() &gt;= 0) {
    self.hideSteps();
    self.steps[self.currentStep()].IsVisible(true);
  } else {
    self.currentStep(0);
  }
}

self.hideSteps = function() {
  for(step in self.steps) {
    self.steps[step].IsVisible(false);
  }
}

self.canGoBack = ko.computed(function() {
  return self.currentStep() &gt; 0;
});

self.canGoFwd = ko.computed(function() {
  return self.currentStep() &lt; (numberOfSteps - 1);
});

} }

function viewModel() { var self = this; }

var viewModel = new viewModel();

APP.setupKnockoutSteps(viewModel, 2);

ko.applyBindings(viewModel);

See the Pen Knockout Page Navigator by Ken Howard (@kenhowardpdx) on CodePen.

THE RESULT

See the Pen Knockout Page Navigator by Ken Howard (@kenhowardpdx) on CodePen.