Effective Modeling in Visual Composer
Here are several ways to make the modeling process more efficient, or the application run better. Whether you are new to Visual Composer or an expert, I hope you find some topics useful for you.
- 1. Service-First Approach
- 2. Data Services are not Ready? Don’t Wait Up. Mockup
- 3. UI Overload: Show Subsets of What’s in the Memory
- 4. Memory Overload: Get Subsets of What’s in the Database
- 5. Understand the Scaling Options and Get a Better Layout
- 6. Extend the Solution using Additional Technologies
- 7. Remember the Meaning of Different Link Types
- 8. Distinguish between Data Share and Data Store
- 9. Don’t Struggle Against Cardinality. Let It Work for You
- 10. Editing of Calculated Values
- 11. Cache Data When Relevant
Not only do we save a lot of manual work this way. When we define the fields structure on our own we might miss one simple thing, like Cardinality being Record (1..1) and not Recordset (0..n), unlike the service port, and create a nasty bug for ourselves.
What if the data services are not ready to consume yet? In that case it is best to use a Mockup Data Service, and continue the modeling. later you will be able to replace it with the real one. Read the next item for more details.
2. Data Services are not Ready? Don’t Wait Up. Mockup
Visual composer encourages us to consume the data services first, then model around them. But what if those are not yet ready? To overcome this development block we could use a Service Component, to imitate the “real” data service.
ℹ A Service Component is a Visual Composer model, that allows to define and reuse non-UI functionality.
- From the Compose Panel add a Service Component into the model.
- Drill into this new model and add the input and output ports and their fields.
- Back in the main model activate the Redefine Ports dialog to select from the updated ports.
Now we could model around the new mockup service. It’s even possible to test the application run-time to some extent, by using Static Data elements inside and writing some “hard-coded” data.
Once the real service is ready, we could drag it from the Search Panel over the Service Component. The Dialog that opens notifies us of any conflicts in the ports structure.
3. UI Overload: Show Subsets of What’s in the Memory
There are scenarios that include a lot of data. The trivial scenario being a table with many rows and columns. We don’t want to suffer a performance hit. In addition, scrolling through a very long list is bad usability. The following example shows the classing “paging in table” scenario.
- First, we get all the records to memory.
- On each press of Next, we show the next subset of records.
4. Memory Overload: Get Subsets of What’s in the Database
In some cases we might have an application designed to show subsets of the data, for example using paging. In the above solution, we first get all the data for paging into the memory. If the complete data is too much, we might want to get to the application only a subsets data in the first place. In this case the tradeoff is paying in more calls to the backend: each time want to get the next subset, we call the database to do so.
5. Understand the Scaling Options and Get a Better Layout
Building a good UI is not a trivial task. There are several options relevant to the layout, one of them is how elements are to be scaled. For example: In the following model the Window contains two Form elements. The Window’s Content Scale is set to “Auto-fit to height”, so it must fit the height of nested elements:
Changing the Window’s height will stretch the Form View elements accordingly. Changing a Form View’s height will have the same effect on the containing Window. On the other hand, Changing the width of elements will have no such effect, as we didn’t choose the scaling to “fit to width”. This is why a gap appears to the right of the Form View elements, as I played around with the widths.
In much the same way we define controls in a Form View to “fit” to the Form’s width, or have their own width. In Form1 the control Txt1 will stretch with the Form, while in Form2 the control Num1 might have its own width.
Here is an example where we need some scaling to be “fixed” to a specific height:
6. Extend the Solution using Additional Technologies
In the most common case we use data services, written in another technology, to get backend data or change it. However, we may need to further manipulate the data only for the application, in a way modeling can’t perform. For that end we could involve code and consume it, e.g. as a Web Service.
There is a built in option in Visual Composer@NWDS to make it easier: We start by creating a Service Component as a mockup to the Web Service. Then we ask the environment to generate the Web Service skeleton for us. Basically we write our Java code in one method of one file to define the behavior. finally we consume the Web Service in our model.
Here is an example: Paging records in the UI – Coding our own Web Service to get Row Numbers
The complete documentation: Using Web Services in Visual Composer – Modeling Composite Views with Visual Composer – SAP Library
Another aspect of extending our solutions is the UI. Some elements may not be available out of the box. In the cases we can’t model this UI, we may develop it ourselves and consume it in our models. For the WebDynpro runtime there is an option to build such a component. here is an example: Web Dynpro Tree Black Box
ℹ There may be an equivalent option later on, dedicated for the SAPUI5 runtime modeling.
7. Remember the Meaning of Different Link Types
It is true that we don’t directly choose the links in our model. However, we control them indirectly, by the elements we connect. Consider this scenario: We have a list of records showing in one element, e.g. Chart View, and we want to enable editing of one record in another element, e.g. Grid View. If we connect the elements directly we get a Data Bind link:
Selecting or editing the data in one element affect the other, as are they are bound to the same data. This reflects in the application as follows:
We might want changes in the Grid View not to influence the Chart View immediately, for example: We need to perform validation in the backend first. In that case, the elements should not be bound. One way to go is to have separate connections for them from the service output port. Then we model the activation of a second service for the update. Following this last step, we reload the employees data. Only then the Chart View is updated.
Here is a summary of the link types that are relevant to passing data, in regards to the source and target:
|Link Type||Data Structure is the Same||Data is Shared|
(Additional fields could be added to the target element in some cases)
(Additional fields could be added to the target element in some cases)
(the Map Data dialog is used to assign values to the target fields)
ℹ There are more elements that cause data itself or the data structure not to be shared, like Operators.
8. Distinguish between Data Share and Data Store
Data Share and Data Store has a common attribute: they could both be used to keep field values we could use elsewhere in the model. When we use them for this purpose, how do we know which one is best to use?
Here is a comparison:
|Data Store||Data Share|
|Allows clustered data||No.||Yes.|
|Maximum elements per application||
Multiple elements in the model all represent the same one.
|As many as added to the model.|
|Creation / recreation||Once.||On each Data Mapping link|
Following Data Map with no Field Assign, what is the field value (TXT2)?
|Unchanged||Value is erased|
The full information:
9. Don’t Struggle Against Cardinality. Let It Work for You
It is important to be aware of different cardinality (multiplicity) types. For example: The user needs to edit rows in a table, then pass them to a data service, while at least one row should be present. The default Record Set type (0..n), allow any number of records, including zero. In this case we need to somehow validate the user input, or in the first place prevent deleting a row if it’s the only one.
An easier solution is to use the 1..n cardinality. Any button containing a DELETE Actions becomes disabled when only one record is left.
In quite the same way we could choose the 1..1 or the 0..1 cardinality, e.g. for a data service input: If it must get exactly one record, it’s best for the port cardinality to be 1..1. If it’s not so, for but for example 0..1, we might have an extra effort in our modeling to make it behave as though it were 1..1.
Here’s an 0..1 example where we must add a record to the Data Share in order to pass data to the service:
10. Editing of Calculated Values
It is common case to present in the UI a calculated value, i.e. value not coming form our source of data, but based on it. Moreover, we may need to allow editing of the value, then pass it back. For example: An external application is using the Visual Composer application. we get a Date value from it in a String format. We need to present it, allow editing, then pass it back as a String.
If we add a Date Picker control and set its value accordingly, it automatically gets Read Only in the application. This happens since the control is not wired to an actual field.
We need to have a dedicated Date field presented in the table. There are two options:
Option 2: Add a Data Share with a Date field, and set the calculation in the Data Map link. Connect the Grid View after the Data Share.
Eventually, in case we need to convert the edited value back to String (true for both options):
11. Cache Data When Relevant
There are several questions we might want to ask regarding performance:
- Do we call the backend multiple times to show the exact same selection?
- Do we render the same data on some UI several times?
In some of these scenarios we could improve the application using cache. The following two documents show how to build a cached selection:
In other cases we might show the same selection format, with different data, for example: a list of restaurants, each time of a specific city. In this case we might still use cache:
- The memory of the selection part gets all the records – done once!
- A filter is applied to allow the relevant subset to pass and show in a table