Skip to Content
Technical Articles

Using Virtual Elements with CDS in Fiori elements

Overview

In this post you will learn, how we can use ‘READ_TEXT’ function for Fiori elements application. Consumption CDS is generating the Fiori elements application but sometimes we need Abap Logic calculation. (Calculate field values using Abap resources one of them read text belongs to material or orders etc.).

In this case, we can use the CDS with Virtual Element.

What are the Virtual Elements and Why we use that?

Sometimes when we make a report, we need calculations for fields and we can not easily make calculations with CDS so that their values can be calculated directly on SAP HANA. Virtual elements represent temporary fields in applications. They are defined consumption CDS view with annotations within the SELECT list. However, the field calculations display by Abap classes that implement the specific code exit interfaces provided for this purpose.

The code exit class for virtual elements. We should implement suitable interfaces according to the use case;

You can find more information about Virtual Element with Sap standard documents link.

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.7/en-US/a7fc007921d44263b09ccc092392b05f.html

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.6/en-US/8cbf576babc348668d00b93387612a1c.html

 

Implementation Steps:

 

  1. Use Eclipse for creating CDS View. Use Virtual element in CDS with annotations.

You can find more information about create the CDS View for beginners.

https://blogs.sap.com/2019/11/07/developing-app-with-sap-fiori-elements-list-report-page-object-page-using-cds-view-and-annotations-abap-programming-model-on-sap-s-4-hana./

 

CDS View;

@AbapCatalog.sqlViewName: 'ZI_V_GOODPACK'

@AbapCatalog.compiler.compareFilter: true

@AbapCatalog.preserveKey: true

@AccessControl.authorizationCheck: #CHECK

@EndUserText.label: 'Goodpack Series No - Basic View'


@OData: { publish: true }


@UI.headerInfo:{ typeNamePlural: 'GoodPack'}

define view ZI_GOODPACK


  as select from    likp             as l1

    inner join      lips             as l2 on  l2.vbeln = l1.vbeln and l2.pstyv = 'ZPAC'

    left outer join kna1             as k1 on k1.kunnr = l1.kunnr

    left outer join vbfa             as v1 on  v1.vbelv   = l1.vbeln and v1.vbtyp_n = '8'

    left outer join vttk             as v2 on v2.tknum = l1.vbeln

    left outer join /scdl/db_proch_o as t1 on t1.docno = l1.vbeln

    left outer join /scwm/huref      as t2 on t2.docid = t1.docid

    left outer join /scwm/hu_ident   as t3 on  t3.guid_hu = t2.guid_hu and t3.idart   = 'Y'

    left outer join lips             as l3 on l3.vbeln = l1.vbeln

    left outer join vbrp             as v4 on  v4.vgbel = l1.vbeln and v4.vgpos = l3.posnr

    left outer join vbrk             as v5 on  v5.vbeln = v4.vbeln and sfakn    = ''


{


      @UI: { lineItem: [ { position: 10, label: 'Delivery'} ]}

  key l1.vbeln,


      @UI.hidden: false

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

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_VKORGSH',element:'vkorg'}}]

      @Consumption.filter : { selectionType : #RANGE, multipleSelections : true, defaultValue : '1250'}

      l1.vkorg,


      @UI.hidden: false

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

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_WERKSSH',element:'werks'}}]

      l1.werks,


      @UI: { lineItem: [ { position: 20, label: 'Customer'} ]}

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

      @Consumption.valueHelpDefinition:[{entity:{name:'ZI_KUNNRSH',element:'kunnr'}}]

      l1.kunnr,


      @UI: { lineItem: [ { position: 30, label: 'Customer Name'} ]}

      concat( concat( k1.name1, ' '), k1.name2 ) as name1,


      @UI: { lineItem: [ { position: 40, label: 'Delivery Note'} ]}

      l1.xblnr,


      @UI: { lineItem: [ { position: 40, label: 'Container ID'} ]}

      v2.signi,


      @UI: { lineItem: [ { position: 50, label: 'Actual Goods Movement Date'} ]}

      l1.wadat_ist,


      @UI: { lineItem: [ { position: 60, label: 'Material Number'} ]}

      l2.matnr,


      @UI: { lineItem: [ { position: 70, label: 'Short text for sales order item'} ]}

      l2.arktx,


      @UI: { lineItem: [ { position: 80} ]}

      v1.vbeln                                   as vbfa_vbeln,


      @UI: { lineItem: [ { position: 90} ]}

      t4.konsimento_tarih,

      @UI: { lineItem: [ { position: 100} ]}

      t4.konsimento_no,


      @UI: { lineItem: [ { position: 110, label: 'Virtual Element'} ]}

      @ObjectModel.virtualElement: true

      @ObjectModel.virtualElementCalculatedBy: 'ZCL_DEMO_CDS_CALC'

      cast( ''  as abap.char(255))               as note


}

group by

  l1.vbeln,

  l1.vkorg,

  l1.werks,

  l1.kunnr,

  k1.name1,

  k1.name2,

  l1.xblnr,

  l1.wadat_ist,

  l2.matnr,

  l2.arktx,

  v1.vbeln,

  v2.signi,

  t2.guid_hu,

  t3.huident,

  t4.konsimento_tarih,

  t4.konsimento_no

 

Define relationship with CDS, ODATA and Custom Class.


2. Create custom class and implement intarface ‘IF_SADL_EXIT_CALC_ELEMENT_READ’.   Implement both methods ‘GET_CALCULATE_INFO’ and ‘CALCULATE’.

  • Method GET_CALCULATION_INFO is used to provide the list of fields which is required for the calculation.
  • Method CALCULATE is actual method where we implement the custom logic.

  • Implementation Step 1 : We called custom class in CDS view.
       @ObjectModel.virtualElement: true

       @ObjectModel.virtualElementCalculatedBy: 'ZCL_DEMO_CDS_CALC'

       cast( ''  as abap.char(255))  as note

 

Use the CALCULATE method for utilizing ABAP resource.

3. Use SAP Web IDE for creating List Reporting App.

You can find detail information about List Reporting App.

https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/1709%20000/en-US/8dec506e13f949c2a82e8c775a94b73b.html

Output

Conclusion

In this blog, we learn how we can utilize the CDS virtual elements. I welcome all suggestions for improvement or questions. Thanks for reading.


References

http://sapabapcentral.blogspot.com/2019/04/fiori-elements-utilizing-cds-with.html

https://blogs.sap.com/2019/04/26/fiori-elements-utilizing-cds-with-virtual-elements

 

Canan Özdemir.

18 Comments
You must be Logged on to comment or reply to a post.
    • Hello Sandra Rossi,

      You can check the this links;

      https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/7.51.6/en-US/04e64a8ffffe49b8a8a5469796f397c0.html

      https://help.sap.com/viewer/923180ddb98240829d935862025004d6/Cloud/en-US/c65942c284dd490a9c3791630d4d4e41.html

      get_calculation_info: This method is called before the actual data retrieval.
      It ensures that all the relevant elements that are needed for the calculation of the virtual element are selected.

      I followed basic example and tried use to “GET_CALCULATION_INFO” method.
      But ı want to say; ı wrote ‘price’ in “get_calculation_info” method but I could use without writing.
      I am not sure about using this method.

      CDS CODE;

      @AbapCatalog.sqlViewName: ‘ZDEMO_CDS_V_005’
      @AbapCatalog.compiler.compareFilter: true
      @AccessControl.authorizationCheck: #CHECK
      @EndUserText.label: ‘CDS to Test Access Control’

      @OData: {
      publish: true
      }
      define view ZDEMO_CDS_005
      as select from sflight as a
      inner join sflconnpos as b on a.carrid = b.carrid
      {
      key $session.user as MyName,
      key a.carrid as MyFlightCarrier,
      b.agencynum as MyAgencyNumber,
      a.fldate,
      a.connid,

      @UI: { lineItem: [ { position: 110, label: ‘Virtual Element’} ]}
      @ObjectModel.virtualElement: true
      @ObjectModel.virtualElementCalculatedBy: ‘ABAP:ZCL_DEMO_CDS_CALC’
      cast( ” as abap.char(255)) as note,

      @Semantics.amount.currencyCode: ‘CURRENCY’
      CURRENCY_CONVERSION(
      amount => price,
      source_currency => currency,
      target_currency => cast( ‘EUR’ as abap.cuky ),
      exchange_rate_date => a.fldate,
      error_handling => ‘SET_TO_NULL’ ) as price,

      @Semantics.currencyCode: true
      cast( ‘EUR’ as abap.cuky ) as currency

      }

      where a.carrid = ‘AA’ and a.fldate = ‘20170706’

      ABAP CODE;
      METHOD if_sadl_exit_calc_element_read~get_calculation_info.
      LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_calc_element>).
      CASE <fs_calc_element>.
      WHEN ‘NOTE’.
      APPEND ‘PRICE’ TO et_requested_orig_elements.
      ENDCASE.
      ENDLOOP.
      ENDMETHOD.

      METHOD if_sadl_exit_calc_element_read~calculate.

      DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
      DATA lt_original_data TYPE STANDARD TABLE OF ZDEMO_CDS_V_005 WITH DEFAULT KEY.

      lt_original_data = CORRESPONDING #( it_original_data ).

      LOOP AT lt_original_data ASSIGNING FIELD-SYMBOL(<fs_original_data>).

      IF <fs_original_data>-price GT 1000.
      <fs_original_data>-note = | High Price|.
      ELSE.
      <fs_original_data>-note = | Low Price|.
      ENDIF.

      ENDLOOP.

      ct_calculated_data = CORRESPONDING #( lt_original_data ).

      ENDMETHOD.

      • I was more looking for some code related to the code you have posted in your post but thank you. I guess the code related to your post should be something like that (in your example, the field NOTE is calculated based on input fields SPRAS and VBELN):

        METHOD if_sadl_exit_calc_element_read~get_calculation_info.
          IF iv_entity <> 'ZI_GOODPACK'.
            RAISE EXCEPTION TYPE /dmo/cx_calc_exit. " any class inheriting from CX_SADL_EXIT
          ENDIF.
          LOOP AT it_requested_calc_elements ASSIGNING FIELD-SYMBOL(<fs_calc_element>).
            CASE <fs_calc_element>.
              WHEN 'NOTE'.
                APPEND 'SPRAS' TO et_requested_orig_elements.
                APPEND 'VBELN' TO et_requested_orig_elements.
              WHEN OTHERS.
                RAISE EXCEPTION TYPE /dmo/cx_calc_exit.
            ENDCASE.
          ENDLOOP.
        ENDMETHOD.
    • Hello Mahesh Kumar Palavalli,

      Thank you for advice, if I saw this block I added it as a reference. I will added link.

      Best regards.

      Canan Özdemir.

  • Hi Canan,

    Great blog with great explanation.

    I have question, in this blog you are using virtual element to display data from the back end to the report in FIORI. My question is, is it possible to use virtual element to hold data input by user, in the form for example, and then post to SAP?

    Regards,

    Tj

    • Hello Tjarliman Rusadi,

      Thank you for comment. I tried to answer the question as far as I understand.
      Can you explain much more hold data input by user ?

      We created Abap class and implemented IF_SADL_EXIT_CALC_ELEMENT_READ fo using Virtual Elements.
      It is exit and call automaticly when you run report.

      * If you create a form and send data to SAP with button;
      you should use different class. You have 2 options for List Report;

      1- You can create button and BOPF business object action in CDS view and give action name for button press event.
      In this case your class created automaticly with action and you can write to code.

      @UI.lineItem:
      [
      { type: #FOR_ACTION, position: 2, dataAction: ‘BOPF:ZACTIONTEST’, label: ‘Testt’ }
      ]

      2- You can create extention button and call your custom oData Service.

      * When push to search button for display table’s data and in that time If you want to save table’s data you can use Virtual Elements class.
      if it is independent of this, you should use a new class.

       

      Best regards.

      Canan Özdemir.

      • Hi Canan,

        Thanks for replying. Really sorry it’s been a while replying to you.

        To your question about ‘hold user’s input data’ in the form.

        Actually, i have a list report application of material master, and the source data is from MARA table, etc. Based on that table i created CDS, and web service based on that CDS was created.

        This app has the capabilities of create data as well with draft capabilities, so user can enter data in a form and save it by clicking standard button, and save those data into a custom table.

        But now, user want to input some additonal data in the form, and these data is not exist in the std table which I chose to be as based table for my CDS (MARA, etc).

        So my questiom is, how can I add those additional fields in my CDS (or in my web servive) as they dont exist in any tables?. Can I use this virtual element concept to add these fields especially in the form so user can enter values to it, and then later save it into a custom table.

        Hopefully it is clear to you.

         

        Thanks

        Tj