RAP - UI Annotations
Today we look at how we can enrich the Fiori Elements with standard elements in order to get a finished app straight away.
Table of contents
We will write again about UI annotations in a separate large article about the diverse elements and possibilities. In this first part, we mainly want to enrich the example from last week with standard elements so that the finished app can be seen as soon as the application is loaded.
Annotation
We already wrote about annotations in CDS views in the Core Data Services basics blog. With these additional properties, you can equip fields with additional functions and behavior. Likewise, we want to get additional behavior and a UI for our core data service. To do this, we can equip the fields with annotations from the UI family.
Selection
If certain fields are to be filtered from the outset, we can define this directly using the "UI.selectionField" annotation. The fields are displayed as search fields, but can subsequently be expanded or hidden using the standard functionality.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
name as PartnerName,
street as Street,
city as City,
country as Country,
payment_currency as PaymentCurrency
}
The number of the position can be freely selected, but may only be assigned once within the view. It determines the order in which items are displayed, so items are initially numbered in increments of 10 to allow for items to be inserted in between. The result now looks like this:
List
Next, we would like to render certain items in the list that will be printed after loading. We achieve this with the annotation "UI.lineItem" which works in a similar way to the selection. We can specify a specific order in which the items will be inserted into the list. With the "importance" attribute, however, we can also determine what information is displayed if not all elements fit on the screen.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
country as Country,
payment_currency as PaymentCurrency
}
The Country column is visible in the list because the item is shown with a very high priority. If all elements have the same priority, then they are built up one after the other until no more space is available.
Texts
So far, the columns still lack proper headings. You can achieve this by using proper data elements from which the texts can be derived. In our case there are only built-in data types, but we want to display proper texts in the UI. For this, the text can be adjusted with "EndUserText", there are also the elements "label" for the text of the column and "quickinfo", this text is displayed when you move the mouse over the heading.
The list now looks much tidier and offers the user explanations when interpreting the output list.
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
country as Country,
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
payment_currency as PaymentCurrency
}
Detail page
If you currently click on a data record in the list, you will automatically be taken to the application's detail screen, but this is still empty. We currently have no information stored for this image. As above, we store a new annotation "UI.identification" in the field. However, this still does not show anything on the detail screen, but we have to assign the fields to a type of group.
To do this, we define a facet at the beginning of the view. This object divides the image into different areas and so we can assign elements or fields. Facets have an ID and must be unique on the image, otherwise no elements will appear on the image.
One group
When designing the image, we now have a free choice of how the image should be designed. Let's start with a simple variant and pack everything under one category.
@UI.facet : [
{
id : 'FacetPartnerFields',
label : 'Partner Informations',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
}
]
Inside the facet we define an area of type "IDENTIFICATION_REFERENCE" under which all objects fall, we set a corresponding ID and a label to be displayed. The "targetQualifier" is used to be able to assign the corresponding fields to the element. This is done via the corresponding annotation:
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
In the end, the detail page looks like this:
Two tabs
The next variant creates two "tabs" on the image. The tabs can also be used to navigate later on the detail screen if there are many fields in order to get to the appropriate section. We add a second entry to the facet with a new ID and new assignment for the fields:
@UI.facet : [
{
id : 'FacetPartnerFields',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
As in the last section, the fields can now be assigned to the corresponding facet and now receive the following detail page (the tabs at the top are clearly visible):
Collection
The third and final form of the page is the "Collection", a summary of various references under one category. To do this, we define another facet with the corresponding type and also assign a label, since this is displayed as a new tab. The other two facets are now given a "parentId" to ensure assignment to the collection.
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
The corresponding fields can be assigned again and you will receive the final image. The two facets are combined in one area and given a title, the objects are grouped into areas.
Here is the entire Core Data Service again with all the annotations for the last example. As you can see, the amount of coding has increased significantly.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP interface for Partner'
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@UI.identification: [{ position: 10, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
key partner as PartnerNumber,
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
name as PartnerName,
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@UI.identification: [{ position: 30, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
street as Street,
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@UI.identification: [{ position: 40, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
city as City,
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@UI.identification: [{ position: 50, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
country as Country,
@UI.identification: [{ position: 60, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
payment_currency as PaymentCurrency
}
Metadata Extension
The UI annotations can grow over time and cause confusion in the actual view. For this we can create a metadata extension to transfer all necessary UI annotations into a separate object. For this you have to create an annotation in the view to be extended:
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'RAP interface for Partner'
@Metadata.allowExtensions: true
define root view entity ZBS_I_RAPPartner
as select from zbs_dmo_partner
{
key partner as PartnerNumber,
name as PartnerName,
street as Street,
city as City,
country as Country,
payment_currency as PaymentCurrency
}
"@Metadata.allowExtensions" announces that the view can be extended with extensions. You can then right-click on the CDS view in the Project Explorer to create the "Metadata Extension" and move the annotations to the new file.
After moving, the extension looks like this, but you should note that in contrast to the interface view, some things have changed. The fields are now terminated with a semicolon and only the field name is required (without keywords like "key").
@Metadata.layer: #CUSTOMER
annotate view ZBS_I_RAPPartner with
{
@UI.facet : [
{
id : 'FacetCollection',
type : #COLLECTION,
label : 'Partner Collection'
},
{
id : 'FacetPartnerFields',
parentId : 'FacetCollection',
label : 'Information',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_INFO'
},
{
id : 'FacetPartnerAddress',
parentId : 'FacetCollection',
label : 'Address',
type : #IDENTIFICATION_REFERENCE,
targetQualifier: 'PARTNER_ADDRESS'
}
]
@UI.selectionField : [ { position: 10 } ]
@UI.lineItem: [{ position: 20, importance: #MEDIUM }]
@UI.identification: [{ position: 10, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Partner'
@EndUserText.quickInfo: 'Identifier of the partner'
PartnerNumber;
@UI.selectionField : [ { position: 20 } ]
@UI.lineItem: [{ position: 10, importance: #MEDIUM }]
@UI.identification: [{ position: 20, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'Name'
@EndUserText.quickInfo: 'Partner name'
PartnerName;
@UI.lineItem: [{ position: 40, importance: #MEDIUM }]
@UI.identification: [{ position: 30, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Street'
@EndUserText.quickInfo: 'Street and Housenumber'
Street;
@UI.lineItem: [{ position: 30, importance: #MEDIUM }]
@UI.identification: [{ position: 40, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'City'
@EndUserText.quickInfo: 'City of the partner'
City;
@UI.lineItem: [{ position: 50, importance: #HIGH }]
@UI.identification: [{ position: 50, qualifier: 'PARTNER_ADDRESS' }]
@EndUserText.label: 'Ctry'
@EndUserText.quickInfo: 'Country'
Country;
@UI.identification: [{ position: 60, qualifier: 'PARTNER_INFO' }]
@EndUserText.label: 'PayCurr'
@EndUserText.quickInfo: 'Payment currency'
PaymentCurrency;
}
Conclusion
In this article we have enriched our Fiori Elements with fields and sections, creating a real application to start working with right away. We went into the various design options and how you can get the detailed image more effectively. You can find the current source code again on GitHub.