Skip to Content
Technical Articles

Smart Templates

Hello guys!

 

Today I want to share my findings about Smart Template, CDS views and Odata.

I had a project where we created App based on Smart Template. There were a lot of questions without answers. And now I want to share my ideas, notes and findings.

As you know SAP provides flexible approach to create a web app – Smart Templates. What does it mean?! It means you can create a web app without front-end coding or with very basic front-end coding. The main idea is: you provide all necessary information from the back-end using special instructions – annotations. Front-end will automatically parse this instructions and draw the UI.

I hope, this blog will be useful for beginners who just started with Smart Templates. But may be professionals also find something interesting here.

 

The task is: create a Web Application with information from SFLIGHT, SPFLI and SAPLANE tables. On the first page we will show info from SFLIGHT table, when user clicks on the line he will be navigated to the second page, where we will display info from SPFLI and SAPLANE.

NOTE: you can choose any set of tables, or replace my tables, or add another tables.

Prerequsites

You need to set-up connections to the SAP Cloud Platform. You can use my instruction:

https://blogs.sap.com/2018/11/12/how-to-setup-cloud-connection/

Create set of CDS views in the back-end.

I hope, you know how to create an ABAP CDS. You need to create 3 CDS, one CDS for each table.

CDS for SFLIGHT:

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight 
{
   key carrid,
   key connid,
   key fldate,
   price,
   currency,
   planetype
}

CDS for SPFLI:

@AbapCatalog.sqlViewName: 'ZYHB_V_SPFLI'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS view for SPFLI table'
define view ZYHB_P_SPFLI
  as select from spfli
{
  key carrid,
  key connid,
      countryfr,
      cityfrom,
      airpfrom,
      countryto,
      cityto,
      airpto
}

CDS for SAPLANE:

@AbapCatalog.sqlViewName: 'ZYHB_V_SAPLANE'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS view for SAPLANE table'
define view ZYHB_P_SAPLANE
  as select from saplane
{
  key planetype,
      seatsmax,
      weight,
      wei_unit
}

These are our core objects. Now we are going to combine them together via association and add some annotation for SmartTemplate.

Combine CDS views in the Model

We need to add associations from SFLIGHT to the SPFLI and SAPLANE.

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS view fr SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid                                       
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   key carrid,
   key connid,
   key fldate,
   price,
   currency,
   planetype,
   
   _spfl,
   _plane
}

Why we use association?! We can use join!

I try to explain: when we use JOIN – data will be selected from both tables. Every time when you will select data – data will be selected from two tables. Even if you will not use data from second table, it will be selected.

When we use association – data will be selected only from requested set. It means, that association helps us to save network resources.

Example: On first page we display data from SFLIGHT table and  we don’t need data from SPFLI. Association concept allows select data only from SFLIGHT on first page, and when we navigate to the second page – only in that moment data from SPFLI will be selected.

Add some annotations

Now we are going to add some annotations to SFLIGHT CDS.

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@EndUserText.label: 'CDS view fr SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   @UI.lineItem: [{position: 10, label: 'Airline Code' }]
   key carrid,
   @UI.lineItem: [{position: 20, label: 'Connection Number' }]
   key connid,
   @UI.lineItem: [{position: 30, label: 'Flight date' }]
   key fldate,
   @UI.lineItem: [{position: 40, label: 'Airfare' }]
   @Semantics.quantity.unitOfMeasure: 'currency'
   price,
   currency,
   @UI.lineItem: [{position: 50, label: 'Aircraft Type' }]
   planetype,
   
   _spfl,
   _plane
}

As you can see we use several annotations:

@OData.publish: true

When you activate your CDS – system will generate OData service. You just need to register generated service in the Service Maintenance transaction: /n/iwfnd/maint_service.

If you don’t know how to do it, use this tutorial from Dilip Kumar: https://blogs.sap.com/2017/11/19/sap-fiori-odata-service-registration-activation/

@UI.lineItem: [{position: 10, label: ‘Airline Code’ }]

This annotation tells Front-end to draw a table. Position – column position. Label – column name

@Semantics.quantity.unitOfMeasure: ‘currency’

This annotation allows to connect measure field with unit of measure.

Create Smart Template Application

1 Go to SAP Cloud Platform

2 Select Neo Trial

3 Select “Services” and then click “SAP Web IDE Full-Stack”.

4 If service is not enables > click “Enable”. Click “Go to Service” link.

5 Create a Project. Right Mouse Button on Workspace -> New -> Project From Template

6 Select “List report” as template and click “Next” button.

