Skip to Content
Technical Articles

SAPUI5 Formatters with Promises (Change UI when Promise resolves)

Background

1st time blogger here on SAP Community – Hope I get this right 😊

The project me and my colleagues are currently working on is a really big one (Maintenance applications for Railway technicians):

  • We are wrapping UI5 applications in UWP (Universal Windows Platform) apps with WinJS to call device API’s.
  • In the future we might use PWA applications (to support other platforms besides Windows)

This app has a synchronization mechanism to download multiple OData Entity Sets offline stores them in an IndexedDB: The datasets are quite big and complex (requiring calculations & combining of data out of multiple stores on the front-end)

Combining data on the front-end is ofcourse an expensive operation, which forces the user to wait until the data is ready.

An example of this is our so called “Checklists”. A checklist is a set of checks/measurements/inspections a technician has to do:

  • Is the light still working when you press the switch upon entry of the building?
  • Is there a smell when you enter?
  • Is the floor dirty?

These are just some examples checks obviously, but the Checklists are really detailed and multiple levels deep (I’ve seen ones go down to 10 levels deep) (parent-child tree).

Problem

In some screens (XML views) we need to do some data combination before we can show the result to the user.

  • A few examples:
    • Load possible values for a Select field based on values filled in other Select fields.
    • Load Characteristics in a table for a Functional Location we are displaying.
    • Calculate the Tree for our complex Checklists. (The bigger the Checklist, the longer it takes)

The above actions are slow and would normally block the UI, and prevent the user from interacting with the application – So we use Promises & Javascript Workers (And in-memory caching) to overcome those problems.

The “being slow” is especially noticeable in UWP, as it still uses IndexedDB 1.0!

Solution

Promises are mentioned a couple times here on SAP Community, so I wanted to share a cool trick with them.

We have a screen for Workorders, where multiple operations can contain checklists.
If we would load these Checklists at the moment a user wants to start his inspection, he would have to wait for the tree to be loaded and he’d be staring at a blank screen… –> Not user friendly at all!

What if we could show the Workorders screen to the user already, and combine the data for the Checklist in the background. After the calculations for the Tree are done, we enable the button to start them? (With a Formatter!)

  • This way the technician can interact with the workorder (Start/Pause), and in the background the model is already being loaded for all Checklists in the operations.

Formatter functions don’t work with Promises (yet?), they only get executed when the property they listen to changes.

1 way to trigger the Formatter would be to just do:

  • getView().getModel(“workorder”).setProperty(“/bIsChecklistLoaded”, true) when the Promise is resolved (in the controller), and make the formatter listen to bIsChecklistLoaded.The setProperty would do a Formatter trigger & the Button would become visible as soon as bIsChecklistLoaded is true.
  • Another way to do it, would be to call the refresh function on your Model
    Please don’t do this: In complex applications, refreshing a Model with a lot of Formatters attached can kill your app responsiveness!

Since our application is rather complex, we’d like an easy way to trigger a formatter when the data on an object’s property becomes ready (so the UI behaves responsive to these events)

Example is below!

 

View code:

<Button icon="sap-icon://action" text="{i18n>ACTIONS}" press="onActionsPress" busy="{path:'workorder>Checklist', formatter: '.formatter.isPromiseLoading'}" />

 

Controller code:

var oModel = this.getView().getModel("workorder")
oModel.setProperty("/Checklist", new Promise(function (resolve, reject) {
  setTimeout(function () {
    // Operation that takes some time to complete...
    // Building a Parent/Child Tree for example...
    resolve(); // Resolve the original Promise
    oModel.setProperty("/Checklist", new CheckListTree({…}));
  }.bind(this), 10000);
}.bind(this)));

Formatter code:

Formatter.prototype.isPromiseLoading = function (oObject) {
  return oObject instanceof Promise; // As long as it's a promise, the Button will stay in Busy state!
};

 

Some example screens:

The classifications are fetched Online (and are only shown if a connection is available)

The lookup of the data online takes some time, but to inform the user that something is loading, we set the table to Busy.

After the Promise resolves, we replace itself on the model with the outcome of the Promise, triggering the Formatter!

 

Conclusion

This is a really good way to load parts of your UI as data becomes available on an object Model in the background, without having to add lots of boolean variables on your model (it just makes your code unreadable).

You could make parts of the UI load as they become available – and prevent users to interact with them as long as the data is still loading)

Please let me know if this helped you, or you found other uses for this!

To wrap it up: if you have any remarks or comments – Feel free to let me know in the comments! Perhaps you guys can also share some other cool tricks that you do in UI5? – They might help us some day! 😊

 

 

Be the first to leave a comment
You must be Logged on to comment or reply to a post.