biExport for SAP Analytics Cloud Blog

How to create a Custom Widget for SAC – lessons learnt

created: 02.06.2020

Over the last months we at biexcellence have created three ready-to-use Custom Widgets for SAP Analytics Cloud (SAC). Each of them provides interesting features and functions, which are not available in SAC standard:

  • biExport: providing Briefing Book generation to PDF, PowerPoint, Word, Excel and CSV
  • biNotification: adding mailing features to planning and reporting processes
  • biSharing: enables users to upload files or select them for sharing their link, e.g. in a SAC standard comment

It’s time now to recapitulate what we like about SAP’s Custom Widget SDK, especially compared to the well-established SDK of Lumira Designer.

This post is also intended as a lessons-learnt for those of you, who start creating powerful Custom Widgets. So of course I also speak about problems that we encountered and things that SAP should work on to improve. This post is not intended as a general how-to, so I recommend that you have read SAP’s getting started documents before continuing.

Code files and programming

From our point of view the files of SAC Widgets:

  • JSON  (Definition)
  • Javascript (Code)
  • APS  (Properties Pane)

are much more structured than those of the Lumira Designer components:

  • Manifest
  • Component.xml
  • Component.ztl
  • Component.js
  • Propsheet.html
  • Propsheet.css
  • Propsheet.js

As a matter of fact, there are much less places to change something and hence less ways to make mistakes!

There is room for improvement, though: You still might have to change code in all three files to change something. A spelling mistake or coding error is only visible after having checked in your changes to GitHub. This may be a bit annoying if you are used to IntelliSense and context sensitive auto completion. 

Real javascript vs. ZTL in Lumira Designer

The definition of the Widget’s script methods represents another massive improvement over Lumira Designer components. Real Javascript now replaces the ZTL implementation, which offered a very restricted instruction set.

In Lumira Designer, we need a hack to call javascript functions on the web client from a component’s script method. Now this can be simply coded in a real javascript function.

Building a release and installing it

I personally never really got used to the way the release build of a Lumira Designer Component had to be created. The usage of Eclipse’s categories and features made the process much more complex than necessary, and it has been the possible source of many inexplicable problems.

Also, the installation process for a customer has been awkward, because in certain scenarios the update process did not work at all or files of an older version had not been properly deleted during deinstallation. This lead to the problem that files from an older version have been used instead of the new one.

This is now all different with SAC!

  1. We do not need a complex release build. We simply have to calculate the integrity hash, store the files somewhere on a central server and reference the file links in the Widget’s JSON
  2. The customer only has to upload a JSON to the tenant, and they can already use the Widget!
  3. The versioning is entirely managed by the programmer! A new version means a new JSON with (best practice!) new links.

Analytics Designer only

Custom Widgets currently can only be used in Analytics Designer. This is less an issue for the programmer, but – as we have learnt over the last couple of weeks – for customers:

Most customers start their SAC projects by rolling out the Stories to their users for self service reporting. They are still waiting for Analytics Designer to become as mature as Lumira Designer. At the same time, customers have encountered features missing in Stories that they would like to provide with Custom Widgets – but they cannot be used there.

As to our knowledge, SAP wants to support Custom Widgets sometime in 2021.

Inclompleteness of the API

Everyone misses the data API the most painfully. Whereas in our Widgets we can do without them, as soon as you want to do really good data visualization, this is where you currently have to stop. (to be correct, we can do MOSTLY without them, as we currently cannot export hidden rows of tables)

Of course, for simple charts you could provide a setValue() method, but in general this is only a workaround.

Moreover, official APIs to retrieve components and datasources of an application, as well as their states and properties, would be a great thing. Currently, there are ways of accessing them. But, the methods are not officially documented and therefore of course nothing that you could rely on…

As to our knowledge, SAP currently plans to support the data API with the Q4 2020 release.

Missing Custom data types

The setter and getter methods are really cool to use as long as you use simple data types, such as string, int or boolean. A complex Custom Widget, though, elementarily needs support of complex data types.

As an example, the biExport Widget allows customers to define an array of Custom Texts. These Custom Texts are pairs of name and value. The name describes a placeholder in the Export Template, the value provides the text that shall replace the placeholder. Hence, “Custom Text” is an object that consists of a name and a value. And an object “Custom Texts” defines an array of “Custom Text”.

Currently it is not possible to define such objects in a Widget, even though we are now using JavaScript, which provides a really simple way of defining objects and alternatively supports the usage of JSON.