7 Provide Project name and Title and click “Next” button

8 On the next screen select System and Service(which was generated with OData annotation)  and click “Next” button.

9 Check all files from the next screen and click “Next” button

10 Select Sflight in OData Collection and click “Finish”.

11 Run the Application: select created Project and click “Run”-> “Run flpSandbox.html”

12 If you click “Go”(1) button -> data will be selected. App title(2) – we provided this name in the step7. As you can see, column “Airfare”(3) containts value and unit of measure(annotation).

Additional features

1 @UI.headerInfo: { typeName: ‘Flight Information’, typeNamePlural: ‘Flights Info’ } – Set table name

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@UI.headerInfo: { typeName: 'Flight Information', typeNamePlural: 'Flights Info' }
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{...
}

2 @UI.presentationVariant: [{sortOrder: [{by: ‘connid’, direction: #ASC}] }] – set sort order

“by” – field name from CDS

“direction” – ASCending or DESCending

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@UI.headerInfo: { typeName: 'Flight Information', typeNamePlural: 'Flights Info' }
@UI.presentationVariant: [{sortOrder: [{by: 'connid', direction: #ASC}] }]
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{...
}

3 Lets add some Filter to the App:

@UI.selectionField: [{position: 10 }]

“position” – set order of filters

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@UI.headerInfo: { typeName: 'Flight Information', typeNamePlural: 'Flights Info' }
@UI.presentationVariant: [{sortOrder: [{by: 'connid', direction: #ASC}] }]
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   @UI.lineItem: [{position: 10, label: 'Airline Code' }]
   @UI.selectionField: [{position: 10 }]
   key carrid,
   @UI.lineItem: [{position: 20, label: 'Connection Number' }]
   @UI.selectionField: [{position: 20 }]
   key connid
...
}

4 How to set Filter Description?

@EndUserText.label: ‘ConnNumb’

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@UI.headerInfo: { typeName: 'Flight Information', typeNamePlural: 'Flights Info' }
@UI.presentationVariant: [{sortOrder: [{by: 'connid', direction: #ASC}] }]
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   @UI.lineItem: [{position: 10, label: 'Airline Code' }]
   @UI.selectionField: [{position: 10 }]
   key carrid,
   @UI.lineItem: [{position: 20, label: 'Connection Number' }]
   @UI.selectionField: [{position: 20 }]
   @EndUserText.label: 'ConnNumb'
   key connid,
...
}

5 Set default Filter values

@Consumption: {
filter: {
mandatory: false,
defaultValue: ‘AA’ }
}

define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   @UI.lineItem: [{position: 10, label: 'Airline Code' }]
   @Search.defaultSearchElement: true
   @UI.selectionField: [{position: 10 }]
   @Consumption: {
                      filter: {
                          mandatory: false,
                          defaultValue: 'AA'

                      }
                  }
   
key carrid,
...
}

6 Add global search

@Search.searchable: true – Add global Search to the toolbar

@Search.defaultSearchElement: true – Specify which fields will be included in the Global Search

@AbapCatalog.sqlViewName: 'ZYHB_V_SFLIGHT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED

@OData.publish: true

@Search.searchable: true

@UI.headerInfo: { typeName: 'Flight Information', typeNamePlural: 'Flights Info' }
@UI.presentationVariant: [{sortOrder: [{by: 'connid', direction: #ASC}] }]
@EndUserText.label: 'CDS view for SFLIGHT table'
define view ZYHB_P_SFLIGHT 
as select from sflight as sfl
association [1] to ZYHB_P_SPFLI as _spfl on  sfl.carrid = _spfl.carrid
                                         and sfl.connid = _spfl.connid
                                        
association[1] to ZYHB_P_SAPLANE as _plane on sfl.planetype = _plane.planetype
{
   @UI.lineItem: [{position: 10, label: 'Airline Code' }]
   @Search.defaultSearchElement: true
   @UI.selectionField: [{position: 10 }]
   key carrid,
   @UI.lineItem: [{position: 20, label: 'Connection Number' }]
   @Search.defaultSearchElement: true
   @UI.selectionField: [{position: 20 }]
   @EndUserText.label: 'ConnNumb'
   key connid,
...
}

 

That is all in this part.

As you can see, without any UI coding we can create a Web Application.

Smart Template is very flexible tool, it allows quickly create Apps, supports different layouts, charts and coloring.

In the next post we will continue

 

Best regards,

Yury Hotsman

 

Be the first to leave a comment
You must be Logged on to comment or reply to a post.