Skip to Content
Technical Articles
Author's profile photo Vijay Chintarlapalli

Hiding a Tab dynamically in Fiori Object page using Virtual Elements/UI Annotations in RAP (Restful ABAP Programming) Model

Introduction :

Since all the new SAP Developments are moving towards RAP(Restful ABAP Programming) based model there could be multiple requirements to hide some of the Facets in the Fiori List Report based object page based using complex dynamic conditions.

Solution :

As there could be complex conditions for multiple tabs which will be displayed in the line item .We can achieve this kind of requirements using the Virtual Element and the UI annotations as shown below.

Lets take a below example scenario for a purchase order we have two different Child entities items PO items, PO Material Items which are required to be displayed based on the condition basis in the object page of list report  .

Purchase%20Order%20Example%20Model

Purchase Order Example Model

Create the below three data base tables  :

PO header

@EndUserText.label : 'Purchase Document'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zpurchasedoc {
  key client               : abap.clnt not null;
  key purchasedocument     : zpurchasedocumentdtel not null;
  @EndUserText.label : 'Description'
  description              : abap.sstring(128);
  @EndUserText.label : 'Approval Status'
  status                   : abap.char(1);
  @EndUserText.label : 'Priority'
  priority                 : abap.char(1);
  @EndUserText.label : 'Purchasing Organization'
  purchasingorganization   : abap.char(4);
  @EndUserText.label : 'Purchase Document Image URL'
  purchasedocumentimageurl : abap.sstring(255);
  crea_date_time           : timestampl;
  crea_uname               : uname;
  lchg_date_time           : timestampl;
  lchg_uname               : uname;

}

PO Item

@EndUserText.label : 'Purchase Document Item'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zpurchdocitem {
  key client                   : abap.clnt not null;
  @EndUserText.label : 'Purchase Document Item'
  key purchasedocumentitem     : abap.char(10) not null;
  key purchasedocument         : zpurchasedocumentdtel not null;
  @EndUserText.label : 'Description'
  description                  : abap.sstring(128);
  @EndUserText.label : 'Price'
  @Semantics.amount.currencyCode : 'zpurchdocitem.currency'
  price                        : abap.curr(13,2);
  @EndUserText.label : 'Currency'
  currency                     : abap.cuky;
  @EndUserText.label : 'Quantity'
  @Semantics.quantity.unitOfMeasure : 'zpurchdocitem.quantityunit'
  quantity                     : abap.quan(13,2);
  @EndUserText.label : 'Unit'
  quantityunit                 : abap.unit(3);
  @EndUserText.label : 'Vendor'
  vendor                       : abap.sstring(32);
  @EndUserText.label : 'Vendor Type'
  vendortype                   : abap.sstring(32);
  @EndUserText.label : 'Purchase Document Item Image URL'
  purchasedocumentitemimageurl : abap.sstring(255);
  crea_date_time               : timestampl;
  crea_uname                   : uname;
  lchg_date_time               : timestampl;
  lchg_uname                   : uname;

}

PO material Item

@EndUserText.label : 'Purchase Document Material Item'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zpurchdocmatitem {
  key client           : abap.clnt not null;
  @EndUserText.label : 'Purchase Document Item'
  key material         : abap.char(10) not null;
  key purchasedocument : zpurchasedocumentdtel not null;
  @EndUserText.label : 'Description'
  description          : abap.sstring(128);
  @EndUserText.label : 'Price'
  @Semantics.amount.currencyCode : 'zpurchdocmatitem.currency'
  price                : abap.curr(13,2);
  @EndUserText.label : 'Currency'
  currency             : abap.cuky;
  @EndUserText.label : 'Quantity'
  @Semantics.quantity.unitOfMeasure : 'zpurchdocmatitem.quantityunit'
  quantity             : abap.quan(13,2);
  @EndUserText.label : 'Unit'
  quantityunit         : abap.unit(3);
  @EndUserText.label : 'Vendor'
  vendor               : abap.sstring(32);

}

Now create the below Interface root Views entities for the

Purchase order header

@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Purschase Document Interface View'
define root  view entity Z_I_PurchaseDocument as select from zpurchasedoc
composition [0..*] of Z_I_PurchItem as _poitem 
 composition  [0..*] of Z_I_PURCHMATITEM  as _pomatitem 
{
    key zpurchasedoc.purchasedocument as Purchasedocument,
    zpurchasedoc.description as Description,
    zpurchasedoc.status as Status,
    zpurchasedoc.priority as Priority,
    zpurchasedoc.purchasingorganization as Purchasingorganization,
    zpurchasedoc.purchasedocumentimageurl as Purchasedocumentimageurl,
    zpurchasedoc.crea_date_time as CreaDateTime,
    zpurchasedoc.crea_uname as CreaUname,
    zpurchasedoc.lchg_date_time as LchgDateTime,
    zpurchasedoc.lchg_uname as LchgUname,
    _poitem ,
    _pomatitem
    // Make association public
}

Purchase Order Item

    @AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Purschase Document Item Interface View'
define view entity Z_I_PurchItem as select from zpurchdocitem 

   association to parent Z_I_PurchaseDocument as _PoHeader on $projection.Purchasedocument = _PoHeader.Purchasedocument {
    key zpurchdocitem.purchasedocumentitem as Purchasedocumentitem,
key zpurchdocitem.purchasedocument as Purchasedocument,
zpurchdocitem.description as Description,
zpurchdocitem.price as Price,
zpurchdocitem.currency as Currency,
zpurchdocitem.quantity as Quantity,
zpurchdocitem.quantityunit as Quantityunit,
zpurchdocitem.vendor as Vendor,
zpurchdocitem.vendortype as Vendortype,
zpurchdocitem.purchasedocumentitemimageurl as Purchasedocumentitemimageurl,
zpurchdocitem.crea_date_time as CreaDateTime,
zpurchdocitem.crea_uname as CreaUname,
zpurchdocitem.lchg_date_time as LchgDateTime,
zpurchdocitem.lchg_uname as LchgUname,
    _PoHeader // Make association public
}
    

Purchase order Material Item

 

    @AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Purschase Document Item Interface View'
define view entity Z_I_PURCHMATITEM as select from zpurchdocmatitem 

   association to parent Z_I_PurchaseDocument as _PoHeader on $projection.Purchasedocument = _PoHeader.Purchasedocument {
    key zpurchdocmatitem.material as material,
key zpurchdocmatitem.purchasedocument as Purchasedocument,
zpurchdocmatitem.description as Description,
zpurchdocmatitem.price as Price,
zpurchdocmatitem.currency as Currency,
zpurchdocmatitem.quantity as Quantity,
zpurchdocmatitem.quantityunit as Quantityunit,
zpurchdocmatitem.vendor as Vendor,

    _PoHeader // Make association public
}
    

Now create the below Root View entities for Projection views :

@EndUserText.label: 'Purschase Order Consumption View'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
define root view entity Z_C_PurchDocument as projection on Z_I_PurchaseDocument {
key Purchasedocument,
Description,
Status,
Priority,
Purchasingorganization,
Purchasedocumentimageurl,
CreaDateTime,
CreaUname,
LchgDateTime,
LchgUname, 
/* Associations */
_poitem : redirected to composition child Z_C_PURCHITEM   ,
 _pomatitem : redirected to composition child Z_C_PURCHMATITEM 
}

PO item

@EndUserText.label: 'Purschase Order item Consumption view'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
define view entity Z_C_PURCHITEM as projection on Z_I_PurchItem {
key Purchasedocumentitem,
key Purchasedocument,
Description,
Price,
Currency,
Quantity,
Quantityunit,
Vendor,
Vendortype,
Purchasedocumentitemimageurl,
CreaDateTime,
CreaUname,
LchgDateTime,
LchgUname,
/* Associations */
_PoHeader :  redirected to parent Z_C_PurchDocument
}

PO Material Item :

@EndUserText.label: 'Purschase Order Material item Consumption view'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
define view entity Z_C_PURCHMATITEM as projection on Z_I_PURCHMATITEM {
key material,
key Purchasedocument,
Description,
Price,
Currency,
Quantity,
Quantityunit,
Vendor,
/* Associations */
_PoHeader :  redirected to parent Z_C_PurchDocument
}

Now create the below meta data extensions for all the 3 consumption views :

    @Metadata.layer: #CORE
@UI: {
    headerInfo: { typeName: 'Purchase Order Item',
                  typeNamePlural: 'Purchase Order Items',
                  title: { type: #STANDARD, label: 'Purchase Order Item'}
                }
                }
annotate view Z_C_PURCHITEM
    with 
{
  @UI.facet: [ { id:          'Items',
                 purpose:       #STANDARD,
                 type:          #IDENTIFICATION_REFERENCE,
                 label:         'Item Data',
                 position:      10 }]
                 
  @UI:{ lineItem:       [{ position: 10, label: 'PO Item' }],                    
        identification: [{ position: 10, label: 'PO Item'}] 

      }   
    
  Purchasedocumentitem;
    @UI:{ lineItem:       [{ position: 20, label: 'PO Document' }],                    
        identification: [{ position: 20, label: 'PO Document'}] }   
    
  Purchasedocument;
      @UI:{ lineItem:       [{ position: 30, label: 'PO Desc' }],                    
        identification: [{ position: 30, label: 'PO Desc'}] }   
  Description;
   @UI:{ lineItem:       [{ position: 40, label: 'Price' }],                    
        identification: [{ position: 40, label: 'Price'}] }   
  Price;
     @UI:{ lineItem:       [{ position: 50, label: 'Currency' }],                    
        identification: [{ position: 50, label: 'Currency'}] }   
  Currency;
    @UI:{ lineItem:       [{ position: 60, label: 'Quantity' }],                    
        identification: [{ position: 60, label: 'Quantity'}] }  
Quantity;

}
@Metadata.layer: #CORE
@UI: {
  headerInfo: { typeName: 'Purchase Order',
                typeNamePlural: 'Purchase Orders',
                title: { type: #STANDARD, label: 'Purchase Order', value: 'Purchasedocument' } },
  presentationVariant: [{ sortOrder: [{ by: 'Purchasedocument', direction:  #DESC }] }] }


annotate view Z_C_PurchDocument
    with 
{
@UI.facet: [ { id:            'Header',
                 purpose:       #STANDARD,
                 type:          #IDENTIFICATION_REFERENCE,
                 label:         'Header Data',
                 position:      10 },
               { id:            'Items',
                 purpose :      #STANDARD,
                 type:          #LINEITEM_REFERENCE,
                 label:         'Items',
                 position:      20,
                 targetElement: '_poitem'
               },
               
                { id:            'MatItems',
                 purpose :      #STANDARD,
                 type:          #LINEITEM_REFERENCE,
                 label:         'MateriallItems',
                 position:      20,
                 targetElement: '_pomatitem'
               }]

 @UI: {  lineItem:       [ { position: 10 } ],
          identification: [ { position: 10 } ],
          selectionField: [ { position: 10 } ] }  
   Purchasedocument;
     @UI:{ lineItem:       [{ position: 20, label: 'Desccriton'}],
        selectionField: [{ position: 20 }],
        identification: [{ position: 20, label: 'Desccriton'}] }

Description;
 @UI:{ lineItem:       [{ position: 30, label: 'Purchasing organization'}],
  selectionField: [{ position: 30 }],
        identification: [{ position: 30, label: 'Purchasing organization'}] }
Purchasingorganization;

    
}

 

    @Metadata.layer: #CORE
@UI: {
    headerInfo: { typeName: 'Purchase Order Material',
                  typeNamePlural: 'Purchase Order Material',
                  title: { type: #STANDARD, label: 'Purchase Order Material'}
                }
                }
annotate view Z_C_PURCHMATITEM
    with 
{
  @UI.facet: [ { id:          'MatItems',
                 purpose:       #STANDARD,
                 type:          #IDENTIFICATION_REFERENCE,
                 label:         'Item Data',
                 position:      10 }]
                 
  @UI:{ lineItem:       [{ position: 10, label: 'Material' }],                    
        identification: [{ position: 10, label: 'Material'}] 

      }   
    
  material;
    @UI:{ lineItem:       [{ position: 20, label: 'PO Document' }],                    
        identification: [{ position: 20, label: 'PO Document'}] }   
    
  Purchasedocument;
      @UI:{ lineItem:       [{ position: 30, label: 'PO Desc' }],                    
        identification: [{ position: 30, label: 'PO Desc'}] }   
  Description;
   @UI:{ lineItem:       [{ position: 40, label: 'Price' }],                    
        identification: [{ position: 40, label: 'Price'}] }   
  Price;
     @UI:{ lineItem:       [{ position: 50, label: 'Currency' }],                    
        identification: [{ position: 50, label: 'Currency'}] }   
  Currency;
    @UI:{ lineItem:       [{ position: 60, label: 'Quantity' }],                    
        identification: [{ position: 60, label: 'Quantity'}] }  
Quantity;

}

Now Create the beviour Definition and Implementation :

managed; // implementation in class zbp_i_purchasedocument unique;

define behavior for Z_I_PurchaseDocument alias Purchorder
persistent table ZPurchasedoc
lock master
//authorization master ( instance )
//etag master <field_name>
{
  create;
  update;
  delete;
  association _poitem { create; }
  association _pomatitem { create; }
}

define behavior for Z_I_PurchItem alias PurchItem
persistent table ZPurchDOCitem
lock dependent by _PoHeader
//authorization dependent by <association>
//etag master <field_name>
{
  update;
  delete;
    association _PoHeader { } field( mandatory) Purchasedocument;


}
define behavior for Z_I_PurchmatItem alias PurchmatItem
persistent table ZPurchDOCmatitem
lock dependent by _PoHeader
//authorization dependent by <association>
//etag master <field_name>
{
  update;
  delete;
    association _PoHeader { } field( mandatory) Purchasedocument;


}
projection;

define behavior for Z_C_PurchDocument alias PurchDocumen
{
  use create;
  use update;
  use delete;

  use association _poitem { create; }
  use association _pomatitem { create; }
}

define behavior for Z_C_PURCHITEM alias PURCHITEM
{
  use update;
  use delete;
  use association _PoHeader;
}

define behavior for Z_C_PURCHMATITEM alias PurchmatItem
{
  use update;
  use delete;
  use association _PoHeader;
}

Service Definition

@EndUserText.label: 'Purschase order server definition'
define service Z_PurschaseOrder_SD {
  expose Z_C_PurchDocument;
  expose Z_C_PURCHITEM;
  expose Z_C_PURCHMATITEM;
  expose Z_I_PurchaseDocument;
  expose Z_I_PurchItem;
  expose Z_I_PURCHMATITEM;
}

Service Binding as below

Service%20Binding

                                                                            Service Binding

Now the Application Looks as below with List Reports and multiple tabs of object page :

List%20Report

List Report

Object%20Page%20with%20Multiple%20Tabs

Object Page with Multiple Tabs

Virtual Elements for UI annotations 

Now the requirement is to hide the Material tab based on some conditions for example based on the User .

PS : We can also try to consume all the Header and Line item view entities contents to do multiple checks or conditions in the Class .

  • Enhance the Interface PO header view entities with the below virtual elements

  • Add the Virtual element fields in the PO header Projection view entity

Projection%20View%20Virtual%20Elements

Projection View Virtual Elements

  • Enhance the Metadata extension using the hidden annotation in the Lineitemreference Facet as shown below

Annotations%20for%20Hidden

Annotations for Hidden

  • Create the below class to handle the virtual elements

Create the class ZCL_COLL_PUR_ITEM_VE with the interface  IF_SADL_EXIT_CALC_ELEMENT_READ

Implement the below methods IF_SADL_EXIT_CALC_ELEMENT_READ~CALCULATE

Since the annotation hidden will interpret as the boolean values pass either abap_true or abap_false as shown below

    FIELD-SYMBOLS: <lv_data>     TYPE any.
    LOOP AT it_original_data ASSIGNING <lv_data>.
* Set index
      DATA(lv_index) = sy-tabix.
      ASSIGN COMPONENT to_upper( 'UICT_POITEM_IS' )  OF STRUCTURE ct_calculated_data[ lv_index ] TO FIELD-SYMBOL(<lv_purcitem>).
      IF <lv_purcitem> IS ASSIGNED .
          <lv_purcitem> = abap_false.
      ENDIF.
          ASSIGN COMPONENT to_upper( 'UICT_POITEMMAT_IS' )  OF STRUCTURE ct_calculated_data[ lv_index ] TO FIELD-SYMBOL(<lv_purcmatitem>).
      IF <lv_purcitem> IS ASSIGNED .
        if sy-uname = 'XXXXXX'.
          <lv_purcmatitem> = abap_true.
          endif.
      ENDIF.
    ENDLOOP.

method :

    IF iv_entity EQ 'Z_I_PURCHASEDOCUMENT'.
      INSERT |UICT_POITEM_IS| INTO TABLE et_requested_orig_elements.
      INSERT |UICT_POITEMMAT_IS| INTO TABLE et_requested_orig_elements.
    ENDIF.
  • Make the fields read only in the Behavior definition

          Behavior%20Definition%20for%20the%20Virtual%20Elements

Behavior Definition for the Virtual Elements

  • Finally you can see that for your user the material item tab will be hidden

Object%20page%20with%20one%20tab%20hidden

Object page with one tab hidden

 

  • Similarly you can hide both the views as well by passing both the virtual element values as true as shown below

Thus you can make use of virtual elements and control the UI annotations and the hide the different UI elements .

 

Assigned Tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo rajesh maripeddi
      rajesh maripeddi

      Hello Vijaya,

       

      Really helpful blog. Can we also hide the columns of List viewer main page according to user using virtual elements. Like for Eg. for some user it should display only 2 columns and for other 3 columns.

      Regards,

      Rajesh

      Author's profile photo Vijaya Chintarlapalli
      Vijaya Chintarlapalli
      Blog Post Author

      Yes rajesh maripeddi you can use it to hide columns as well

      Author's profile photo rajesh maripeddi
      rajesh maripeddi

      Hello @Vijaya Chintarlapalli,

      I have requirement in list report, I have create List report using RAP and when I click on Create button there I have two fields.

      I need to make that second field hidden or non-editable based on the value I will enter in the first field. Is this possible through Virtual elements. I have tried couple of options but could not achieve.

      Can this be achievable using Virtual elements or any other approach.

      Thanks in advance.

      Regards,

      Rajesh

      Author's profile photo Vijaya Chintarlapalli
      Vijaya Chintarlapalli
      Blog Post Author

      rajesh maripeddi : This is not possible using Vitrual elements , you have to go for Custom UI5 option.

      Thanks,

      Vijay

      Author's profile photo Romulo Pacheco
      Romulo Pacheco

      Hello @Vijaya Chintarlapalli

      Is there ANY way to dynamically hide a field on the Create page of a RAP application? (managed scenario)

      I've been running through several articles about this topic, but no one seems to talk about the Create standard action page. Looks like this page isn't affected by any kind of annotations.

      Awesome post btw, congrats!

       

      Regards,

      Rômulo