Dynamic UI Generation in Web Dynpro ABAP
How Come!!!. That was my first reaction when I saw the view layout of a webdynpro for abap component as
While output was:
And that was my first day when I heard about dynamic UI generation from my Beautiful team lead. It goes like:
There are classes for each UI element in webdynpro for ABAP
( I.e. CL_WD_CHECKBOX , CL_WD_CHECKBOX_GROUP, CL_WD_INPUT_FIELD etc..)
One can add this created UI element object to the current View in WDDOMODIFYVIEW method of the view.
Let’s start with simple creation of Tray UI element in the View.
Exercise 1:
Create Tray UI element in the view.
Solution:
Create a Webdynpro component using transaction code Se80 and in the MAIN view create a transparent container named
TC_MAIN with flow layout. ( It’s a not mandatory to create it but it’s a good practice to create such transparent container
as it can be helpful if you are planning to change the layout of your view etc.. )
All the dynamic generated UI elements will be placed over this transparent container.
Put the below code in your WDDOMODIFYVIEW method of the view and your tray UI Element will be ready.
method WDDOMODIFYVIEW .
"Let's Create Tray
data : lr_tray type REF TO cl_wd_tray.
data : lr_caption TYPE REF TO cl_wd_caption.
DATA : lr_container TYPE REF TO cl_wd_uielement_container.
data : lr_flow type ref to cl_wd_flow_data.
data : lr_matrix_layout type REF TO cl_wd_matrix_layout.
"As we are gonna put the tray in TC_MAIN ( the transperant container )
"fetch it ...
lr_container ?= view->get_element( 'TC_MAIN' ).
"Create a Tray Object
CALL METHOD CL_WD_TRAY=>NEW_TRAY
EXPORTING
ID = 'TR_TRAY'
WIDTH = '100%'
RECEIVING
CONTROL = lr_tray.
"Need to Assign the flow layout information for this Tray
"As it is part if ROOTUIELEMENTCONTAINER ( with layout flow )
lr_flow = cl_wd_flow_data=>new_flow_data( lr_tray ).
lr_tray->set_layout_data( lr_flow ).
"" add tray to container
CALL METHOD lr_container->add_child
EXPORTING
the_child = lr_tray.
"' set layout of tray
CALL METHOD cl_wd_matrix_layout=>new_matrix_layout
EXPORTING
container = lr_tray
RECEIVING
control = lr_matrix_layout.
CALL METHOD cl_wd_caption=>new_caption
EXPORTING
id = 'CA_TRAY'
text = 'Yahoo... Here is my Tray (*_*)'
RECEIVING
control = lr_caption.
"' set header for tray
CALL METHOD lr_tray->set_header
EXPORTING
the_header = lr_caption.
endmethod.
Save , Activate and RUN
Exercise 2:
Add an input field in the tray with label attached to that input field and a button at bottom.
Solution:
As the input field’s Value property needs to be bind with View context node attribute, we need to create context node/attribute too.
In case of input field UI Element.
Create A method in Component controller Named: RET_CC_CONTEXT.
Exporting parameter : ER_CONTEXT type ref to IF_WD_CONTEXT_NODE.
Put the below code in your WDDOMODIFYVIEW method and Run it Again.
If you see an Error while activation,scratch your head read the error description and solve it!
method WDDOMODIFYVIEW .
"Let's Create Tray
data : lr_tray type REF TO cl_wd_tray.
data : lr_caption TYPE REF TO cl_wd_caption.
DATA : lr_container TYPE REF TO cl_wd_uielement_container.
data : lr_flow type ref to cl_wd_flow_data.
data : lr_matrix_layout type REF TO cl_wd_matrix_layout.
"As we are gonna put the tray in TC_MAIN ( the transperant container )
"fetch it ...
lr_container ?= view->get_element( 'TC_MAIN' ).
"Create a Tray Object
CALL METHOD CL_WD_TRAY=>NEW_TRAY
EXPORTING
ID = 'TR_TRAY'
WIDTH = '100%'
RECEIVING
CONTROL = lr_tray.
"Need to Assign the flow layout information for this Tray
"As it is part if ROOTUIELEMENTCONTAINER ( with layout flow )
lr_flow = cl_wd_flow_data=>new_flow_data( lr_tray ).
lr_tray->set_layout_data( lr_flow ).
"" add tray to container
CALL METHOD lr_container->add_child
EXPORTING
the_child = lr_tray.
"' set layout of tray
CALL METHOD cl_wd_matrix_layout=>new_matrix_layout
EXPORTING
container = lr_tray
RECEIVING
control = lr_matrix_layout.
CALL METHOD cl_wd_caption=>new_caption
EXPORTING
id = 'CA_TRAY'
text = 'Yahoo... Here is my Tray (*_*)'
RECEIVING
control = lr_caption.
"' set header for tray
CALL METHOD lr_tray->set_header
EXPORTING
the_header = lr_caption.
"****************Create Input field ********************************
"create Node And Element for input field
"Part 1: stracture creation : with one field called name
TYPE-POOLS: abap.
DATA :
lt_components TYPE abap_component_tab,
lw_component TYPE LINE OF abap_component_tab,
lr_structdescr type ref to CL_ABAP_STRUCTDESCR,
lt_attribs TYPE wdr_context_attr_info_map,
ls_attribs like LINE OF lt_attribs.
lw_component-name = 'NAME'.
TRY.
lw_component-type = cl_abap_elemdescr=>get_c( p_length = 20 ).
CATCH cx_sy_move_cast_error .
ENDTRY.
append lw_component to lt_components.
lr_structdescr = cl_abap_structdescr=>create( lt_components ).
"Part2 : Now Create a Node based on this Dynamic struct.
DATA:
lo_parent_node_info TYPE REF TO if_wd_context_node_info,
lo_child_node_info TYPE REF TO if_wd_context_node_info,
* lo_nd_gen_tab TYPE REF TO if_wd_context_node,
lt_child_node_map TYPE wdr_context_child_info_map,
comp_context type ref to if_wd_context_node.
FIELD-SYMBOLS : <fs_stru> TYPE any .
* DATA dy_stru TYPE REF TO data.
wd_comp_controller->ret_cc_context(
IMPORTING
er_context = comp_context ).
lo_parent_node_info = comp_context->get_node_info( ).
lt_child_node_map = lo_parent_node_info->get_child_nodes( ).
READ TABLE lt_child_node_map TRANSPORTING NO FIELDS WITH TABLE KEY name = 'ND_DETAIL'.
IF sy-subrc = 0.
" REMOVE_CHILD_NODE
lo_parent_node_info->remove_child_node( 'ND_DETAIL' ).
ENDIF.
"" get attrib property
LS_ATTRIBS-name = 'NAME'.
insert ls_attribs into table lt_attribs.
" create Node in Comp Controller
CALL METHOD lo_parent_node_info->add_new_child_node
EXPORTING
name = 'ND_DETAIL'
is_singleton = abap_true
static_element_rtti = lr_structdescr
is_static = abap_true
attributes = lt_attribs
RECEIVING
child_node_info = lo_child_node_info.
DATA lr_wa TYPE REF TO data.
data lo_child_node_detail TYPE ref to if_wd_context_node.
FIELD-SYMBOLS <lfs_dyn> TYPE any.
CREATE DATA lr_wa TYPE HANDLE lr_structdescr.
ASSIGN lr_wa->* TO <lfs_dyn>.
lo_child_node_detail = comp_context->get_child_node( name = 'ND_DETAIL' ).
lo_child_node_detail->bind_structure( EXPORTING new_item = <lfs_dyn> ).
" Map that component controller node to View
DATA: lo_node_info TYPE REF TO if_wd_context_node_info,
lo_node TYPE REF TO if_wd_context_node,
mapping_info TYPE wdr_context_mapping_info,
lv_name TYPE string,
lt_path TYPE wdr_ctx_element_path_segments.
DATA map_path TYPE string.
CLEAR lt_path.
""
DATA:
lr_child_node_info_view TYPE REF TO if_wd_context_node_info,
lt_child_node_map_view TYPE wdr_context_child_info_map.
lo_node_info = WD_CONTEXT->get_node_info( ).
lv_name = 'ND_DETAIL'.
lt_child_node_map_view = lo_node_info->get_child_nodes( ).
READ TABLE lt_child_node_map TRANSPORTING NO FIELDS WITH TABLE KEY name = 'ND_DETAIL'.
IF sy-subrc = 0.
" REMOVE_CHILD_NODE
lo_node = wd_context->get_child_node( name = 'ND_DETAIL' ).
lr_child_node_info_view = lo_node->get_node_info( ).
RETURN.
ELSE.
ENDIF.
CONCATENATE 'COMPONENTCONTROLLER.' lv_name INTO map_path.
APPEND map_path TO lt_path.
mapping_info-controller = 'COMPONENTCONTROLLER'. "conponent name
mapping_info-path = lt_path. "Controller context node name
"" create view node refering component node
CALL METHOD lo_node_info->add_new_mapped_child_node
EXPORTING
child_name = lv_name
mapping_info = mapping_info
is_static = abap_true
RECEIVING
child_node_info = lr_child_node_info_view.
"Now Let's Create An input field along with the label and put it in Try
"Bind the inout field with the Name element of ND_DETAIL Node we created
DATA lr_input TYPE REF TO cl_wd_input_field..
DATA lr_matrix_data TYPE REF TO cl_wd_matrix_data.
DATA lr_matrix TYPE REF TO cl_wd_matrix_head_data.
DATA lv_lbl_id TYPE string.
DATA lv_lbl_txt TYPE string.
DATA lv_lbl_for TYPE string.
DATA lr_label TYPE REF TO cl_wd_label.
DATA inp_id TYPE string.
DATA lv_width TYPE string.
CLEAR : inp_id , lv_width.
CALL METHOD cl_wd_input_field=>new_input_field
EXPORTING
bind_value = 'ND_DETAIL.ND_DETAIL.NAME'
id = 'IF_NAME'
input_prompt = 'Enter Name'
RECEIVING
control = lr_input.
"" create lbl for Input field
CALL METHOD cl_wd_label=>new_label
EXPORTING
id = 'LBL_NAME'
label_for = 'IF_NAME'
text = 'Name'
RECEIVING
control = lr_label. " CONTROL
lr_matrix = cl_wd_matrix_head_data=>new_matrix_head_data( lr_label ).
lr_label->set_layout_data( lr_matrix ).
lr_matrix_data = cl_wd_matrix_data=>new_matrix_data( lr_input ).
lr_input->set_layout_data( lr_matrix_data ).
"Let's Add this couple to the Try
"' get tray as container
lr_container ?= view->get_element( 'TR_TRAY' ).
"" add label and Input field to Tray
CALL METHOD lr_container->add_child
EXPORTING
the_child = lr_label.
CALL METHOD lr_container->add_child
EXPORTING
the_child = lr_input.
"Now let's Create a button and add it to Tray
data : lr_button type REF TO cl_wd_button.
CALL METHOD CL_WD_BUTTON=>NEW_BUTTON
EXPORTING
IMAGE_SOURCE = '~Icon/Search'
on_action = 'PROCESS_EVENT'
ID = 'BTN_SEARCH'
TEXT = 'Sumit'
RECEIVING
CONTROL = lr_button.
"as we want this button to come on new line make it matrix head data
lr_matrix = cl_wd_matrix_head_data=>new_matrix_head_data( lr_button ).
lr_button->set_layout_data( lr_matrix ).
"" add Button to Tray
CALL METHOD lr_container->add_child
EXPORTING
the_child = lr_button.
endmethod.
- SAVE, Activate and Run
If you are not bored ….Try this
Exercise 3:
Get the Value user has entered in Name field and on click of the Button SEARCH Display it in popup.
Note: You need to implement the ONACTIONPROCESS_EVENT Method Which is we have bind with the Search button.
Happy Coding….
Hi Raju Borda,
I am seeing small kid in your screen output, Is this lengthy abap code to generate a small kid in ur output.??