Introduction

The purpose of this blog is to explain how we can easily use AJAX to trigger asynchronous HTTP requests in Web UI Tableviews.

There are several blogs available on SAP Community about AJAX implementations in the Web UI but this blog focuses on Tableview integration.

Use cases for such implementation are unlimited but the current use case is the following:

In the Business Partner’s Identification Numbers assignment block we maintain the National Register ID of B2C customers (in a custom ID Type). For GDPR reasons, this value is encrypted before it is stored in the database table. But there is a business requirement to allow some agents seeing the decrypted ID. For performance reason and to avoid reloading the whole page, an asynchronous HTTP request is triggered to display the decrypted ID.

Remark: how is this ID first encrypted is not part of the scope of this blog. What is important to know is that encryption/decryption is done by an external API.

screenshot

Figure 1 – Final result

 

As a starting point I used the excellent blog from Jerry Wang:

How to implement and debug AJAX functionality in Webclient UI component

 

Realization

Summary of the steps:

  • Enhancement of the standard Web UI Component/View
  • Creation of a custom Tableview Iterator
  • Creation of a custom HTTP Handler Class and SICF service

 

Enhancement of the standard Web UI Component/View

Component: BP_DATA, View: AccountIDNumberList

Creation of a custom Tableview Iterator

Create a new custom Class (e.g. ZL_BP_DATA_ACCOUNTIDNUMB1_IT) implementing interface IF_HTMLB_TABLEVIEW_ITERATOR

iterator

Figure 2 – Iterator

 

Create attribute GR_CONTEXT_NODE_TV type ref to CL_BSP_WD_CONTEXT_NODE_TV

Implement method Constructor

  METHOD CONSTRUCTOR.

    gr_context_node_tv = ir_context_node_tv.

  ENDMETHOD.

 

Implement method IF_HTMLB_TABLEVIEW_ITERATOR~RENDER_CELL_START

Thanks to this method we can generate the HTML DOM elements required to execute the Javascript:
-THTMLB Button: triggers the AJAX Request (lr_button->onclientclick)
-THTMLB Textview: displays the AJAX Response text. The generated <span> HTML DOM element is uniquely identified within the table (lr_textview->id)

  METHOD if_htmlb_tableview_iterator~render_cell_start.

    DATA: lv_ident_type TYPE string,
          lv_ident_code TYPE string,
          lv_txtid_s    TYPE string,
          lv_txtid_l    TYPE string,
          lv_index      TYPE char2,
          lr_button     TYPE REF TO cl_thtmlb_button,
          lr_textview   TYPE REF TO cl_thtmlb_textview.

* Check that Identification Number Row Type is 'National Register ID'
    lv_ident_type = gr_context_node_tv->collection_wrapper->find( iv_index = p_row_index )->get_property_as_string( 'IDENTIFICATIONTYPE' ).
    CHECK lv_ident_type EQ 'ZNATID'.

    MOVE p_row_index TO lv_index.

* Generate the suffix and the full DOM element ID for the table row Texview (in this case: ‘<span>’)
    CONCATENATE 'TXT.ZNATID.' lv_index INTO lv_txtid_s.
    MOVE p_tableview_id TO lv_txtid_l.
    REPLACE FIRST OCCURRENCE OF 'Table' IN lv_txtid_l WITH lv_txtid_s.

    CASE p_column_key.

* Add Button 'Decrypt' in column <STRUCT.ATTR1>
      WHEN '<STRUCT.ATTR1>'.
        lv_ident_code = gr_context_node_tv->collection_wrapper->find( iv_index = p_row_index )->get_property_as_string( 'IDENTIFICATIONNUMBER' ).
        CREATE OBJECT lr_button.
        lr_button->onclientclick = |doDecryptID('| && lv_ident_code && |','| && lv_txtid_l && |')|.
        lr_button->text = TEXT-001.
        p_replacement_bee     = lr_button.

* Add Textview in column <STRUCT.ATTR2>
      WHEN '<STRUCT.ATTR2>'.
        CREATE OBJECT lr_textview.
        lr_textview->id = lv_txtid_s.
        p_replacement_bee = lr_textview.

    ENDCASE.

  ENDMETHOD.

Where <STRUCT.ATTR1> and <STRUCT.ATTR2> are two attributes of the Tableview Context Node, either standard or custom. These two attributes must be added to the View Configuration. In this case these attributes represent columns ‘Custom Actions’ and ‘Decrypted ID’

Two parameters are passed to the Javascript function ‘doDecryptID(’:
lv_ident_code = encrypted ID (value of the inputfield ‘Identification Number’)
lv_txtid_l = unique identifier of the ‘<span>’ HTML DOM element in the client HTML page

 

Methods IF_HTMLB_TABLEVIEW_ITERATOR~GET_COLUMN_DEFINITIONS and IF_HTMLB_TABLEVIEW_ITERATOR~RENDER_ROW_START can remain empty

 

Adjust View Controller

On the enhanced Controller Class (Z…_IMPL), create attribute ITERATOR type ref to ZL_BP_DATA_ACCOUNTIDNUMB1_IT

controller

Figure 3 – Controller

Redefine and implement method DO_INIT_CONTEXT

  METHOD do_init_context.

    CALL METHOD super->do_init_context.

    CREATE OBJECT iterator
      EXPORTING
        ir_context_node_tv = typed_context->builidnumber.

  ENDMETHOD.

If you have enhanced the Context Node, of course you have to pass the enhanced one:
ztyped_context->zbuilidnumber

Adjust .htm page

(AccountIDNumberList.htm)

Define URL variable for custom SICF service: zcrajax_natid_d

<%
data: lv_url TYPE string,
lv_query type string.
lv_query = 'q='.
lv_url = cl_crm_web_utility=>create_url( iv_path = '/sap/crm/zcrajax_natid_d' iv_query = lv_query iv_in_same_session = 'X' ).
%>

 

Add the following javascript code

<script>
var gv_txtid;

function GetXmlHttpObject(){
 if (window.XMLHttpRequest) {
    return new XMLHttpRequest();
 }
 if (window.ActiveXObject) {
    return new ActiveXObject("Microsoft.XMLHTTP");
 }
 return null;
}

function stateChanged() {
  if (xmlhttp.readyState == 4) {
     document.getElementById(gv_txtid).innerHTML = xmlhttp.responseText;
 }
}

function getRequestURL(str) {
  var url = "<%= lv_url %>" + str;
  url = url + "&sid=" + Math.random();
  return url;
}

function doDecryptID(str,txtid){
 if (str.length == 0 ) {
   document.getElementById(txtid).innerHTML = "";
   return;
 }
 gv_txtid = txtid;
 xmlhttp = GetXmlHttpObject();
 if (xmlhttp == null ){
   alert ("Your browser does not support XML HTTP Request");
   return;
 }
 var requesturl = getRequestURL(str);
 xmlhttp.onreadystatechange = stateChanged;
 xmlhttp.open("GET",requesturl,true);
 xmlhttp.send(null);
}
</script>

(This code could be included in a .js file uploaded to the MIMEs Repository)

 

Add standard tag attribute iterator to the BSP Extension Table element (CHTMLB, THTMLB…)

<chtmlb:configTable id                    = "Table"
                    table                 = "//BuilIDNumber/Table"iterator              = "<%= controller->iterator %>"
                    …
                    />

 

Create custom HTTP Handler Class and SICF service

Create new custom HTTP Handler Class (implementing interface IF_HTTP_EXTENSION) and assign it to new custom SICF service that you referenced in the .htm page.

Figure 4 – Handler Class

Tx SICF

Figure 5 – SICF Service

 

Implement method IF_HTTP_EXTENSION~HANDLE_REQUEST

METHOD if_http_extension~handle_request.

  DATA: lv_ident_code TYPE string,
        lv_ident_nr   TYPE string.

  lv_ident_code = server->request->get_form_field( 'q' ).

* call external API to retrieve the decrypted ID from the encrypted ID
********************************************
Call External API
   exporting lv_ident_code (encrypted ID)
   importing lv_ident_nr (decrypted ID)
********************************************  

  server->response->set_cdata( lv_ident_nr ).

ENDMETHOD.

Details of the API call is not documented as it is not the purpose of this blog

 

Conclusion: With a minimum of enhancements it is possible to use AJAX within any Web UI Tableview

 

Please share feedback in a comment

Ask questions about CRM WebClient UI

Read other CRM WebClient UI blog posts

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x