Wizards – the step by step type, not the spell casting type – they’re not much fun.  Well, at least that’s what I think; to be honest there are few things less interesting to code in the world than another Wizard.

The trouble we have is that it’s a paradigm that’s presented to the end user over and over and as such they are reinforced in the users brain over and over again as the right way to do things.  This epic reinforcement leads us down an inevitable path; the first step of which is us saying, “there’s a much better way of gather this information”, and the final step of which is us wearily saying, “ok, I given, so you want: next, previous and cancel, yes?”.  It’s a losing battle and one I’m sure many of us have fought through before – only to be defeated in the end by the weight of the user’s expectations.

So, what can we do to make this inevitable requirement easier to swallow?  Well, the first port of call is the Force.com Cookbook and it’s recipe for VisualForce wizards.  It’s a good start and shows the basics: use a common controller, return the PageReference of the next or previous page.  I’ve been there a few times over the past couple of years – it’s always a good starting point but I often feel as though it’s lacking something and as such I tend to end up tweaking it.

This continual tweaking got me thinking: surely there has to be another way.  Not necessarily a better way, please note, just a different way.

So what do I want from this different way? In general I don’t want my VisualForce pages to really need to worry about the fact they are in a Wizard. What do I mean by this? Well, I want the controller that stands behind them to provide a standardised way for carrying out certain “default” wizard tasks. As with most of my ideas they’re open to change and development but as I see things at the minute these default features are:

  • Provide the page title
  • Check the user is somewhere they can be
  • Provide Next and Previous actions for navigation

A VisualForce page that uses such a controller may have a skeleton that looks like this.

<apex:page controller="wizardController" title="{!pageTitle}" action="{!checkStep}">
  <apex:commandButton action="{!Previous}" disabled="{!NOT(hasPrevious)}" value="Previous" immediate="true"/>
  <apex:commandButton action="{!Next}" disabled="{!NOT(hasNext)}" value="Next" />
</apex:page>

This is, as you can see, a completely bare bones page. It provides the template for each page in the wizard to be built from.

The best thing about this page in my mind is that all of the navigation is taken away from each individual page and centralised in the controller. We now have only one artifact that is responsible for navigation. This has to be a good thing, no?

What about the controller itself then, how should we implement this? We first need to store the information about each page, I hold this information in a small inner class called NavigationPage.

private class NavigationPage{
  public Integer previous {get; set;}
  public Integer next {get; set;}
  public PageReference thePage {get; set;}
  public String title {get; set;}
}


The controller itself holds a reference to a Map object. This Map contains a list of all of the available pages in the Wizard. The Integers, next and previous, defined in the NavigationPage object refer to the keys in this Map; it is these keys that didtact the flow of the pages. This gives rise to a method to setup the pages in the controller; this method would look something like this:

private void setupSteps(){
  NavigationPage np = new NavigationPage();
  np.thePage = Page.newOpptyStep1;
  np.title = 'New Opportunity - Customer Information';
  np.previous = null;
  np.next = 2;
  steps.put(1, n);

  np = new NavigationPage();
  np.thePage = Page.newOpptyStep2;
  np.title = 'New Opportunity - Opportunity Information';
  np.previous = 1;
  np.next = 3;
  steps.put(2, n);

  np = new NavigationPage();
  np.thePage = Page.newOpptyStep3;
  np.title = 'New Opportunity - Customer Information';
  np.previous = 2;
  np.next = null;
  steps.put(3, n);
}


Given this information inside the controller it’s a fairly trivial task to fill out the other navigation related actions needed to satisfy our earlier VisualForce template. Although we’re still missing one piece of information; the key of the current page, without this we’re doomed. This is a simple a holding an Integer in the controller. For simplicity’s sake we can just default this to the first page in the Wizard or, a better solution would be to have this find the key of the item in the Map that has null as it’s previous step. Either way once we have this we can fill out the remaining actions needed on the controller like so.

public PageReference Next(){
  if(steps.get(curStep).next == null)
    return null;
		
  curstep = steps.get(curStep).next;
  PageReference pr = steps.get(curStep).thePage;
  return pr;
}

public PageReference Previous(){
  if(steps.get(curStep).previous == null)
    return null;
		
  curstep = steps.get(curStep).previous;
  return steps.get(curStep).thePage;
}
	
public boolean getHasNext(){
  return steps.get(curStep).next != null;
}

public boolean getHasPrevious(){
  return steps.get(curStep).previous != null;
}

public string getPageTitle(){
  return steps.get(curStep).title;
}


The final piece of the puzzle is the checkStep action that I had on the page. Firstly, what is this for? Well I don’t like users thinking that they can shortcut the wizard, after all they asked for it they should go through the usability anguish the same as the rest of us. So, the idea of the checkStep action is to double check that the page they are trying to load is actually the next page in the wizard flow. This has the obvious advantage that once we get to the end of the wizard we can rest assured that the user went through every step and we’re not going to start getting null reference exceptions. The implementation is again a trivial one but it provides us with the security we need to stop users bookmarking the wrong page, entering in URLs themselves or generally finding a way to jump from page to page with no care for the implications to the data.

public PageReference checkStep(){
  if(getPagePath(ApexPages.currentPage()) != getPagePath(steps.get(curStep).thePage)){
    curstep = 1;
    PageReference pr = steps.get(curStep).thePage;
    pr.setRedirect(true);
    return pr;
  }
		
  return null;
}
	
private string getPagePath(PageReference pr){
  return new URL('http://temp.org' + pr.getUrl()).getPath();
}


There’s some messing around in there to make sure I am comparing like with like but the crux of the idea is to simply compare the PageReferences for the current page and the page curStep says we should be on. If they’re different return to the start. If not then just carry on as normal.

Whilst this is a basic, bare bones template for the implementation of a wizard in VisualForce I have to say I’m quite pleased with it. In particular because it brings all of the code responsible for navigation into one well defined place. Yes, it means we need a code change if we want to alter the flow of the wizard but what’s wring with that. The bonus is that we can write test classes to make sure that the flow of the wizard is what we want.

This is a starting point that I offer to the world; I’d be keen to hear your feedback on it from your personal experiences with such user requirements.