Wizard Plugin
A Wizard is a dialog that consists of multiple pages and guides a user through a multi-step process. Wizards usually involve getting input from the user and then performing some action based on those inputs.
Use Wizards Wisely
In the past, especially when they became popular, wizards were used for everything - even things that could otherwise be simple dialog or wouldn't need a UI at all. Therefore a word of caution: Use wizards wisely. Make sure you really need to guide a user through a blocking process. If you do, then wizards can be very powerful.
Creating a Wizard
A basic wizard with a single page and a close button.
var plugin = new Wizard("Your Name", main.consumes, {
title: "The title of the dialog",
allowClose: true,
height: 200
});
plugin.on("draw", function(){
var firstPage = new WizardPage({ name: "first" }, plugin);
plugin.startPage = firstPage;
});
plugin.show();
Looks like this.
Wizard inherits from Dialog()
The interface from
Dialog()
is available to you as well. That means that you can tweak the button bar of your wizard and use any of the other APIs thatDialog()
offers.
Wizard Properties
The following properties can be passed to the Wizard()
constructor.
allowClose | Boolean specifying whether the close button is shown. |
---|---|
class | The css class for the wizard dialog. |
height | The height of the wizard dialog. |
width | The width of the wizard dialog. |
resizable | Whether the wizard dialog is resizable. |
title | The title of the wizard dialog. |
modal | Whether the dialog is modal. Defaults to true. |
Adding Wizard Pages
A wizard lets a user walk through different wizard pages via next and previous buttons. Optionally the wizard can show the user finish and cancel buttons when appropriate. The wizard api lets you decide the sequence of the pages shown. It keeps a history of the shown pages in order for the previous button to provide a consistent history. Of course even this can be influence via events.
Lets start by creating four pages. It is common practice to create the wizard pages in the draw
event of the wizard. This way they are created just in time.
plugin.on("draw", function(){
var intro = new WizardPage({ name: "intro" }, plugin);
var input = new WizardPage({ name: "input" }, plugin);
var action = new WizardPage({ name: "action" }, plugin);
var last = new WizardPage({ name: "last" }, plugin);
plugin.startPage = intro;
});
Settings the startPage
property tells the wizard to show that page (in this case intro
) when the wizard is first shown.
Adding your own contents
The easiest way to populate a dialog is by adding custom html and css. The following example loads css from wizard.css and adds a div element to the body of the first page.
plugin.on("draw", function(){
// Insert css
ui.insertCss(require("text!./wizard.css"), options.staticPrefix, plugin);
var intro = new WizardPage({ name: "intro" }, plugin);
intro.on("draw", function(e){
// Insert HTML from a file
ui.insertHtml(e.html, require("text!./intro.html"), intro);
});
var input = new WizardPage({ name: "input" }, plugin);
var action = new WizardPage({ name: "action" }, plugin);
var last = new WizardPage({ name: "last" }, plugin);
plugin.startPage = intro;
});
In the same way you can populate the other pages with contents as well. Make sure to check out the Ace Widgets and Form as they make for a great combination with the wizard pages.
Managing State during the Page's Life Time.
Similar to the Dialog plugin use the show
event to manage state of the components in the page.
This example adds a list widget to a wizard page. Each time the page is shown the contents of the list of recalculated.
var input = new WizardPage({ name: "input" }, plugin);
var list;
input.on("draw", function(e){
list = new List({ container: e.html }, plugin);
});
input.on("show", function(){
list.setRoot(calculateItems());
});
Wizard Buttons
The next and previous buttons are automatically turned on when a page is activated. You can use the next
event as described in the next section to alter the visible state of the 4 buttons that the wizard has.
The code in the example below would show all buttons except next.
plugin.showNext = false;
plugin.showPrevious = true;
plugin.showFinish = true;
plugin.showCancel = true;
Which looks like this.
Wizard Interactions
Use the next
, previous
and cancel
events to breathe life into your wizard. You often want to determine the next page based on choices a user has made for instance. The following sections tell you how to do this.
We'll assume there are four pages; intro
, input
, action
and last
Next Event
The next
event is fired when a user clicks on the next button. You determine which page to present next to the user by returning a reference to that page in the event handler.
This is what the next
event handler might look like for our wizard. After the intro
pag the user goes on to the input
page. There the user can either click a checkbox or not. If the user checks the checkbox and clicks next they go to the action
page. Otherwise they are shown the last
page. After the action
page, the last
page is shown as well.
plugin.on("next", function(e){
var page = e.activePage;
// Intro -> Input
if (page.name == "intro") {
return input;
}
// Input -> Action (if checked)
else if (page.name == "input") {
if (page.container.querySelector(".checkbox").checked) {
plugin.showPrevious = false; // We don't allow to go back from here
plugin.showCancel = true; // Allow the user to cancel the process
return action;
}
}
// In all other cases, show the last page
plugin.showFinish = true;
plugin.showPrevious = false;
plugin.showNext = false;
return last;
});
Previous Event
The previous event is called when a user uses the previous button to navigate to a page.
plugin.on("previous", function(e){
var page = e.activePage;
if (page.name == "intro")
plugin.showFinish = true;
});
Cancel Event
The cancel event is called when a user clicks the cancel button.
plugin.on("cancel", function(e){
abort();
plugin.gotoPage(last);
});
Navigating
You can programmatically trigger the actions that correspond to the buttons.
plugin.next()
plugin.previous()
plugin.cancel()
plugin.finish()
In addition you can display any page automatically.
plugin.gotoPage(intro);
The page will be added to the history when using gotoPage()
.
Fetch a reference to the active page like this.
var page = plugin.activePage;
Full Example
define(function(require, exports, module) {
main.consumes = ["Wizard", "WizardPage", "ui"];
main.provides = ["yourplugin"];
return main;
function main(options, imports, register) {
var Wizard = imports.Wizard;
var WizardPage = imports.WizardPage;
var ui = imports.ui;
/***** Initialization *****/
var plugin = new Wizard("Your Name", main.consumes, {
title: "The title of the dialog",
allowClose: true,
height: 400
});
plugin.on("draw", function(){
// Insert css
ui.insertCss(require("text!./wizard.css"), options.staticPrefix, plugin);
var intro = new WizardPage({ name: "intro" }, plugin);
intro.on("draw", function(e){
// Insert HTML from a file
ui.insertHtml(e.html, require("text!./intro.html"), intro);
});
var input = new WizardPage({ name: "input" }, plugin);
input.on("draw", function(e){
// Insert HTML from a file
ui.insertHtml(e.html, require("text!./input.html"), input);
});
var action = new WizardPage({ name: "action" }, plugin);
action.on("draw", function(e){
// Insert HTML from a file
ui.insertHtml(e.html, require("text!./action.html"), action);
});
var last = new WizardPage({ name: "last" }, plugin);
last.on("draw", function(e){
// Insert HTML from a file
ui.insertHtml(e.html, require("text!./last.html"), last);
});
plugin.on("next", function(e){
var page = e.activePage;
// Intro -> Input
if (page.name == "intro") {
return input;
}
// Input -> Action (if checked)
else if (page.name == "input") {
if (page.container.querySelector(".checkbox").checked) {
plugin.showPrevious = false; // We don't allow to go back from here
plugin.showCancel = true; // Allow the user to cancel the process
start();
return action;
}
}
// In all other cases, show the last page
plugin.showFinish = true;
plugin.showPrevious = false;
plugin.showNext = false;
return last;
}, plugin);
plugin.on("cancel", function(e){
abort();
plugin.gotoPage(last);
}, plugin);
plugin.startPage = intro;
});
/***** Functions *****/
function start(){
}
function abort(){
}
/***** Lifecycle *****/
plugin.on("load", function(){
});
plugin.on("unload", function(){
});
/***** Register and define API *****/
/**
* Your wizard description
**/
plugin.freezePublicAPI({
});
register(null, {
"yourplugin": plugin
});
}
});
Updated less than a minute ago