Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Ajit_K_Panda
Product and Topic Expert
Product and Topic Expert

Introduction

Based on my brief experience with SAP Fiori Elements, I have previously written two blogs as follows:

Building upon those blogs, in this blogpost, i will document my insights in exploring actions on List Report and Object Page using annotations only.

This blog post has as a follow-up to the following subsequent post:
CAP with Fiori Elements: Actions on List Report / Object Page using Annotations – Part2

Explanation of POC scenario and Its resources

We will use the sample project “cap-fe-lr-op-actions” that I have shared on GitHub here to explain the concepts. Let’s briefly examine the project and some of its essential files.

Ajit_K_Panda_0-1707107177848.jpeg

Service cap_fe_lr_op_actions_serviceproivides following data set: Roots, Items, Categories, Criticalities, Samples.
Please be aware that in this blog post, my emphasis is on illustrating the functionality of presenting tables in various configurations. It’s worth noting that the service utilized for demonstration purposes may not be flawless and is solely used to explain the functionalities.

Detailed Explanation

Note: This blog post does not delve into custom actions or navigating to other apps.

In SAP Fiori Elements, actions refer to specific operations or functionalities that users can perform within an application. These actions are typically associated with buttons allowing users to trigger specific behaviors or execute predefined tasks or navigate to other applications.

There are 2 ways actions can be added to Fiori Elements based applications.

  1. Annotation-Based: add, enable or disable buttons using annotations
  2. Custom-Actions: add, enable or disable buttons using extension (manifest.json)

Actions can be divided into 2 categories based on how they are added:

  1. Generic Actions
  2. App-Specific Actions

1. Generic Actions
In both the list report and on the object page, SAP Fiori Elements offers standard actions like Create (+), Delete, Edit, Export, Personalization etc. These actions can be customized by enabling or disabling them based on your application's requirements.

  • To enable create, update, and delete functionalities in Fiori Elements, it is essential to include @odata.draft.enabled when utilizing CAP with OData V4-based service
  • Disabling create, update, and delete functionalities is achievable at both the service and UI application levels.
  • Create actions can be enabled or disabled using following annotations:
    //======>>Service Annotaions<<======
    annotate service.Roots with @(
        Capabilities.Insertable: false
    );​
    
    //========>>UI Annotaions<<========
    annotate service.Roots with @(
        UI.CreateHidden: true
    );​​
  • Simillar to create action, update / edit action can also be enabled or disabled.
    //======>>Service Annotaions<<======
    annotate service.Roots with @(
        Capabilities.Updatable: false
    );​
    
    //========>>UI Annotaions<<========
    annotate service.Roots with @(
        UI.UpdateHidden: true
    );​​​

    Disabling the edit action at the service level won't hide the edit button on the UI; instead, it results in an error.

    Additionally, it's feasible to dynamically control the edit action based on a specific element of the entity or by using dynamic expressions.
    /* disableUpdation,enableUpdation 
    are elements of Roots entity.  */
    
    //======>>By Property<<======
    annotate service.Roots with @(
      UI.UpdateHidden: disableUpdation
    );​​​
    
    //======>>By Dynamic Expression<<======
    annotate service.Roots with @(
      UI.UpdateHidden : {$edmJson: {$Ne: [
            {$Path: 'enableUpdation'},
            true
      ]}}
    );​​​
    This will dynamically hide the button whenever the condition is satisfied based on the value of entity.
  • Just like create or edit actions, the delete action can be either enabled or disabled..
    //======>>Service Annotaions<<======
    annotate service.Roots with @(
        Capabilities.Deletable: false
    );​
    
    //========>>UI Annotaions<<========
    annotate service.Roots with @(
        UI.DeleteHidden: true
    );​​​
    Disabling the Deletion action based on property or dynamic expression is applicable exclusively on the object page.
    /* disableDeletion,enableDeletion
       are elements of Roots entity.  */
    
    //======>>By Property<<======
    annotate service.Roots with @(
      UI.DeleteHidden: disableDeletion
    );​​​
    
    //======>>By Dynamic Expression<<======
    annotate service.Roots with @(
      UI.DeleteHidden : {$edmJson: {$Ne: [
            {$Path: 'enableDeletion'},
            true
      ]}}
    );​
  • Other generic buttons on the table toolbar include copy, personalization, and export. The personalization and export buttons can be hidden using the following configuration in the manifest.json file.
    "controlConfiguration": {
        "@com.sap.vocabularies.UI.v1.LineItem": {
            "tableSettings": {
                "enableExport": false,
                "personalization": {
                    "sort"  : false,
                    "filter": false,
                    "column": false
                }
            }
        }
    }​

