CRM and CX Blogs by SAP
Stay up-to-date on the latest developments and product news about intelligent customer experience and CRM technologies through blog posts from SAP experts.
cancel
Showing results for 
Search instead for 
Did you mean: 
dmitry_sharshatkin
Active Participant


 

 

Update view fields via AJAX call



Use Case


When doing some applications one may need to update certain fields on the screen without calling a back-end. In this case, the use of AJAX functionality of CRM WebUI can be useful. In this document, we will describe how one can update all the configured fields on the view.


Let us assume we have a view with Order Summary information, including Gross Value, Net Value, Tax Amount, Number of Items and Gross Weight.




 


On BSP level, it look like below:










<%@page language="abap" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="thtmlb" prefix="thtmlb" %>

<chtmlb:config displayMode =
"FALSE"
mode        =
"RUNTIME" />




Required JavaScript


As described before (see: http://scn.sap.com/community/crm/webclient-ui-framework/blog/2015/12/11/parallelization-in-web-ui--p...), we need a function which calls an AJAX request and the functionality which will be called after the request is executed, i.e. a callback function.


As before, we will be using a standard method thtmlbAJAXCall.callBackendin order to call a back-end handler.










<script language="javascript" type="text/javascript">

function UpdateTotals()
{
var ajax_url = "<%= controller->create_ajax_url( ) %>";
thtmlbAJAXCall.callBackend(ajax_url,UpdateTotalsCallback);
}



</script>




In this case, we will use our own callback function, which will be expecting the data in JSON format. Basically it expects a table with two columns: NAME and VALUE. NAME will be a unique id of the field (e.g. C18_W65_V67_V69_btcumulath_struct.gross_value) and VALUE is the text, which needs to be placed into the field.










<script language="javascript" type="text/javascript">

function UpdateTotalsCallback(reqObj)
{
var responseText = reqObj.request.responseText;
var obj = JSON.parse(responseText);
var fnum = obj.TEXT.length;
for (var i = 0; i < fnum; i++) {
var elem = document.getElementById(obj.TEXT[i].NAME);
if (elem){
elem.title = obj.TEXT[i].VALUE;
elem.value = obj.TEXT[i].VALUE;
}
}
}


</script>




Required ABAP code


For consistency we also place a full ABAP code, including the one needed to generate the AJAX URL.










method create_ajax_url.

data: lr_class_desc    type ref to cl_abap_typedescr.
data: lv_class_name    type string.

lr_class_desc
= cl_abap_classdescr=>describe_by_object_ref( me ).
lv_class_name
= lr_class_desc->get_relative_name( ).

call method cl_crm_web_utility=>create_service_url
exporting
iv_handler_class_name
= lv_class_name
iv_controller_id     
= me->component_id
receiving
ev_url               
= rv_url.

endmethod.




Below you can find a sample of callback handler.










  method if_crm_web_callback~handle_request.

data: lr_controller      type ref to zl_zdmsh_pr_totals_impl.
data: lr_model           type ref to if_bsp_model_binding.
data: lr_context_node    type ref to cl_bsp_wd_context_node.
data: lr_descr           type ref to if_bsp_dlc_view_descriptor.
data: lv_xml             type bsp_dlc_xml.
data: lt_bsp_fields      type bsp_dlct_adv_conf_itm.
data: lt_field_list      type table of crmt_rtd_string_pair.

data: lv_node            type string.
data: lv_attribute_path  type string.

data: lr_writer          type ref to cl_sxml_string_writer.
data: lv_json            type xstring.


field-symbols:
<fs_bsp_field
type bsp_dlcs_adv_conf_itm,
<fs_field_list>
type crmt_rtd_string_pair.


check ir_controller is bound.

try.
lr_controller ?= ir_controller
.
catch cx_root.
endtry.

check lr_controller is bound.

" Get Personalization
lr_descr
= lr_controller->configuration_descr->get_property_descriptor( ).
lv_xml  
= lr_controller->configuration_descr->get_config_data( ).

" Get Available BSP Fields
call method cl_bsp_dlc_config_util=>adv_conf_meta_to_table
exporting
ir_view_descr       
= lr_descr
iv_adv_conf_meta_xml
= lv_xml
importing
et_adv_conf         
= lt_bsp_fields.

" Loop At BSP Fields
loop at lt_bsp_fields assigning <fs_bsp_field> where type = 'FIELD'.

" Get Model Data
call method cl_bsp_model=>if_bsp_model_util~split_binding_expression
exporting
binding_expression
= <fs_bsp_field>-field_name
importing
attribute_path    
= lv_attribute_path      " Property
model_name        
= lv_node.               " Context Node

try.
" Get BSP Model
lr_model ?= ir_controller
->get_model( lv_node ).

" Check Context Node
lr_context_node  ?= lr_model
.

append initial line to lt_field_list assigning <fs_field_list>.

<fs_field_list>
-name  = lr_model->get_attribute_name( lv_attribute_path ).
<fs_field_list>
-value = lr_model->get_attribute( attribute_path = lv_attribute_path ).

catch: cx_root.
continue.
endtry.

endloop.

"ABAP to JSON
lr_writer
= cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
call transformation id source text = lt_field_list[] result xml lr_writer.
lv_json
= lr_writer->get_output( ).


" Set Response
ir_server
->response->set_data( lv_json ).
ir_server
->response->set_header_field( name  = 'content-type'
value = 'text/xml' ).


endmethod.




One can note that our coding (we are talking about ABAP and JavaScript together) is very generic. It does not depend on the selected model and context nodes. It is also performance and logically optimized, as we are processing only the fields, which are present on the screen (as per WebUI configuration), and not the possible ones.


Hope it can help someone to build modern usability- and performance- optimized applications in WebUI.