A Content-Driven Approach To Building Powerful And Flexible Wizards
Technical Blogs January 30, 2017 By Javeed Chida
Let me begin by clarifying that this post has nothing to do with the Harry Potter universe.
But seriously. You know what I mean by wizards, don’t you? Those helpful series of screens that gather a set of choices from the user and then use the captured choices to do something for the user. Often times, one user selection can lead to a different outcome that the other choices on the same screen.
It turns out I am faced with a requirement to build such a wizard. And the requirements are a little bit amorphous. So I asked myself the same question I have come to ask before embarking on a multi-layered application development effort:
Can I accomplish this with the content management system?
Or more verbosely stated as:
Are all the layers I need to accomplish this already there for me?
Well, the answer is yes. It can be done using the CMS. And it can be powerful and flexible.
Here are my requirements for a contrived Mood Wizard:
- Screen 1: Ask user to pick their position (you know: standing, sitting, etc). Picking an option on Screen 1 takes them to Screen 2.
- Screen 2: Ask user how they feel (happy, sad, angry, etc.). Picking an option on Screen 2 takes them to Screen 3 unless they pick ‘angry’, in which case they are taken to Screen 4.
- Screen 3: Ask user to choose an energy level. Picking an option on Screen 3 takes user to Screen 999 (the final screen).
- Screen 4: User types up a rant and hits Continue to be taken to Screen 999 (the final screen).
- Screen 999: This is the final screen. User can click the Go button to do something with their choices.
- At any point during use of the wizard, the user can back up a screen.
- At any point during use of the wizard, the user can start over.
- At any point during use of the wizard, the user can see what choices they’ve made from screens that had choices (aka options) rather than custom markup.
Here are the moving parts of my solution:
- A structure
- A template
- A Dynamic Data List definition (to house rants from angry visitors)
- A servlet to call into the DynamicDataListRecord API (because it’s a great persistence mechanism with a clean API and is one of the goodies that Liferay comes with).
Here is the structure I defined:
Some interesting things to note here:
- The screens are repeatable.
- The options within a screen are repeatable.
- Every option has a Target Screen Identifier - the identifier of the screen to load when the option is selected. it also has a Target URL in case picking it needs to change the page location.
That simplicity to me is POWER.
You may note that I also have a Custom Markup for each screen and a Target Screen Identifier for it. This allows for the definition of custom markup and a way to configure the next screen to go to if Custom Markup is adopted for any given screen. In my contrived use case, Custom Markup is perfect to capture the user’s rant if they were to pick Angry.
And that gives me the FLEXIBILITY I need.
Here is the XML definition of the above structure.
And here is the Velocity template I wrote for it.
For screen 2, I capture some user information (an email address and a rant) and post it to my VisitorRantServlet that saves it to a DDL record-set. The user can setup an instance of the stock Dynamic Data List Display portlet portlet to view/edit the submitted records.
Here are some screenshots if the above link doesn't work. The Web Content Display portlet on top shows the content item I created using the previously define structure and template. The Dynamic Data List Display portlet below it shows any rants added.
There are lots of possibilities here. Here's a few:
- Any screen can use custom markup to load any data from a servlet, REST service and such, in much the same way that I use it to capture a visitor’s rant.
- The template is wide open to code in any extra customization. (You know you’ll need it.)
- We have the robustness of content versioning.
- I do wish we had the added robustness of template (and even structure) versioning :-(.
By the way, you don't need a servlet to call into the DDL Record Set API. JSONWS makes it a snap but there is the inherent complexity of having to deal with basic authentication. The raw API lets you run any trusted code on the server and was my preference for the purpose of this demo.