2. App-Specific Actions
Based on position or location, Following different kinds of action can be added on List Report or Object Pages using annotations:

2.1 Global Actions:

  • These actions are placed/rendered at the top of the page (next to share button). On list report, this is possible only with extensions. However, on object page, global actions can be added using annotations.
  • global action can be defined using UI.Identification annotation as shown below:
    annotate service.Roots with @(UI.Identification: [
    {
      $Type      : 'UI.DataFieldForAction',
      Action     : 'cap_fe_lr_op_actions_service.ga_op_calculate',
      Label      : 'Trigger Calculation',
      Criticality: #Negative
    },
    {
      $Type      : 'UI.DataFieldForAction',
      Action: 'cap_fe_lr_op_actions_service.EntityContainer/ga_op_ub_replication',
      Label      : '(Unbound) Trigger Replication',
      Criticality: #Positive
    }
    ]);​​​​​​
  • Result:
  • Note: Both bound and unbound actions can be added as Global Actions

2.2 Actions on Table:

  • Specific actions tailored for the application can be incorporated into a table either on the toolbar or as a distinct column
  • This is possible both on List Report or Tables on Object Page
  • The following annotations demonstrate how to add such buttons:
  • /*==========>> Button on ToolBar <<==========*/
    annotate service.Roots with @(UI.LineItem: [
      {
        $Type : 'UI.DataFieldForAction',
        Action: 'cap_fe_lr_op_actions_service.ta_lr_toolbarAction',
        Label : 'Toolbar Action'
      }
    ]);
  • /*==========>> Button as Column <<==========*/
    annotate service.Roots with @(UI.LineItem: [
      {
        $Type      : 'UI.DataFieldForAction',
        Action     : 'cap_fe_lr_op_actions_service.ta_lr_inlineAction',
        Label      : 'Inline Action',
        Inline     : true,
        Criticality: #Positive
      }
    ]);
  •  Note 1: To display the button as a column, set the Inline property to true in the UI.DataFieldForAction annotation
  • Note 2: The Action property refers to the bound action from your service in the format '{ServiceName}.{ActionName}'.
  • Note 3: These actions become enabled when one or more rows are selected and are termed context-dependent actions. The conext is passed in req.params parameters.
  • Note 4: It is also possible to show unbound actions on the toolbar using the following annotation:
    annotate service.Roots with @(UI.LineItem: [
      {
        $Type : 'UI.DataFieldForAction',
        Action: 'cap_fe_lr_op_actions_service.EntityContainer/ta_lr_ub_toolbarAction',
        Label : '(Unbound) Toolbar Action'
      }
    ]);​​
    In this case, selection of row does not have any impact and context is not passed, hence called context-independent actions. Also Action property refers to the unbound action from your service in the format '{ServiceName}.EntityContainer/{ActionName}'.
  • Note 5: The text on the inline buttons can be substituted with an icon by utilizing the "IconUrl" annotation property. In this case, the label of the button serves as the tooltip for the button.

  • annotate service.Roots with @(UI.LineItem: [  
      {
        $Type      : 'UI.DataFieldForAction',
        Action     : 'cap_fe_lr_op_actions_service.ta_lr_inlineIconAction',
        Label      : 'Inline Icon Action',
        Inline     : true,
        IconUrl    : 'sap-icon://da',
        Criticality: #Negative
      }​
    ]);
  • Result:

2.3 Actions in Forms and Sections:

  • Similar to other instances, actions can also be incorporated into forms and groups using the same annotations:
    annotate service.Roots with @(UI.FieldGroup #Details: {
    $Type: 'UI.FieldGroupType',
    Data: [
      {
        $Type : 'UI.DataFieldForAction',
        Action: 'cap_fe_lr_op_actions_service.EntityContainer/fg_op_ub_triggerRefresh',
        Label : '(Unbound) Section Trigger'
      },
      {
        $Type : 'UI.DataFieldForAction',
        Action: 'cap_fe_lr_op_actions_service.fg_op_triggerInlineAction01',
        Label : 'Inline Trigger 01',
        Inline: true
      }
    ]});
    
    annotate service.Roots with @(UI.FieldGroup #MoreDetails: {
    $Type: 'UI.FieldGroupType',
      Data : [
        {
          $Type : 'UI.DataFieldForAction',
          Action: 'cap_fe_lr_op_actions_service.fg_op_triggerAction',
          Label : 'Section Trigger'
        },
        {
          $Type : 'UI.DataFieldForAction',
          Action : 'cap_fe_lr_op_actions_service.fg_op_triggerInlineAction02',
          Label : 'Inline Trigger 02',
          Inline: true
        }
    ]});​
  • When the inline property is set to true, the action will be displayed within the field group section as illustrated below.
  • Moreover, it is also feasible to include unbound actions in this context.
  • Result:

2.4 Actions in Chart:

  • Action buttons can also be added to the chart toolbar by defining the Actions property in the annotation term UI.Chart.
  • Here is an example:
    UI.Chart #ROChart: {
      $Type              : 'UI.ChartDefinitionType',
      Title              : 'Amount By Item',
      ChartType          : #Bar,
      Dimensions         : [iname],
      DimensionAttributes: [{
        $Type    : 'UI.ChartDimensionAttributeType',
        Dimension: iname,
        Role     : #Category
      }],
      DynamicMeasures: ['@Analytics.AggregatedProperty#itemamount_sum'],
      Actions : [
        {
          $Type      : 'UI.DataFieldForAction',
          Action     : 'ca_op_ub_chartAction',
          Label      : '(Unbound) Chart Action',
          Criticality: #Positive
        }
      ]
    }
  • Result:
  • Note: Actions are added in Actions property of @UI.Chart annotation term.

2.5 Determining Actions

  • These actions, also known as finalizing actions, are positioned in the object page's footer and are designed for operations that have a comprehensive impact on the entire page.
  • It is essential to avoid defining finalizing actions for actions that are specific to controls or individual parts of the page
  • For determining actions, Determining property is set to true in UI.DataFieldForAction annotation term as shwon:
    annotate service.Roots with @(UI.Identification: [
      {
        $Type      : 'UI.DataFieldForAction',
        Action     : 'cap_fe_lr_op_actions_service.da_op_clearParymentAction',
        Label      : 'Clear Payment Action',
        Determining: true,
        Criticality: #Negative
      },
      {
        $Type      : 'UI.DataFieldForAction',
        Action     : 'cap_fe_lr_op_actions_service.EntityContainer/da_op_ub_clearOutstanding',
        Label      : '(Unbound) Clear Outstanding',
        Determining: true,
        Criticality: #Positive
      }
    ]);​
  • Result:

Miscellanous features

1. Disabling Actions (unclickable)

  • At times, it may be necessary to deactivate actions based on specific business logic, such as enabling the trigger delivery action only when the order status is submitted. This level of control can be implemented using the @Core.OperationAvailable annotation term.
  • Let's look at some example annotations:
    annotate service.Roots with actions{
      ta_lr_inlineAction @Core.OperationAvailable: disableUpdation;
      ta_lr_inlineIconAction  @Core.OperationAvailable: {
        $edmJson: {$Gt: [{$Path: 'totalAmount'}, 1000]}
      };
      ta_lr_toolbarAction @Core.OperationAvailable: disableUpdation;
    };​
    In above sample, ta_lr_inlineAction will be disabled or enabled (made clickable) based on the value in 'disableUpdation' element of Roots entity. Simillary ta_lr_inlineIconAction will be disabled or enabled if 'totalAmount' is greater than 100 of Roots entity.
  • Note: It is possible to refer elements of an entiy or provide dynamic expression to evaluate operation availability.

2. Hiding Actions

  • It is possible to hide actions based on elements of entity or using dynamic expressions.
  • Sample Annotation on Item entity:
    annotate service.Items with @(UI.LineItem #Items: [
    {
      $Type      : 'UI.DataFieldForAction',
      Action     : 'cap_fe_lr_op_actions_service.ta_op_item_inline',
      Label      : 'Item Inline Action',
      Inline     : true,
      Criticality: #Positive,
      ![@UI.Hidden]: {$edmJson: {$Ne: [{$Path: 'enableItem'}, true]}}
    }
    
    ]);

    result:

  • Another fantastic capability is the ability to activate a button when the entity is in edit mode:
    annotate service.Items with @(UI.LineItem #Items: [
    
    {
      $Type      : 'UI.DataFieldForAction',
      Action     : 'cap_fe_lr_op_actions_service.ta_op_item_inline2',
      Label      : 'Action on Edit',
      Inline     : true,
      Criticality: #Negative,
      ![@UI.Hidden]: IsActiveEntity
    }
    ]);​

    Please be aware that IsActiveEntity is a property within Fiori Elements, and it is set to false when the entity is in edit mode.

 

Conclusion

In this blog post, we have delved into the utilization of different annotations to incorporate actions at different positions on List Report and Object Pages along with some miscellanous features.

Together, the Cloud Application Programming Model and Fiori Elements improve developer experience while also boosting productivity and accelerating the development of enterprise-ready applications.

More information about Fiori Elements with cloud application programming model can be found here. You can follow my profile to get notification of the next blog post on CAP or Fiori Elements. Please feel free to provide any feedback you have in the comments section below and ask your questions about the topic in sap community using this link.