How to handle state transitions in SAPUI5

In this blog post I want to share with you my approach to handle states and transitions between them in a SAPUI5 app. This idea was used in a recent project and has shown to be robust, flexible and easy to maintain.

 

Problem statement

Often SAPUI5 apps have some kind of state and possibilities to manipulate these states. For example a request could have the states “initial”, “pending” and “resolved”. Additionally only some actions are allowed on a certain state. And depending on the current state and the applied action the request must transition to another state. Finally there must be some representation of the states and actions on the UI.

 

Theory basics

An approach I have used in a project was to encapsulate all state transition into a so called state machine object.

For those of you who went through theoretical computer science during their studies will for sure have encountered such a state machine.

You may remember it as something complex, far from practical usage and hard to grasp. But we will only talk about deterministic finite state machines which are quite easy to understand. They have only a finite number of states and are deterministic, meaning a transition from one state to another one is always explicit for any input.

So let’s have a look at how a state machine is defined:

It is basically a quintuple  with:

 input alphabet (stuff on which the state machine reacts to, i.e. an action)

 states (i.e. “pending”, “resolved”)

 the initial state

 the state transition function

 final states (defines when the state machine stops)

This model allows us to perform transitions depending on the input (i.e. an action) and the current state. State machines which show this behavior are also called Mealy machines.

 

Adaption to our problem

Let’s now see how we can adapt this theory to our initial problem.

As initially pointed out we want to show different states of an item and depending on the state allow different actions to be performed which will change the state (see Fig. 1).

The input alphabet is therefore a collection of strings which represent the actions. States will be the states which are possible for our item (“initial”, “pending”, “resolved”, “deleted”) whereas the final state is defined as “deleted”. And the transition function looks like this:

(“initial”, “save”) -> “pending”

(“initial”, “resolve”) -> “resolved”

(“pending”, “resolve”) -> “resolved”

(“resolved”, “delete”) -> “deleted”

This is a partially defined function as there are not all possibilities defined.

Fig. 1: Planned state machine

 

Implementation

Now how do we implement this? It turns out that this is quite easy. In SAPUI5 we can define our own object (often called “class” but actually this is a prototype).

sap.ui.define([
	"sap/ui/base/Object"
], function(BaseObject) {
	"use strict";

	/**
	 * State Machine for status handling
	 * @class
	 */
	return BaseObject.extend("com.sap.example.StateMachine", {
		oStateMachineService: null,
		iPendingCurrentStateId: null,
		oStatusTransitions: {},
		oCurrentState: [],
		aActions: []
		...

This object will encapsulate the mathematical model which was explained before. The aActions array contains the input alphabet (“save”, “resolve”, “delete”) and oCurrentState contains the current status of the state machine (consisting of a unique id, name and the successor states). Each successor consists of an id and an action which specifies the required action to transition to this state.

Additionally the state machine is designed to be very flexible, therefore the transitions and actions are loaded from an XS OData service which is passed in to the state machine in the constructor (using the ODataModel from SAPUI5). In its constructor the service is called and the entries (actions, transitions) are loaded. On the database the data could be modeled with three columns, for example the first state:

  • Id: 1
  • Name: initial
  • Successors: [2:save,3:resolve]

Note the property iPendingCurrentStateId? As this state machine will be used in other components of the app we must ensure that when the state of it is set but the state machine is not yet initialized (from the OData service) that the state will not be lost. Therefore it will be cached and on successful initialization it will be immediately set.

To properly handle the states some functions are required:

  • getCurrentState()
  • getAllowedActionsForCurrentState() (gives an array of allowed actions for the current state)
  • transition(sAction) (will transition to the next state depending on the action and the current state)

These functions are easily implemented by checking the current state object and its successors.

Anytime the UI transitions to a state we just have to call the transition() function on the state machine and then can get the current state and the follow up actions which are available. This nicely encapsulates all state handling in a single object and keeps the business logic clean.

The only missing point is how to trigger the transitions in the UI?

To do this some buttons are normally used. If you are using the XML based views you can set the “visible” attribute of each button to a local JSON model property.

If you take the two buttons “save” and “delete” then you could bind them on the property “/actions/save” and “/actions/delete”. Finally you have to update these properties by reading the state machine’s allowed actions (using getAllowedActionsForCurrentState()) and setting the properties in a loop.

This is the required clue code to bind the state machine to the UI.

 

Conclusion

We have tackled the challenge to handle different states and corresponding actions with a simple implementation of the powerful theory of deterministic finite state machines.

I hope this introduction on how to utilize state machines in SAPUI5 was helpful and will make your apps more robust and flexible.

If you have any questions regarding the implementation details feel free to come back to me.

 

 

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply