ZK8 Wizard Example - Part 1
Robert Wenzel, Engineer, Potix Corporation
July/August 2015
ZK 8.0
Introduction
ZK 8 contains many new features to provide a easier approach to cleaner MVVM development and simplify reusing UI elements. The goal of this smalltalk series is to give ideas and scenarios where/how those new features (e.g. LINK ME shadow elements and template injection) can be applied, and how it helps to separate the application model (java code) from the UI (zul files).
e.g. <sh:if> <sh:forEach> <sh:apply> <sh:choose>
This example is NOT intended to copied/pasted as-is, as every application has different requirements and here only those requirements that I made up myself are covered, so please don't claim missing features in this wizard (according to my requirements they are not missing) and if you like feel free to use these ideas, and implement your own.
As an example I chose a reusable wizard template. Since it has the same frame layout but different content for each step - making it an ideal showcase for templating and a model driven UI (MVVM).
There will be 4 Parts in this series:
- Defining a wizard template (+ simple example)
- Using the wizard in a complex example (Order process)
- Add form binding & validation
- Styling the wizard (with Bootstrap)
This first part will introduce a wizard template with a simple example wizard, implementing a 3-Step Survey.
Note that I am using Java 8 for this example (everything can be done in older Java versions too, it's often just more to write). I encourage everyone to switch to Java 8 to benefit from new language features and more important: security updates. If you find my usage of Java 8 features inappropriate I am happy for constructive comments.
A reusable Wizard class/template
- zk.example.wizard.model.WizardViewModel.WizardViewModel
- zk.example.wizard.model.WizardStep
- /wizardexample/src/main/webapp/WEB-INF/zul/template/wizard/wizard.zul
Simple Usage (Survey)
The basic wizard usage can be demonstrated implementing a simple survey consisting of basically 3 different parts (explained below):
- Java ViewModel (SimpleWizardViewModel.java)
- start page (simple.zul)
- step pages (/WEB-INF/zul/simplewizard/steps/*.zul)
- zk.example.simplewizard.SimpleWizardViewModel
- ViewModel containing the initialization code, defining the steps
...
@Init
public void init() {
survey = new Survey();
initWizardModel();
}
private void initWizardModel() {
List<WizardStep> availableSteps = Arrays.asList(
wizardStep(QUESTION_1),
wizardStep(QUESTION_2),
wizardStep(QUESTION_3),
wizardStep(DONE)
.withBeforeNextHandler(() -> Executions.sendRedirect("./simple.zul"))
.withNextLabel("Restart")
);
wizardModel = new WizardViewModel<WizardStep>(availableSteps);
}
private WizardStep wizardStep(String stepId) {
String title = stepId;
String templateUri = STEP_FOLDER + stepId + ".zul";
return new WizardStep(stepId, title, templateUri);
}
...
- Lines 3, 4, 18: initialize the viewModel properties
- Lines 14, 15: define custom "next" handling and label
The ViewModel is not doing much, just creating the empty Survey and WizardStep objects and finally initializing the WizardViewModel.
- /wizardexample/src/main/webapp/simple.zul
- the start page using the simple wizard
<?component name="wizard" templateURI="/WEB-INF/zul/template/wizard/wizard.zul" ?>
<zk>
<div width="500px"
viewModel="@id('vm') @init('zk.example.simplewizard.SimpleWizardViewModel')"
validationMessages="@id('vmsgs')">
<wizard wizardModel="@init(vm.wizardModel)" survey="@init(vm.survey)">
<!-- injected template - visible inside the wizard -->
<template name="yesno">
<radiogroup selectedItem="@bind(answer)">
<radio label="Yes" value="${true}"/>
<radio label="No" value="${false}"/>
</radiogroup>
</template>
</wizard>
</div>
</zk>
- Line 1: define the <wizard> component based on a template
- Line 7: add a <wizard> using a wizardModel and a survey object
- Line 10: inject a template re-usable throughout the wizard steps
- /wizardexample/src/main/webapp/WEB-INF/zul/simplewizard/steps
- contains all the wizard steps showing one exemplary step here question_2.zul
<zk xmlns:sh="shadow">
Have you ever climbed a rock?
<sh:apply template="yesno" answer="@ref(survey.answer2)"/>
<sh:if test="@load(survey.answer2)">
Did you fall down?
<sh:apply template="yesno" answer="@ref(survey.answer2b)"/>
</sh:if>
</zk>
- Lines 3, 6: apply the previously injected template
- Line 4: conditionally display a dependent question
As you see the shadow elements come in handy avoiding code duplication and ensure a consistent rendering.
That's enough to create a wizard for a simple case.
Now let's use the same wizard template for a more complex case. in Part 2 'LINK ME
More complex Usage (Order Wizard)
- Basket
- adjust basket (add/ remove/ change items)
- Shipping Address
- enter shipping address
- Payment
- choose payment method + enter conditional details
- Confirmation
- review data, accept GTC submit order (handle exceptions)
- Feedback
- user feedback when order was successful
Data Model
zk.example.order.api.Order
- Order
- Basket
- BasketItem (list of)
- Payment (payment method)
- CreditCard (based on payment method)
- or BackAccount (based on payment method)
- ShippingAddress (city, street, zip code)
- Basket
Form Row template
Additional features
Input Mask
Bookmarks Handling
Custom I18N
using the same convenience functions in the zul and java code
More complex Usage (Order Wizard)
Summary
bla bla
What's next?
Download
- The source code for this article can be found in github.
Running the Example
The example consists of a maven web application project. It can be launched with the following command:
mvn jetty:run
Then access the overview page http://localhost:8080/longoperations/overview.zul
And that's what you'll see:
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |