Skip to Content
Technical Articles
Author's profile photo Mio Yasutake

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%20List%20Page

Analytical List Page

Steps

  1. Create a data model
  2. Add annotations
  3. 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%20selection

Floorplan selection

Entity%20Selection

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%20does%20not%20show%20measures

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!

References

Assigned Tags

      12 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Deepak Singh
      Deepak Singh

      This Makes me Happy! Thank You @mioyasutake

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      Hi deepak_singh99,

      Thanks for your comment! Your repository helped me a lot.

      Author's profile photo Makbule Merve Gül
      Makbule Merve Gül

      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

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      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.

       

      Author's profile photo Merve Gül
      Merve Gül

      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

       

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      Thanks for the information. This is the repo I referred to.

      I have updated the link to the repo.

      Author's profile photo Thajunniza M A
      Thajunniza M A

      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.DateEdm.Time, or Edm.DateTimeOffset. But as per our req we need to show per year.Can you help to format the date type to display only year.

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      Hi Thajunniza M A,

      Thanks for reading!

      In the document, there is the following description.

      • The data type of the dimension is either edm.datetime or edm.string. If the data type is edm.string, then it needs to have the additional annotation in the OData metadata annotation: sap:semantics:”year (YYYY) or yearweek (YYYYWW) or yearmonth (YYYYMM) or yearquarter (YYYYQ)”.

      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.

      Author's profile photo Arvin Wen
      Arvin Wen

      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.

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      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".

       

      Author's profile photo Deepak Singh
      Deepak Singh

      Hello Mio Yasutake have you done with hierarchy data for smart table tree using annotations in capm cds ,

      Author's profile photo Mio Yasutake
      Mio Yasutake
      Blog Post Author

      Hi deepak_singh99

      I haven't used hierarchy annotations with CAP.