
Script: Recycling-Heroes - Virtual elements for UI Features (Contact) [013]
How can you use virtual fields to provide additional information to the UI and even influence existing fields? In this episode, we'll explore various aspects of virtual fields.
Table of contents
Introduction
Last time, we adapted the UI of our application and replaced the technical identifiers with text. We also implemented value helps for the most important fields to make working with the app more convenient. In this episode, we'll look at virtual fields in the Consumption View and how we can use them to display additional information and hide unnecessary information. We'll create a constant interface and then focus on working with the fields.
Constant Interface
In the first step, we'll create a new interface in the SHARE package. Here, we want to assign some constants to the "ContactType" so that we can work with the constants later and don't have to resort to hard-coded values. We'll create the constants as a structure in the interface and give them descriptive names. This allows us to access the information later in the code using a descriptive name.
Virtual Fields
If we want to display additional information in our UI that may not be stored in the database but may be derived from this information, we can use virtual elements. To do this, we define a new virtual element at the consumption level and give it a name and a type. We create four elements: an icon that will later look different for each type, and three fields with which we want to hide certain information in the UI. Telephone, email, and birthday are fields that we don't need for every type of contact. In order for our ABAP exit to be called for the fields, we must define it for the field. We use "CalculatedBy" to specify the ABAP class we want to call.
To get rid of the error, we need to create the class in the system. We can create a new class using the context menu, giving it a descriptive name and a description. Then we search for the interface for the exit and find it with IF_SADL_EXIT. Once we've filled everything in, we assign a transport and create the class in the system. Let's format the class accordingly and activate it.
After checking the Core Data Service, all errors should now be gone, and we can activate the view to continue implementing the logic.
Implementation
The class has two methods: we will use CALCULATE to populate the virtual fields later, and we use GET_CALCULATION_INFO to specify which fields and information we need for the calculation.
Let's first look at the method signature; this provides us with information about the requested fields and the entity that is currently being loaded. This allows us to query additional fields that we will need later. So, in the first step, we perform a check to ensure that the correct entity is being requested by the system. If it is a different entity, the logic should be exited. We then pass the "ContactType" to the requested fields, as we need this for the check and derivation.
Then we can implement the second method. First, we need a typed table, since we are receiving a table of type ANY TABLE, but we want to access the specific fields later. To do this, we map the incoming data to our new typed table. Once we're finished with our logic, we pass the data back to the return structure via mapping.
Now we can implement the actual mapping logic. To do this, we loop over the table and work with a reference, since we want to change the data shortly. We'll start with the icon for the "ContactType," using the new SWITCH and also needing the constants from the interface. Using the SAP Icons, we now select three suitable icons that we want to see later in the UI. Next, we hide the fields we no longer want to see in the UI, again depending on the type.
UI Annotations
To display an icon, for example, we need the annotation "UI.headerInfo.typeImageUrl" in the header. We include our new field there. Using the hash symbol and the field in parentheses, we pass the field's contents to the annotation. If we then go back to our app and update the UI, we should now find an image in the upper area of the object page. We will now use a different image for the customer than for an employee. This makes it easier for the enduser to classify the entry later when creating and editing.
In the next step, we want to deactivate the fields Birthday, Phone, and Email. To do this, we use the "hidden" attribute in the respective annotation and set the respective field as a reference to hide the content. If we then reload the UI and look at the details, we won't notice any changes. So what's the problem with using it? The annotation is defined as a Boolean and therefore requires the Boolean type to function. This has been an issue in ABAP development since the beginning, as there is no real Boolean type. So we have to go back to the Consumption View and replace the data type with ABAP_BOOLEAN. This data type is actually recommended in all cases, since, unlike ABAP_BOOL, it is a data element and can therefore be used in more places. Once the Core Data Service is activated, we exchange the values in our exit and reload the UI.
If we now look at the customer and go to the details page, the birthday is now hidden on the UI. The annotation takes effect and hides the elements. In the next step, we create an address where more elements are hidden. To do this, we create a new data record, define the Contact Type attribute as Address, and save the entry. After saving, the data is reloaded, and we see that the three fields are now hidden. However, we now have the problem that our facet is now displayed empty.
Therefore, we go to our Consumption View and define a new virtual element so that we can also hide the facet in the UI. We also fill in the field in our ABAP exit if we have the address type. Finally, we go to the metadata extension and add the "hidden" attribute to the Digital Contact facet. If we go back to the UI and reload the data, the facet on the detail page should now also be hidden, giving us a clean view.
Requested Elements
To conclude the session, let's take a look at the requested elements in the exit. To do this, we deactivate the requested element in the GET_CALCULATION_INFO method and test the behavior in the UI. To do this, we deactivate some fields in the list report so that we see our icon as a column, but not the contact type. If we now execute the selection, the field remains empty. In Fiori, only those fields are requested from the backend that the user also sees in the UI. This saves database performance, transfer capacity, and keeps loading speeds low. Ultimately, however, this means that our virtual field doesn't receive the information we need for derivation, and thus the display remains empty.
We request this element via the method and receive it in the method as loaded information. Basically, we also have the option of reading information from the database here to obtain the missing information. However, with the standard logic, we can achieve as few calls as necessary.
Hiding Fields
Let's call the UI again and look at the list of fields. Currently, we see the virtual fields in the selection list. These normally only provide little added value for the user, as they only have a controlling character. To prevent the fields from being available for selection, we can hide them from the user. To do this, we add the fields to the metadata extension and hide them using UI.hidden. If we go back to the app and refresh the UI, the fields will now disappear from the selection list of possible fields. We also use the fields to control the properties of the UI.
Summary
In this episode, we looked at how we make virtual fields available at runtime and derive the correct content. We can use them to display additional fields in the UI or restrict the visibility of other fields. Finally, we clarified what we need the fields for and what influence visibility has on them. The UI is now complete, and we can look at the creation of instances in the next episode.
Thanks for watching, enjoy! while learning and see you next time.
YouTube
Video