Skip to Content

Maybe you like SAPUI5 like I do. Then for sure you know the great SAPUI5 sample and documentation pages SAPUI5 Explored or SAPUI5 Demo kit. There you can easily browse though all available SAPUI5 controls and documentation about all properties and functions. But the greatest are the samples: Just run them – and if you like one, you find all source code in form of some XML and JavaScript snippets.

Wouldn’t it be great to use such content directly in your Design Studio or Lumira Desginer app? – Without writing a SDK component and dealing with JSON data formats etc? Here you go.

 

What You Need

You need two ingredients:

  • To access analytical data in SAPUI5, you need an SAPUI5 model implementation. Fortunately I have implemented it already as part of Design Studio 1.6, it ships in all later versions including Lumira 2.x. It has been undocumented so far, but I think in the meantime it is mature enough to be used when needed.
  • A little SDK component that allows to use so-called SAPUI5 XML Views directly in your app without a need for additional components. I’m currently integrating this component into SCN Community package for Lumira 2.x and for Design Studio. In the meantime you find the source code here.

 

Try It Without Data

If you have the XMLView component installed, you can try it without coding. Create one instance in Designer and ensure that the Additional Properties View is visible.

In the SAPUI5 Demo kit, find the sample, then switch to source view.

 

Now copy the XML view content to the upper part and the Controller JavaScript code to the lower part of the Additional Properties View.

Cool, isn’t it? You can immediately run the app, modify the XML or JavaScript or even add multiple XMLViews and other components.

 

Use Data

The sample above is quite nice, but also quite useless: The values that the charts display are hard-coded sample values.

I promise you that you will be able to use any SAPUI5 with any Lumira data source when you have read the whole article, but at the beginning let’s use a very simply sample that should work with most data sources without modifications.

Add a data source to your app and drag it over the XMLView component to bind it (or set the “Data Source” property in the Properties View).

Now add the following XML to the upper part of the Additional Properties View. The lower part should stay empty.

<mvc:View
 xmlns:l="sap.ui.layout"
 xmlns:core="sap.ui.core"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns="sap.m">
 <List
  id="dimensions"
  items="{/dimensions/(MEASURES_DIMENSION)/members}">
  <StandardListItem
   title="{text}"
   description="{key}"/>
 </List>
</mvc:View>

 

You will see a list of measures in a list box.

 

How Does It Work

Lumira uses SAPUI5 internally. If you use SAPUI5 directly, you will recognize that, both, Lumira and SAPUI5 have much in common. Both allow you to assemble UI elements. Both  follow the Model-View-Controller design principles – and both contain a powerful Data Binding feature. The following table lists some aspects:

