Technical Articles
Creating a draft enabled Sales Order Fiori App using the new ABAP Programming Model – Part 3: Defining the UI & Creating the Fiori Elements App
Defining the UI using Metadata Extensions
In the previous part we’ve defined the data model for our app. Now it’s time to define how our app should look like. We’ll do this by adding UI annotations to our consumption views using Metadata Extensions.
Within the next few subsections I’ll try to explain how the different annotations determine how the UI will look like.
UI annotations for List Report
Annotation | Usage |
@UI.typeNamePlural | Title above the list |
@UI.selectionField | Default position of the field within the selection criteria |
@UI.lineItem | Default position of the field within the table |
UI annotations for Object Page facets
Annotation | Usage |
@UI.facet | Used to group fields as desired |
@UI.facet.type | Type of facet (CollectionFacet, ReferenceFacet or ReferenceURLFacet) |
@UI.facet.label | Description (title) for facet |
@UI.facet.parentId | Reference to parent facet (for nested facets) |
Sales Order Header consumption view Metadata Extension
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders',
title: { type: #STANDARD, label: 'Sales Order' }
}
}
annotate view ZSD_C_SOHEADER
with
{
@UI.facet: [
{
label: 'Header data',
id: 'Header',
type: #COLLECTION
},
{
label: 'Document Information',
id : 'HeaderData',
parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'HeaderData'
},
{
label: 'Organizational Information',
id : 'OrgInfo',
parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'OrgInfo'
},
{
label: 'Customer Information',
id : 'CustomerInfo',
parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'CustomerInfo'
},
{
label: 'Internal Information',
id : 'InternalInfo',
parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'InternalInfo'
},
{
label: 'Items',
purpose: #STANDARD,
id: 'Items',
type: #LINEITEM_REFERENCE,
targetElement: '_items'
}
]
@UI: {
lineItem: [ { position: 10, label: 'Sales Order', importance: #HIGH } ],
selectionField: [ { position: 10 } ],
identification:[ { position: 10, label: 'Sales Order' } ],
fieldGroup: [{ qualifier: 'HeaderData', position: 10 }]
}
orderNumber;
@UI: {
lineItem: [ { position: 20, label: 'Order Type', importance: #HIGH } ],
selectionField: [ { position: 20 } ],
identification:[ { position: 20, label: 'Order Type' } ],
fieldGroup: [{ qualifier: 'HeaderData', position: 20 }]
}
orderType;
@UI: {
lineItem: [ { position: 110, label: 'Net Value', importance: #HIGH } ],
selectionField: [ { position: 150 } ],
identification:[ { position: 150, label: 'Net Value' } ],
fieldGroup: [{ qualifier: 'HeaderData', position: 30 }]
}
netValue;
@UI: {
selectionField: [ { position: 160 } ],
identification:[ { position: 160, label: 'Currency' } ]
}
currency;
@UI: {
lineItem: [ { position: 30, label: 'Sales Organization', importance: #HIGH } ],
selectionField: [ { position: 30 } ],
identification:[ { position: 30, label: 'Sales Organization' } ],
fieldGroup: [{ qualifier: 'OrgInfo', position: 10 }]
}
salesOrganization;
@UI: {
selectionField: [ { position: 40 } ],
identification:[ { position: 40, label: 'Distribution Channel' } ],
fieldGroup: [{ qualifier: 'OrgInfo', position: 20 }]
}
distributionChannel;
@UI: {
selectionField: [ { position: 50 } ],
identification:[ { position: 50, label: 'Division' } ],
fieldGroup: [{ qualifier: 'OrgInfo', position: 30 }]
}
division;
@UI: {
selectionField: [ { position: 60 } ],
identification:[ { position: 60, label: 'Sales Office' } ],
fieldGroup: [{ qualifier: 'OrgInfo', position: 40 }]
}
salesOffice;
@UI: {
selectionField: [ { position: 70 } ],
identification:[ { position: 70, label: 'Sales Group' } ],
fieldGroup: [{ qualifier: 'OrgInfo', position: 50 }]
}
salesGroup;
@UI: {
lineItem: [ { position: 80, label: 'Sold-to', importance: #HIGH } ],
selectionField: [ { position: 80 } ],
identification:[ { position: 80, label: 'Sold-to' } ],
fieldGroup: [{ qualifier: 'CustomerInfo', position: 10 }]
}
soldTo;
@UI: {
lineItem: [ { position: 90, label: 'Ship-to', importance: #HIGH } ],
selectionField: [ { position: 90 } ],
identification:[ { position: 90, label: 'Ship-to' } ],
fieldGroup: [{ qualifier: 'CustomerInfo', position: 20 }]
}
shipTo;
@UI: {
lineItem: [ { position: 100, label: 'Customer Reference', importance: #LOW } ],
selectionField: [ { position: 100 } ],
identification:[ { position: 100, label: 'Customer Reference' } ],
fieldGroup: [{ qualifier: 'CustomerInfo', position: 30 }]
}
customerReference;
@UI: {
lineItem: [ { position: 130, label: 'Created By', importance: #LOW } ],
selectionField: [ { position: 110 } ],
identification:[ { position: 110, label: 'Created By' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 10 }]
}
createdBy;
@UI: {
lineItem: [ { position: 140, label: 'Created On', importance: #LOW } ],
selectionField: [ { position: 120 } ],
identification:[ { position: 120, label: 'Created On' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 20 }]
}
createdOn;
@UI: {
selectionField: [ { position: 130 } ],
identification:[ { position: 130, label: 'Created At' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 30 }]
}
createdAt;
@UI: {
selectionField: [ { position: 140 } ],
identification:[ { position: 140, label: 'Changed On' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 40 }]
}
changedOn;
}
Sales Order Item consumption view Metadata Extension
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Sales Order Item',
typeNamePlural: 'Sales Order Items',
title: { type: #STANDARD, label: 'Sales Order Item' }
}
}
annotate view ZSD_C_SOITEM
with
{
@UI.facet: [
{
label: 'Item Information',
id : 'ItemData',
//parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'ItemData'
},
{
label: 'Internal Information',
id : 'InternalInfo',
//parentId : 'Header',
type : #FIELDGROUP_REFERENCE,
targetQualifier : 'InternalInfo'
}
]
@UI: {
hidden: true,
lineItem: [ { position: 10, label: 'Sales Order', importance: #HIGH } ],
selectionField: [ { position: 10 } ],
identification:[ { position: 10, label: 'Sales Order' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 10 }]
}
orderNumber;
@UI: {
lineItem: [ { position: 20, label: 'Item', importance: #HIGH } ],
selectionField: [ { position: 20 } ],
identification:[ { position: 20, label: 'Item' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 20 }]
}
orderItem;
@UI: {
lineItem: [ { position: 30, label: 'Material', importance: #HIGH } ],
selectionField: [ { position: 30 } ],
identification:[ { position: 30, label: 'Material' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 30 }]
}
material;
@UI: {
lineItem: [ { position: 40, label: 'Description', importance: #HIGH } ],
selectionField: [ { position: 40 } ],
identification:[ { position: 40, label: 'Description' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 40 }]
}
itemDescription;
@UI: {
lineItem: [ { position: 50, label: 'Quantity', importance: #HIGH } ],
selectionField: [ { position: 50 } ],
identification:[ { position: 50, label: 'Quantity' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 50 }]
}
orderQuantity;
@UI: {
selectionField: [ { position: 60 } ],
identification:[ { position: 60, label: 'Sales Unit' } ]
}
salesUnit;
@UI: {
lineItem: [ { position: 70, label: 'Net Value', importance: #HIGH } ],
selectionField: [ { position: 70 } ],
identification:[ { position: 70, label: 'Net Value' } ],
fieldGroup: [{ qualifier: 'ItemData', position: 70 }]
}
netValue;
@UI: {
selectionField: [ { position: 80 } ],
identification:[ { position: 80, label: 'Currency' } ]
}
currency;
@UI: {
lineItem: [ { position: 90, label: 'Created By', importance: #LOW } ],
selectionField: [ { position: 90 } ],
identification:[ { position: 90, label: 'Created By' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 10 }]
}
createdBy;
@UI: {
lineItem: [ { position: 100, label: 'Created On', importance: #LOW } ],
selectionField: [ { position: 100 } ],
identification:[ { position: 100, label: 'Created On' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 20 }]
}
createdOn;
@UI: {
lineItem: [ { position: 110, label: 'Created At', importance: #LOW } ],
selectionField: [ { position: 110 } ],
identification:[ { position: 110, label: 'Created At' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 30 }]
}
createdAt;
@UI: {
lineItem: [ { position: 120, label: 'Changed On', importance: #LOW } ],
selectionField: [ { position: 120 } ],
identification:[ { position: 120, label: 'Changed On' } ],
fieldGroup: [{ qualifier: 'InternalInfo', position: 40 }]
}
changedOn;
}
Exposing the Business Object consumption CDS view as oData service
Open transaction /IWFND/MAINT_SERVICE and add the generated service to the list of activated services. This can either be co-deployed or routing-based, depending on your system setup.
Generating the Fiori Elements App
Open up SAP Web IDE and create a new project from template. Choose for “List Report Application” and click Next.
Enter following details (you can choose your own):
- Project Name: ZSD_SO_DEMO_V1
- Title: Manage Sales Orders
- Namespace: be.thevaluechain
- Description: Manage Sales Orders
Click “Next”
In the next screen choose your desired backend system from the service catalog and select your previously activated oData service. Click “Next“.
Select all remote annotations and click “Next“.
Enter following details:
- OData Collection: ZSD_C_SOHEADER
- OData Navigation: to_items
Click “Finish“.
Select the newly created project and click the “play” button in the toolbar.
Select “flpSandbox.html” and click “OK“.
Open the app by clicking the generated tile.
Result:
Our app now has basic functionality:
- Search
- Result list report
- Search helps
- Detail screens (display)
In the next parts we’ll implement the required logic to enable:
- Changing existing Sales Orders
- Deleting existing Sales Orders
- Creating new Sales Orders
- Locking Sales Orders when a Draft instance is created
Hello Geert-Jan Klaps,
Thanks for this blog post. I was searching for such materials. Actually, I'm new to ABAP programming model and I'm following this tutorial
https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/201809.001/en-US/a1243bff462b4ee3a03e2bb6fc30e015.html
I have a question and hope you can assist me:
I defined annotations for UI.facet exactly as you did, but I didn't get them displayed on the Object Page.
Actually, I have defined the annotations for the list report view (home view) and the object view (detail view) in the same CDS view. is that right? or I have to split the code (CDS view for each of the home and detail view) ?
Here is part of the code:
........
@UI.headerInfo: {
typeName: 'Sales Order Item',
typeNamePlural: 'Sales Orders Items',
title: {value: 'My Sales Order List'},
description.value: 'List Report Sales Orders'
}
@Search.searchable: true
define view ZDEMO_CDS_SalesOrderItem_M as select from SEPM_I_SalesOrderItem_E as Item {
@UI.selectionField.position: 10
@UI.lineItem: {importance: #HIGH,label: 'Sales Order', position: 10}
@UI.facet: [
{
label: 'General Information',
id:'GeneralInformation',
//isSummary: true,
type: #COLLECTION,
position: 10
},
{
label: 'Customer Info',
id: 'CustomerInfo',
parentId: 'GeneralInformation',
type: #FIELDGROUP_REFERENCE,
position: 20,
targetQualifier: 'Company'
}
]
key Item.SalesOrder as SalesOrderID,
//@UI.hidden: true
key Item.SalesOrderItem as ItemPosition,
@UI.fieldGroup: [{
qualifier: 'Company',
position: 10
}]
@UI.selectionField.position: 20
@Search: {defaultSearchElement: true, fuzzinessThreshold: 0.7} // The search will work even if you provide part of the company name
//@Search.defaultSearchElement: true // You have to provide the complete company name, then the search will work(When choosing the default filter)
@UI.lineItem.position: 20
Item._SalesOrder._Customer.CompanyName as CompanyName,
.......
Hi , Can you Tell me how will i get vertical scrollbars for sales report in this screen.
Thanks for the detailed annotation overview.