GeeWizz – A Lightning Wizard Component

Continuing my series of component-based posts, I have a bigger component this time – a wizard component capable of hosting other components.

Salesforce Wizard Component

For some of my other component based blogs, look here:

Why?

Wizards are very useful for gathering a set of data that won’t easily fit on one page or is grouped into specific areas for collection.

Of course, you can use a flow or a process to gather this data, but there are limits to what you can do with flows. Using this new component, you can pretty much do anything you like with data inputs and outputs, types of components that you would like to display, the state that you would like to maintain, and more.

You have full control of the wizard. And you really want to be in control of your wizard. Who knows what they might get up to otherwise?

How (High-level)

The Wizard is a container component that instantiates and destroys child components as needed. It maintains its state across all children (as long as you tell it to). It also handles back, forward, close and other actions triggered from the children.

In my version, I generally put the back, forward, etc. buttons on the children and call the wizard functions from them.

If you would like the buttons on the Wizard itself rather than the children, that’s fine; it’ll handle that too.

The header is a wizard component used to main continuity across all the screens. You, of course, can update the text as you proceed through the screens.

Here’s what it looks like:

GeeWizz Lightning Component
GeeWizz Lightning Component in action

Details

The Wizard consists of:

  • A main wizard component
  • An opener (The wizard is opened like a quick action at present, but it could be hosted anywhere.)
  • An interface with a few common attributes for each of the Wizard sub components
  • A Wizard base component that all components must extend
  • Some event definitions

The main component contains attributes that define what components it should load and in what order.
In the future, I’m going to feed this in via a wizard wrapper so the same wizard can be used for multiple applications.

These attributes define the next and previous components. For example:

<aura:attribute name="nextComponentNameMap" type="Map" default='{
 "":"GeeWizzStep1",
 "cGeeWizzStep1":"GeeWizzStep2",
 "cGeeWizzStep2":"GeeWizzStep3",
 "cGeeWizzStep3":""
 }' />
<aura:attribute name="previousComponentNameMap" type="Map" default='{
 "cGeeWizzStep1":"",
 "cGeeWizzStep2":"GeeWizzStep1",
 "cGeeWizzStep3":"GeeWizzStep2",
 "":"GeeWizzStep3"
 }' />

When the Wizard opens, it finds the first component and attempts to instantiate it.

It binds several useful functions to the subcomponent:

  • Next (goes to the next component)
  • Previous (goes to the previous one)
  • Close (closes the Wizard)
  • Notify (shows an alert or other notification, configurable by the developer)
  • Context (a getter/setter allowing storage of data between components)

Typically you would load a component and then retrieve the context.
Thinking about this now, I really should inject it on load…

Another thing to note is that a function “init” is called on load of the component, rather than using the regular init event, as I have had timing issues using the standard technique.

Here is the most important part – creating the new components:

createComponent: function(component, nextComponent, dir) {
 var self = this;
 var direction = (!dir || dir == undefined) ? 'forwards' : 'backwards';
 $A.createComponent(
 "c:" + nextComponent, {
 "aura:id": nextComponent,
 userId: component.getReference("v.userId"),
 direction: direction,
 next: self.next.bind(self, component),
 previous: self.previous.bind(self, component),
 close: self.close.bind(self, component),
 notify: self.notify.bind(self, component),
 context: self.context.bind(self, component),
 },
 function(newComponent, status, errorMessage) {
 console.log(status);
 if (status === "SUCCESS") {
 var body = component.get("v.body");
 body = [];
 body.push(newComponent);
 component.set("v.body", body);
 } else if (status === "INCOMPLETE") { console.log(errorMessage); }
 else if (status === "ERROR") { console.log(errorMessage) }
 }
 );
 },

Note the ‘bind’ calls – these bind the calls from the sub-components to this component, which is a nice direct way to call methods on the parent.

And lastly, the Wizard Opener uses the Overlay library to instantiate the Wizard itself in a popup.
Of course, you could just put it on a page or load it onto a Lightning layout.

Currently, this wizard does not save its status/context to Salesforce, so you need to open it fresh every time.

This again could be easily rectified by saving a current status variable to an appropriate location.
You could also save the context object (encoded as JSON) and rehydrate it on load.

I hope you find this useful.

Download the files

All the files are located on Github.

Enjoy!

Cool Components

Have questions? Let us know in a comment below, or contact our team directly. You can also check out our other posts on customizing your Salesforce solution.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top