Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member189544
Contributor
2,165
In this blog post series I want to show, how to add additional functionality to an SAP Lumira Application. I will show how a "Composite" component can be used to add additional functionality to Lumira applications, where in Design Studio only an SDK component could do the job.

Introduction


The basics and general scripting to do this, have already been explained in some other blog posts  (thanks to reiner.hille-doering, michael.jung2 and others), but I thought it would be worth to show the way step-by-step to combine it in a real-life example I recently created for a Proof of Concept.

The goal was to have a visualization component, that is capable to show images in a dynamic way and ineract with them. That means the images are driven by a data source, they can be filtered and selected, and the visual appearance is dynamic and configurable.

In this Part 1 I will start developing the component from scratch and bring it into a first testable version.

In Part 2 I will continue, make the component more flexible and add functionality to it, so one can finally use it in various scenarios.

Preparation


To start developing every component we need some test-data. I collected some sample images of Disney cartoon characters and put them on a web-share on my development systems ("sapdemovm") tomcat web application server:



Then I created an Excel workbook containing some columns with the image data, like an ID, the name, filename and the URL to access the image in a browser:



Now I started Lumira Discovery and created the Offline Data Source from the Excel sheet:



and saved the document with data for later use as offline data source in Lumira Designer.

Creation of the composite


Now I opened this document in Lumira Designer:



Then I created the composite called “DYNAMIC_IMAGES”:



Now I opened the composite. Here I added the following Technical Components.

 

Components


A “Components” Technical Component



This is used to be able to dynamically create the blocks and images based on the data source in the scripting.

 

A “Global Scripts Object” Technical component:



This will hold the scripts we will create later on.

 

Layout


On the Layout we will use two "Adaptive Layout Container" components, a Block template and an Image template component:



The final Layout looks like this:



 

We will use the "ADAPTIVE_LAYOUT_MAIN" component as our container, that will hold the blocks containing the Images at runtime, which will be created dynamically via Scripting. The _TEMPLATE components should be hidden, since they are just used as templates, to set general properties for the images and blocks, like Colspans for the blocks and CSS Class for the images:



The properties will be copied to the new instances of these templates via Scripting later on.

 

Interface Properties


Create a Property “inDataSource” of type DataSourceAlias:



This will receive the data source from the application, that uses the component and receive the image data from it.

 

Global Variables


Create a global array variable (gBlocks) to store the Block objects:



It will be used later on in Scripting to store the dynamically created block objects and remove them again, before creating new ones.

 

Global Scripts


Create a Global Scripts Object:



And in there create two script function:

 

One, the deleteImages() function, to delete the existing Images:



Code
if (gBlocks!=undefined && gBlocks.length>0) {
// Delete each block:
gBlocks.forEach(function(block, index) {
COMPONENTS.deleteComponent(block);
});
// Finally empty the blocks array:
gBlocks=[BLOCK_TEMPLATE];
gBlocks.pop();
}

 

And the other one, the createImages() function, to create the new images:



Code
// set the vars to the template objects for correct type
var block = BLOCK_TEMPLATE;
var image = IMAGE_TEMPLATE;
// check, if there were blocks already created, which need to be removed:
GLOBAL_SCRIPTS_DYNAMIC_IMAGES.deleteImages();
// create the dataselections (for the moment hardcoded to actual datasource dimension)
var selections = inDataSource.getDataSelections({
"DS:2,DIM:id_11": "?"
});
// Loop through the dataset and get the image URL:
selections.forEach(function(sel, index) {
// Get the dimension member for each selection:
var m = inDataSource.getMember("DS:2,DIM:id_11", sel);
// The Url seems always to be in the text, even if only key is available:
var imageUrl = m.text;
// Create a new block inside ADAPTIVE_LAYOUT_MAIN:
block = COMPONENTS.createComponent(ComponentType.Block,ADAPTIVE_LAYOUT_MAIN);
// copy properties from an empty template block
COMPONENTS.copyProperties(BLOCK_TEMPLATE, block);
// Create a new image inside block:
image = COMPONENTS.createComponent(ComponentType.Image, block);
// copy properties from an empty template image:
COMPONENTS.copyProperties(IMAGE_TEMPLATE, image);
// set the additional properties:
image.setImage(imageUrl);
image.setVisible(true);
// add the block to the gBlocks global variable for later removal:
gBlocks.push(block);
});

 

Events


Use the createImages() function in the “On Initialization”- and “On Property Change”-events of the composite to the trigger the creation of the images when the composite is created or whenever properties are updated:



Code
// Initialize gBlocks array:
gBlocks=[BLOCK_TEMPLATE];
gBlocks.pop();
if (inDataSource.isInitialized()) {
GLOBAL_SCRIPTS_DYNAMIC_IMAGES.createImages();
}

(The initialization of the gBlocks global variable needs to be done only once!)

 

Interface Function


Finally create an update Interface Function:



Code
GLOBAL_SCRIPTS_DYNAMIC_IMAGES.createImages();

The function simply triggers the createImages() Global Script Function and acts as interface to trigger updates from outside the composite via Scripting.

 

Create test application


Now that our composite is prepared, create a new Application “DYNAMIC_IMAGES_APP” in the Document to test the result:



 

Add the (offline) data source to this application:



 

Edit the initial view of the data source to include all available data:



 

Add the Composite:



 

Bind the data source “DS_1” to the Composite’s Data Source Data Binding Property:



 

Add a header text, a crosstab representation of the data source and a dimension filter component.
Finally add the update() interface function of the composite to the “On Apply”-event of the Dimension Filter:



We are now finished and ready for a first test run.

Run


Now run the application:



Looks nice, doesn’t it?

When you filter the data source using the dimension filter, the Dynamic Images Composite is updated accordingly!

 

Outlook


In the next blog post of this blog post series, I will show how to make the component even more flexible and add selection functionality to it, so we can finally use it in various scenarios and with different data sources.

You can find Part 2 of this blog post series here:

Building useful components with Lumira composites – Dynamic Images Part 2

Have fun!
3 Comments