Aspect Lumira Designer SAPUI5
Elements Component Control
Data is coming from Data Source (BW, HANA, …) Model (JSON Model, ODataModel)
Logic is written in Event Handlers Controller
UI is stored in App or Composite View (e.g. XML View
Bind data to a complex element Set data source property List Binding
Bind data to property Use a Property Binding Binding Path

 

As you see, mainly the concepts in Data Binding are different and incompatible. To close the gap, I have implemented the “Lumira SDKModel for SAP UI5” (“SDKModel” for short), which solves this gap. It provides a Model for SAPUI5 data binding – based on Lumira data sources.

The SDKModel provides all data from a SDK Result Set JSON via the SAPUI data binding Model API, just as the existing models JSONModel and ODataModel do.

 

Binding Syntax

Once the model is attached, almost all properties of an SAPUI5 control can be bound. In XML views, a property is bound using the “{<bindingPath>}” syntax. A Binding Path consists of one or more parts, starting with and separated by slash signs, for example “{/<part1>/<part2>/<part3>}”. This concept is the same for all models, but the syntax and meaning of the parts depends on the model type. E.g. SDKModel has different supported parts than ODataModel or JSONModel.

Simple and List Binding

Depending on the type of the bound property, the model must either provide a single value or a list. In case of single values, SAPUI5 also supports type conversion and formatting. For details see the SAPUI5 documentation.

Properties that bind to a list are typically used for aggregations (which would normally contain child controls). For example, a Listbox control has an “items” property that is normally filled with a number of ListboxItem controls. But for data binding, you bind the “items” property to a list or array of the model and provide a single template ListboxItem control. For each entry in the bound list, SAPUI5 will automatically clone the template and connect it with the entry from the model. Therefore, the template can use a relative binding path (without a leading slash) which will be used to bind relatively to a list entry.

In the example above, listbox’s “items” propertiy might be bound to “{/something}” and the ListboxItem template has a “text” property bound to “{else/value}”. SAPUI5 will create ListboxItems for each entry. And each ListboxItem’s “text” property is bound to “/something/0/else/value”, “/something/1/else/value”, and so forth.

In effect, the binding path is a concatenation of the path of the list-bound property, the index, and the relative path of the template. This approach can be arbitrarily nested, having controls containing controls containing controls, etc., always propagating bound parts of the model to the children.

Master Data Paths

The following paths access master data (sometimes also called meta data), that is, data that is on an axis, such as dimensions, members, attributes, etc.

The model directly accesses the SDK JSON and thus corresponds to the JSONModel documentation. In all arrays you can either specify the index, the key, or a placeholder (like “(MEASURE_DIMENSIONS)” ).

 

Path
Description
/dimensions List of dimensions; column dimensions first, then row dimensions
/dimensions/0 First dimension – which is the dimension on columns, index 0.
/dimensions/<key> Dimension with the given internal key
/dimensions/(MEASURES_DIMENSION) The dimension containing the measures. You can use the placeholder “(MEASURES_DIMENSION)” also for all subsequent path instead of index or key.
/dimensions/<indexOrKey>/key Key of the specified dimension
/dimensions/<indexOrKey>/text Language-dependent name of the dimension
/dimensions/<indexOrKey>/axis “COLUMNS” | “ROWS”: Axis on which the dimension is located
/dimensions/<indexOrKey>/axis_index  Axis tuple index of the dimension, >= 0
/dimensions/<indexOrKey>/containsMeasures true|false: Does dimension contain measures?
/dimensions/<indexOrKey>/attributes List of attributes (not valid when result set has no attributes)
/dimensions/<indexOrKey>/attributes/0/key The key of the first attribute of the given dimension
/dimensions/<indexOrKey>/attributes/<indexOrKey>/text The text of the given attribute if the given dimension
/dimensions/<indexOrKey>/members Array of dimension’s members

 

Samples

The following sample shows all dimensions from the result set in a list box and uses the dimension’s text as item title and the dimension’s key as description.

List of Dimensions

<mvc:View
 xmlns:l="sap.ui.layout"
 xmlns:core="sap.ui.core"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns="sap.m">
 <List
  id="dimensions"
  items="{/dimensions}">
  <StandardListItem
   title="{text}"
   description="{key}"/>
 </List>
</mvc:View>

The following sample shows a list of measures and uses the measure’s text as item title and the measure’s key as description.

List of Measures

<mvc:View
 xmlns:l="sap.ui.layout"
 xmlns:core="sap.ui.core"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns="sap.m">
 <List
  id="dimensions"
  items="{/dimensions/(MEASURES_DIMENSION)/members}">
  <StandardListItem
   title="{text}"
   description="{key}"/>
 </List>
</mvc:View>

 

Data Paths

While the paths for master data are – except from the support to use keys – similar to the JSONModel, the access to the data area follows a different approach: A set of data cells is selected using a data selection JSON. All such data selections on the path are combined until you eventually select a single data cell. From the cell you can get value, formattedValue and more.

The data selection JSON syntax is known from many places, e.g. getData APIs and chart data selection. It has the form “‘<dim1>’: ‘<member1>’, ‘dim2’: [‘<member3>, ‘<member4>'” etc. Note that here we used single quotes inside the JSON, which is handy if the expression is placed in a string surrounded by double quotes. Also note that the braces ({ }) are omitted in selection JSONs in binding paths. Don’t confuse the braces used for SAPUI5 binding in general with the braces surrounding data selection JSONs.

If you use ‘*” as pseudo key for a member, SDKModel will create a list binding – producing a list with one entry for each member of the dimension. You can use the ‘*’ also for multiple dimensions to iterate over the combinations. The same happens with “?”, only that the totals are skipped. You know this concept from the new getDataSelections API to iterate over result sets.

 

Path
Description
/’dim1′: ‘*’ Keep all cellls – but iterate over the different members of dim1
/’dim1′: ‘m11’, ‘dim2’: ‘*’ Reduce data to all cells with dimension1 being ‘m11’ and iterates over all members of dim2
/’dim1′: ‘?’ Same as “/’dim1′: ‘*'”, but skip totals
/’dim1′: ‘*’/0 First member of the list created by “/’dim1′: ‘*'”. The result is the same as “‘dim1’: ‘m11′” (assuming that ‘m11’ is the first member of dim1 in the result set. Depending in the navigation state this expression might select one or more cells.
/’dim1′: ‘*’/0/value The float value of the first data cell selected by “‘dim1’: ‘m11′”. If “‘dim1’: ‘m11′” selected multiple cells, the value might not be the expected one. In this case it would be better to refine the selection.
/’dim1′: ‘*’/0/formattedValue The formatted string value of the first data cell selected by “‘dim1’: ‘m11′”. If “‘dim1’: ‘m11′” selected multiple cells, the value might not be the expected one. In this case it would be better to refine the selection.
/’dim1′: ‘*’/0/’dim2’: ‘m21’/value The float value of the first cell selected with “‘dim1’: ‘m11, ‘dim2’: ‘m21′”.
/’dim1′: ‘*’/0/’dim2’: ‘*’ Same as “/’dim1′: ‘m11’, ‘dim2’: ‘*'”: Reduce the data to all cells with dimension1 being ‘m11’ and iterates over all members of dim2
/’dim1′: ‘*’/0/format/LocalException-1 If “LocalException-1” is the key of a conditional format, and the cell has some level for this conditional format type assigned, you will receive a number between 0 and 9. Else it will be null.

 

Samples

Let’s assume for the next samples that you have a dimension with key “store_city” in the initial view and a measure with key “store_cost”.

 

List with data

<mvc:View
 xmlns:l="sap.ui.layout"
 xmlns:core="sap.ui.core"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns="sap.m">
 <List
  id="data"
  items="{/'store_city': '*', '(MEASURES_DIMENSION)': 'store_cost'}">
  <StandardListItem
   title="{value}"
   description="{formatedValue}"/>
 </List>
</mvc:View>

Note: If you have more dimensions in the initial view, the numbers shown in the list might not be the expected ones. In this case also specify the other dimensions, for example, using placeholder “(RESULT_MEMBER)“.

Master Data for Data Cells

If you have a path pointing to a data cell selection (for example, from a parent list binding), you can navigate to the corresponding member master data using a <dimension_name> path.

Path
Description
/’dim1′: ‘*’/0/dim1/text Returns the member text of the first member of dim1. Identical to “/dimensions/dim1/members/0/text” (assuming that member0 also appears in the result set as first member).

Samples

The following sample shows a Grid Table with two columns. Rows iterate over dimensions “store_city”. The first column shows the corresponding member text. The second column shows a data cell value.

 

Simple Table

<mvc:View
 xmlns="sap.ui.table"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns:u="sap.ui.unified"
 xmlns:c="sap.ui.core"
 xmlns:m="sap.m">
   <Table
    rows="{/store_city:'*'}"
    title="Cities"
    visibleRowCount="7">
    <columns>
     <Column width="12rem">
      <m:Label text="Store City"/>
      <template>
       <m:Text text="{store_city/text}"/>
      </template>
     </Column>
     <Column width="11rem">
      <m:Label text="Store Cost"/>
      <template>
       <m:Text text="{'(MEASURES_DIMENSION)': 'store_cost'/formattedValue}"/>
      </template>
     </Column>
    </columns>
   </Table>
</mvc:View>

 

 

Cascading Data Selections

You can make data selections smaller and smaller – nesting list components into other list components. For example, a table could have multiple lines, each line bound to a data selection that contains many cells. Some columns can select total values from such a block. Some other columns can contain complex controls, such as lists or micro charts that show multiple values of the remaining dimensions.

Samples

The following sample shows a table with three columns. We assume that the initial view contains dimensions “product_id”, “gender”, and measures on the axes.  The rows iterate over the dimension “product_id” – showing one line for each product. The fist column shows the product – with key and text. The second column shows the total sales – independent of dimension “gender”. As the selection here contains multiple cells with unspecified dimension “gender”,  we need to use a “(RESULT_MEMBER)” refinement selection. The third column shows details on dimension “gender” in a nested dropdown box. It iterates over the members of dimension “gender” and shows the details.

 

Table with Dropdown Boxes

<mvc:View
 xmlns="sap.ui.table"
 xmlns:mvc="sap.ui.core.mvc"
 xmlns:u="sap.ui.unified"
 xmlns:c="sap.ui.core"
 xmlns:m="sap.m">
   <Table
    rows="{/product_id:'*'}"
    title="Products"
    selectionMode="MultiToggle"
    visibleRowCount="7">
    <columns>
     <Column width="20rem">
      <m:Label text="{/dimensions/product_id/text}"/>
      <template>
       <m:Text text="{product_id/text} ({product_id/key})"/>
      </template>
     </Column>
     <Column width="8rem">
      <m:Label text="{/dimensions/(MEASURES_DIMENSION)/members/store_sales/text}"/>
      <template>
       <m:Text text="{'(MEASURES_DIMENSION)': 'store_sales', gender: '(RESULT_MEMBER)'/value}"/>
      </template>
     </Column>
     <Column width="10rem">
      <m:Label text="{/dimensions/(MEASURES_DIMENSION)/members/store_sales/text} Details"/>
      <template>
        <m:Select  width="100%" items="{'(MEASURES_DIMENSION)': 'store_sales', 'gender': '*'}">
          <c:Item text="{gender/text}: {value}"/>
        </m:Select>
      </template>
     </Column>
    </columns>
   </Table>
</mvc:View>

 

The result is a nice table with drop down controls in the cells:

 

Conclusion

I must admit that writing the correct binding paths is not simple. But it should still take less time than rewriting everything from scratch.

As promised, you should be able to bind a microchart from the SAPUI5 sample. The XML would be something like

<mvc:View
 xmlns="sap.suite.ui.microchart"
 xmlns:m="sap.m"
 xmlns:mvc="sap.ui.core.mvc">
 <ComparisonMicroChart scale="M" class="sapUiSmallMargin" press="press" width="30rem" minValue="-30" maxValue="70"
  colorPalette="#5cbae6, #b6d957, #fac364, #8cd3ff, #d998cb, #f2d249, #93b9c6, #ccc5a8, #52bacc, #dbdb46, #98aafb"
   data="{/'store_city': '?', '(MEASURES_DIMENSION)': 'store_sales'}">
  <data>
   <ComparisonMicroChartData title="{store_city/text}" value="{value}"/>
  </data>
 </ComparisonMicroChart>
</mvc:View>

 

and shows up in Designer like this:

 

If you need a table representation, you should spend some time looking into the Scorecard component. Internally it uses the XML View and SDKModel, but provides some help to configure all the binding logic in its Additional Properties View. This view also helps understanding the binding expression syntax.

The SDKModel can be also useful for more specific SDK components. Let’s assume that you have an SDK component with handler type “sapui5” and a data-bound property “data”. Then you can require an SDKModel, fill it with the result set JSON and hand it over to SAPUI5’s setModel API.

 define(["sap/designstudio/sdk/SDKModel"], function(SDKModel) {
    <soneSuperType>.extend("<Id>", {
        setData: function(json) {
            var model = new SDKModel(json);
            this.setModel(model);
        },
       // ...
    });
});

For more details you might also have a deeper look into the XMLView sample component.

To report this post you need to login first.

8 Comments

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

  1. Mustafa Bensan

    Hi Reiner,

    Thanks for sharing yet another very creative innovation.  So the next question/challenge is how to attach event handlers to individual controls in composite scenarios such as the Table with Checkboxes and Dropdown Boxes example above, in order to integrate with scripting?  🙂

    Regards,

    Mustafa.

     

    (0) 
    1. Mike Howles

      LOL, Mustafa.  I asked Reiner the exact same question.  🙂  I’d suspect I might have a go at adding it if enough of us keep asking that question.  🙂

      (1) 
    2. Reiner Hille-Doering Post author

      Hello Mustafa,

      the controller code could easily call SDK APIs like fireEvent, firePropertiesChanged, callZTLFunction etc. Let’s extend my first example:

      <mvc:View
       controllerName="sap.m.sample.ListSelection.List"
       xmlns:l="sap.ui.layout"
       xmlns:core="sap.ui.core"
       xmlns:mvc="sap.ui.core.mvc"
       xmlns="sap.m">
       <List
        id="dimensions"
        selectionChange="handleSelectionChange"
        mode="SingleSelect"
        items="{/dimensions/(MEASURES_DIMENSION)/members}">
        <StandardListItem
         title="{text}"
         description="{key}"/>
       </List>
      </mvc:View>

       

      sap.ui.define([
        'jquery.sap.global',
        'sap/ui/core/mvc/Controller'
       ], function(jQuery, Controller) {
       "use strict";
      
       var ListController = Controller.extend("sap.m.sample.ListSelection.List", {
      
        onInit : function (evt) {
        },
      
        handleSelectionChange: function (oEvent) {
          debugger;
          var selectedKey = oEvent.getParameter("listItem").getDescription();
          var comp = this.getView().getParent();
          comp.setSelectedItem(selectedKey);
          comp.fireDesignStudioPropertiesChangedAndEvent(["selectedItem"], "onSelect");
        }
      
       });
      
       return ListController;
      
      });

       

      This works if XMLView would have an “selectedKey” property and an “onSelect” event.

      But component metadata is static – which does not fit for a generic component like XMLView.

      The easiest – and most likely also best – approach for XMLView is do define some properties and events upfront and use them for different purposes.

      I will later add at least some “selection” property and “onSelect” event. Maybe one could also add some “stringProperty1”, “booleanProperty1” etc property and also some reusable events.

       

      There is also a more radical solution for generic components like XMLView: You could add e.g. a “doEval” ZTL function to the component evaling some JavaScript code passed from the browser in Rhino on server-side. But such a hack would be dirty and would effectively destroy all security features in the Lumira Scripting engine (like Script Validation).

      Regards,

      Reiner.

       

      (0) 
      1. Mustafa Bensan

        Hi Reiner,

        Thanks very much for the detailed feedback.  I was not entirely sure if the SDK APIs would be accessible within the controller code but your example has certainly clarified this.

        Regards,

        Mustafa.

        (0) 
      2. Mike Howles

         There is also a more radical solution for generic components like XMLView: You could add e.g. a “doEval” ZTL function to the component evaling some JavaScript code passed from the browser in Rhino on server-side.. But such a hack would be dirty and would effectively destroy all security features in the Lumira Scripting engine (like Script Validation).

        As someone familiar with the Rhino hacking, I know how to grab global scope in Lumira 2.x if anyone needs it.  🙂

         

         

         

        (0) 
  2. Mike Howles

    Reiner,

    I was able to follow through your examples with success.  This is very convenient.  As Mustafa mentioned and I had asked you as well, adding a generic event handler to expose to a BIAL event would be quite interesting prospect.  The trick would be how to make it generic enough to be usable.

    I’ve taken your code contribution and bundled it into the Lumira SCN SDK Components and folks can download it at the usable place as an installable .zip:

    https://github.com/org-scn-design-studio-community/lumiradesignercommunityext/blob/master/releases/org.scn.community.sdk.extensions.zip?raw=true

    (2) 

Leave a Reply