In our Widgets we have a lot of these complex objects. What we currently do is: Instead of providing simple setters and getters, we only provide an addXXXX() and a clearXXXX() method. This is okay for now but a bit of a workaround.

We would really like to have the possibility to define complex objects (which was possible in the ZTL files with Lumira Designer). And we would like to enable our customers to work with these objects (which was also not possible in Lumira Designer). This would make working with complex data types much easier than today.

Missing Parameters in events

The possibility to create events in Custom Widgets is just great! It is a feature that we love to use for providing our customers with a way to customize the way they use our Widgets.

However, the events do not currently support a payload. E.g. for onSuccess or onError events it would be great if a parameter could be passed with the event, so a programmer could deliver a text message and, even better, a detailed status object.

Currently we have to provide two functions to achieve the same:

  1. onError event which the customer can implement to show an error
  2. getServiceMessage method which returns the error

Wrong Code execution order

It is a behaviour that we also encountered in Lumira Designer: For some technical reason the execution of setters does not follow the order in your code!

Take the following example:

setValueA(1);
setValueB(2);
calculateAplusB();

We would like to set two properties with values and then retrieve the sum of those two values in the code. You would assume that the framework first sets A and B with 1 and 2 and that the calculate method returns 3 as a result.

Not quite like it! In our tests it always returned 0! Why is that?

Debugging the code showed that the calculate method was called before the setters were called!

How did we solve this severe problem?

In addition to:

        get ValueA() {
            return this._A;
        }
        set type(value) {
            this._A = value;
        }

We added:

        getValueA() {
            return this.type;
        }
        setValueA(value) {
            this._setValue("type", value);
   
            let properties = {};
            properties[name] = this[name];
            this.dispatchEvent(new CustomEvent("propertiesChanged", {
                detail: {
                    properties: properties
                }
            }));
          }

In the JSON we define:

    "getValueA": {
      "returnType": "integer",
      "description": "Get Value A",
      "parameters": []
    },
    "setValueA": {
      "description": "Set Value A",
      "parameters": [
        {
          "name": "value",
          "type": "integer",
          "description": "The new value"
        }
      ]
    }

Some notes on the code:

  1. Defining the methods as setValueA instead of set ValueA and adapting the JSON to the new methods ensures that the order of the method calls is not changed
  2. We have to keep the setter and getter because they are used by the SAC framework, and also if you want to set the properties from the APS javascript.
  3. We have to call propertiesChanged in our set method because the framework will not take care of it!

Usage of oAuth service

We love the way we can easily configure and use oAuth with SAC. With Lumira Designer we had to use tokens, create a serialized session and use it for logging in.
For exporting it is crucial to execute with the user’s authorization, which made the solution quite complex.

The adoption of oAuth, on the other hand, allows us to request permission from the end user to reuse his/her authentication for the export process. We can even store this authentication securely to support scheduled exports!

SAP UI5 integration

First of all, it is a great thing that with SAC – being itself implemented using SAP UI5  -  you can easily use SAP UI5 in your Custom Widgets. You do not have to include the libraries as a programmer, because they are already available. So there are no obstacles between you and the perfect looking Widget.

Two things might slow you down though:

  • There is no official documentation on how to add SAP UI5 components to your Widgets. Our first trials resulted in ugly rendering without CSS, because the widgets are running in a shadow DOM. Now we are using slots in our Widgets, but it is unclear if this is the right approach and if it will be supported also in the future.
  • Some SAP UI5 components such as UploadSet might not be available and have to be added specifically for your Widget

Restriction to modern browsers

This point is not special to the SDK, as SAP Analytics Cloud in general needs the most modern browser implementations in order to run properly. It can be seen either positive or negative.

For programmers, this definitely is positive:

  • use the most modern features of javascript, CSS and HTML (e.g. slots)
  • “hacks” to support certain features also in older browsers are not needed

On the other hand, customers that are a bit more reluctant in adopting the most recent versions of operating systems, browsers and tools in general, cannot be targeted.

 

Our Customers

Our SAP Export solutions are alredy used by a number of global companies!

Logo Repsol
Logo Glatfelter Claas
Logo TÜV Süd
Logo JYSK
Logo Airbus
Logo Yamaha
Logo BKW
Logo Geberit
Logo Rockwell Collins

„With the export functionality we can bring fantastic solutions to our Design Studio users. Great tool, fantastic performance and powerful design options.“

Mario Rüger, Senior Architect Business Intelligence, TÜV Süd