A State Machine for UI Control

Reusable Detail View Control

A common situation in web UIs is that you can select some item to view and edit its details. Selection can be done using treeviews, list, search masks and more.

Examples

Example using a TreeView for selection
Example using a TreeView for selection with detail view in edit mode and TreeView hence disabled
A web UI with a search mask on top and a detail mask below
Using a search mask for item selection

Detail View Behavior Model

When the displayed item is edited, the selection should be disabled. So there is a lot of stateful behavior:

  • User actions in the selection component change the content of the detail component.
  • User actions in the detail component
    • may disable the selection component
    • may enable or disable buttons

It turns out that the behavior model for many simple detail view components is similar. So it makes sense to provide a base class that captures this behavior. A simple state chart for the behavior model looks like this:

DetailView Control State Chart
State chart controlling a DetailView

Implementing Standard Detail View Behavior

The abstract Groovy class DetailViewBehavior.groovy serves as a control template for detail view implementations. It can be embedded as an (anonymous) inner class that controls view behavior. Abstract methods have to be overwritten to control specific view elements and communicate with the environment.

Comments on Code
Line 80
Class DetailViewBehavior uses a StateMachine object to implement behavior. This object is protected so that it can be modified (e.g. added additional transitions or activities) by a derived class.
Lines 86 and 88
The state machine is created and initialized in public method initSm() with the appropriate start state. In the following lines, all onEntry activities and transitions are added as shown in the above state chart. For every state,  an onEntry Closure is provided. Also all transition have Closures. They all call methods, most of them abstract, that must be implemented in derived classes.
Line 133
Public method execute() directly delegates to the StateMachine instance.
Line 143
@Deprecated  method initItem(Long itemId)  was used to load a new object into the detail view. Its functionality is now refactored to transition method onItemSelected(Long itemId) . Given the itemId, a data transfer object for this object can be retrieved from the service layer. It will usually be stored in some local variable and its fields displayed in the view.
Lines 146, 148, 157, 163, 165, …, 175, 178, 184, 193
Protected methods implementing activities onEntry and on transitions. It was found that some activities are often unneccessary, so these have empty default implementations. The others are made abstract to enforce their implementation. See javadoc comments for more detailled descriptions.
Lines 207 … and 237 …
Enums defining states and events for the state machine. Due to Javas implementation of Enums, it is not simple to make states and events extendable without loosing the benefits of Enums. Therefor three „spare“ state (XST1, XST2, XST3) and event (XEV1, XEV2, XEV3) values are provided to allow some additional states and events for an extended state chart.

Integrating DetailViewBehavior into a Vaadin View

Class DetailViewBehaviour is intended to be used in a component subtree for displaying and editing details of some domain objects. The example uses SubTree as a base class for implementing the detail view. See full code of example class MilestoneDetailView on GitHub.

Embedding an object derived from DetailViewBehaviour as an anonymous inner class, all ui elements of the surrounding class are accessible from DetailViewBehaviour methods. External method calls, e.g. selection of a different object in a selection component, are transformed into events sent to the behavior state machine.

Comments on code
Lines 176, 178
When a new object is selected for display, onItemSelected()  is called. The Id of the selected object is sent to the state machine as a parameter to DVEvent.Select by calling the execute method of viewBehavior.
Line 184
The controlling state machine viewBehavior is constructed as an object of the anonymous inner class derived from DetailViewBehavior. All abstract methods have to be implemented here. As methods of an inner class, they have full access to the Vaadin ui components built with VaadinBuilder.
Lines 191, 201, 208, 215, 221
Entry methods of states primarily prepare enabled state of all input components. Common functionality of editing and creation states is put into methods prepareEdit()  and presetEmpty() .
Line 235
Transition method that loads another object from the service layer into the detail view. It is triggered by a changed selection in the selection component.
Lines 235, 248, 274
Transition methods that send edited or created objects to the service layer for saving, triggered by an event from the Save button.
Lines 257, 264
Transition methods that reset UI state when Cancel button is pressed from editing or creating state.
Line 280
Here the actual save or create interaction with the service layer is done. Then the updated object is saved in the local currentDto  variable. Also the list of selectable objects for a toMany association is reloaded from the service layer.
Line 304
The superordinate selection component is notified that editing is finished. So it can be enabled again to allow new selections. Object attributes that are used as a tag in the selection component are passed to allow an update of selection lists or trees. If the structure has changed significantly, e.g. by creating a new object, the selection component is notified so that it can reload from the service layer.
Lines 313, 323, 333, 342
See the Javadoc comments on these helper methods.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.