Technical Articles
Building an Analytical List Page with CAP OData V4
Introduction
In this blog post, I am going to demonstrate how to annotate CAP service to enable the display of an Analytical List Page (ALP). I discovered this solution in deepak_singh99‘s GitHub repository (currently not available), so I want to give credit to him.
Scenario
To build a very basic ALP app on top of CAP OData V4 service as shown below. The code is available at GitHub.
Analytical List Page
Steps
- Create a data model
- Add annotations
- Create ALP
1. Create a data model
I have created a very basic data model based on a Books entity generated by `cds add samples` command.
namespace my.bookshop;
entity Books {
key ID : Integer @title: 'ID';
title : String @title: 'Title';
stock : Integer @title: 'Stock';
category1: String @title: 'Category1';
category2: String @title: 'Category2';
publishedAt: Date @title: 'Published At';
}
The data model is exposed to the service as is.
using my.bookshop as my from '../db/data-model';
service CatalogService {
@readonly entity BooksAnalytics as projection on my.Books;
}
2. Add annotations
I will explain the annotations added by dividing them into four blocks for clarity.
The first block focuses on enabling aggregate functions. These annotations are crucial for Fiori tools to properly recognize and support the Analytical List Page (ALP). Without these annotations, Fiori tools may raise error indicating the absence of a suitable entity for ALP.
annotate CatalogService.BooksAnalytics with @(
Aggregation.ApplySupported: {
Transformations: [
'aggregate',
'topcount',
'bottomcount',
'identity',
'concat',
'groupby',
'filter',
'expand',
'search'
],
GroupableProperties: [
ID,
category1,
category2,
title,
publishedAt
],
AggregatableProperties: [{
$Type : 'Aggregation.AggregatablePropertyType',
Property: stock
}]
},
Analytics.AggregatedProperty #totalStock: {
$Type : 'Analytics.AggregatedPropertyType',
AggregatableProperty : stock,
AggregationMethod : 'sum',
Name : 'totalStock',
![@Common.Label]: 'Total stock'
},
);
The second block is for displaying a chart in the middle of the ALP. One point that was new to me was the use of DynamicMeasure. With OData V2, you may be familiar with “normal” Measure annotations. However, in the context of OData V4, normal Measure somehow does not work, so you need to use DynamicMeasure, which references the @Analytics.AggregatedProparety defined in the first block.
annotate CatalogService.BooksAnalytics with @(
UI.Chart: {
$Type : 'UI.ChartDefinitionType',
Title: 'Stock',
ChartType : #Column,
Dimensions: [
category1,
category2
],
DimensionAttributes: [{
$Type : 'UI.ChartDimensionAttributeType',
Dimension: category1,
Role: #Category
},{
$Type : 'UI.ChartDimensionAttributeType',
Dimension: category2,
Role: #Category2
}],
DynamicMeasures: [
![@Analytics.AggregatedProperty#totalStock]
],
MeasureAttributes: [{
$Type: 'UI.ChartMeasureAttributeType',
DynamicMeasure: ![@Analytics.AggregatedProperty#totalStock],
Role: #Axis1
}]
},
UI.PresentationVariant: {
$Type : 'UI.PresentationVariantType',
Visualizations : [
'@UI.Chart',
],
}
);
The third block focuses on displaying visual filters. To achieve this, you will need three annotation blocks: chart, presentation variant and value list. The chart annotation block is similar to the one in the second block. However, please note that OData V4 currently only supports bar and line chart types for visual filters, whereas OData V2 also supports donut charts.
* You can also add these annotations with the guided development feature of Fiori tools, which will be much easier.
annotate CatalogService.BooksAnalytics with @(
UI.Chart #category1: {
$Type : 'UI.ChartDefinitionType',
ChartType: #Bar,
Dimensions: [
category1
],
DynamicMeasures: [
![@Analytics.AggregatedProperty#totalStock]
]
},
UI.PresentationVariant #prevCategory1: {
$Type : 'UI.PresentationVariantType',
Visualizations : [
'@UI.Chart#category1',
],
}
){
category1 @Common.ValueList #vlCategory1: {
$Type : 'Common.ValueListType',
CollectionPath : 'BooksAnalytics',
Parameters: [{
$Type : 'Common.ValueListParameterInOut',
ValueListProperty : 'category1',
LocalDataProperty: category1
}],
PresentationVariantQualifier: 'prevCategory1'
}
}
The fourth block consists of SelectionFields and LineItem annotations that you may already be familiar with.
annotate CatalogService.BooksAnalytics with@(
UI: {
SelectionFields : [
category1,
category2,
publishedAt
],
LineItem: [
{ $Type : 'UI.DataField', Value : ID, },
{ $Type : 'UI.DataField', Value : title, },
{ $Type : 'UI.DataField', Value : category1, },
{ $Type : 'UI.DataField', Value : category2, },
{ $Type : 'UI.DataField', Value : stock, },
{ $Type : 'UI.DataField', Value : publishedAt, },
],
}
);
3. Create ALP
Let’s proceed with creating an ALP with using the template.
Floorplan selection
Entity Selection
To configure ALP, you need to make some settings in the “options”.”settings” seciton of the manifest.json file. The “views” section is used to display the main chart and table. This section is included by default when generating the app using the “Analytical List Page” template. If you wish to use different annotations than the default ones (without qualifier), you need to make the necessary adjustment here.
The “@com.sap.vocabularies.UI.v1.SelectionFields” section in the “controlConfiguration” is used to show the visual filters. It’s important to note that the filterFields names must match the property names of the entity used.
"options": {
"settings": {
"entitySet": "BooksAnalytics",
...,
"controlConfiguration": {
"@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"type": "ResponsiveTable",
"selectionMode": "None"
}
},
"@com.sap.vocabularies.UI.v1.SelectionFields": {
"layout": "CompactVisual",
"initialLayout": "Visual",
"filterFields": {
"category1": {
"visualFilter": {
"valueList": "com.sap.vocabularies.Common.v1.ValueList#vlCategory1"
}
},
"category2": {
"visualFilter": {
"valueList": "com.sap.vocabularies.Common.v1.ValueList#vlCategory2"
}
},
"publishedAt": {
"visualFilter": {
"valueList": "com.sap.vocabularies.Common.v1.ValueList#vlPublishedAt"
}
}
}
}
},
"views": {
"paths": [
{
"primary": [{"annotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant"}],
"secondary": [{"annotationPath": "com.sap.vocabularies.UI.v1.LineItem"}],
"defaultPath": "both"
}
]
}
}
}
A note about the table type
By default, the table type for the Analytical List Page is set to “AnalyticalTable”. However, with this setting, measures are not displayed in the table. You can observe that “Stock” column in the below image is empty.
AnalyticalTable does not show measures
From my investigation, AnalyticalTable requires simple aggregation annotation as shown below:
annotate CatalogService.BooksAnalytics with @(
Aggregation.ApplySupported
);
However, you cannot display charts with this simple annotation. To work around this issue, I had to use ResponsiveTable instead of AnalyticalTable. If anyone knows the how we can use AnalyticalTable, please let me know in the comment section.
Closing
By utilizing the mentioned settings and configurations, you can successfully create an Analytical List Page (ALP) on top of CAP OData V4 service. I hope this article has provided valuable insights into the analytical capabilities of CAP and OData V4. Thanks for reading!
This Makes me Happy! Thank You @mioyasutake
Hi deepak_singh99,
Thanks for your comment! Your repository helped me a lot.
Hi Mio Yasutake
Great and informative blog from you as always.. one kind share: the github link referred to Deepak's work seem broken, kindly refer it to the the root project level.
Many thanks,
Best,
Merve
Hi Makbule Merve Gül,
Thanks for your comment. Unfortunately, the repository seems to have been removed or gone private, so it is not available now.
Hi Mio Yasutake
It seem like the app moved to another repo, since I dont know its previous state I cant compare it though.
https://github.com/deepaksinghbondili/MyHanaApp-cap/tree/master/app/assemblyapp
Thanks for the information. This is the repo I referred to.
I have updated the link to the repo.
Thank you for the blog.In the document they have mentioned that Line charts are only rendered if the dimension is time based, that is if you use
Edm.Date
,Edm.Time
, orEdm.DateTimeOffset
. But as per our req we need to show per year.Can you help to format the date type to display only year.Hi Thajunniza M A,
Thanks for reading!
In the document, there is the following description.
Based on this, one approach would be to create a virtual element that contains only year and add annotation @sap.semantics: 'year' to the field. Another approach (I am not sure if this works though,) is to add sap:display-format='Year' to the DateTime field.
Dear Yasutake,
Thanks for your sharing, I learn a lot from it.
And from my investigation, please add stock to the GroupableProperties. The AnalyticalTable should show it now.
Dear Arvin Wen,
Thanks for your comment. I added stock to the GroupableProperties. As a result, stock values were displayed, but total for stock does not work. If it is working, "Totals for : Stock" button would be displayed, instead of "Group by: Stock".
Hello Mio Yasutake have you done with hierarchy data for smart table tree using annotations in capm cds ,
Hi deepak_singh99
I haven't used hierarchy annotations with CAP.