Web UI Data Load Utility – Preferably custom customizing tables
Usually , there is a need for custom customizing tables to accommodate project specific requirements. Uploading the data into these tables through “Table maintenance” can get difficult for each and every table ( if the records are more or more columns are there in table). In such situations , we typically write custom (SE38) programs / LSMW to load the data into these tables using data files. Also, we need to provide GUI access along with Web UI access to maintain these tables.
To overcome all these complexities, I developed a custom Web UI component to facilitate data load for any given custom table ( preferably customizing tables).
Features of this tool:
1. Works with any table.
2. Provided table columns will be displayed dynamically.
2. Uploaded file data will be displayed in the assignment block columns in sequential order of the file data.
3. Works with text and csv files.
4. File data gets saved to the specified table.
However , depending on your additional requirements – like data validation, mismatch of file columns order with table columns order etc, you have to develop further to meet your requirements.
Please follow below steps to develop this component:
Component Details :
Created a component “Z_TABL_UPD” with MainWindow, then created three views – “TableView”, “FileUpload” , “DataView” and an overview page “FileUpdOvrPage”.
Created a custom component “CuCoDataUpd” with context nodes ‘FILEPARAM’ and ‘DBTABLE’ then performed context node binding with views – “FileUpload” view context node ‘FILEPARM’, “TableView” view context node ‘DBTABLE’.
Custom Component “CuCoDataUpd” Details :
OverviewPage “FileUpdOvrPage” Details :
“FileUpload” View Details:
Upload Event Details :
It is same like GS_FILE_UPLOAD component , View VFileUpload , Event “Upload” and Bounded the FILEPARAM context node with custom controller context node.
File Type Selection Event Details :
METHOD eh_onsel_fltyp.
DATA : lv_selection TYPE string,
lr_htmlb_ddlb TYPE REF TO cl_htmlb_event_selection.
IF htmlb_event_ex->event_class EQ ‘CL_HTMLB_EVENT_SELECTION’.
lr_htmlb_ddlb ?= htmlb_event_ex.
lv_selection = lr_htmlb_ddlb->selection.
me->typed_context->fileparam->set_type( attribute_path = ‘//FILEPARAM/TYPE’ value = lv_selection ).
ENDIF.
ENDMETHOD.
“DataView” View Details :
Context Node INIT Method :
METHOD if_bsp_model~init.
DATA:
lr_custom_controller TYPE REF TO zl_z_tabl_u_cucodataupd_impl,
lr_controller TYPE REF TO zl_z_tabl_u_dataview_impl,
lr_coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
lr_entity TYPE REF TO cl_crm_bol_entity,
lr_table TYPE REF TO if_bol_bo_property_access,
lv_table TYPE string,
lv_tabname TYPE ddobjname,
lt_fields TYPE ddfields,
ls_field TYPE dfies,
lt_columns TYPE abap_component_tab,
ls_column TYPE abap_componentdescr,
lr_element TYPE REF TO cl_abap_datadescr,
lr_struct TYPE REF TO cl_abap_structdescr,
lr_itab TYPE REF TO cl_abap_tabledescr,
lr_line TYPE REF TO data,
lr_dref TYPE REF TO data,
lr_value_node TYPE REF TO cl_bsp_wd_value_node,
lr_bo_coll TYPE REF TO if_bol_bo_col.
super->if_bsp_model~init( id = id
owner = owner ).
CHECK owner IS BOUND.
lr_controller ?= owner.
lr_custom_controller = lr_controller->get_cust_controller( ).
gr_cuco ?= lr_custom_controller.
lr_coll_wrapper = lr_custom_controller->typed_context->dbtable->get_collection_wrapper( ).
lr_table ?= lr_coll_wrapper->get_current( ).
lv_table = lr_table->get_property_as_string( iv_attr_name = ‘TBMA_VAL’ ).
lv_tabname = lv_table.
CHECK NOT lv_tabname IS INITIAL.
CALL METHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
LOOP AT lt_fields INTO ls_field.
lr_element ?= cl_abap_elemdescr=>describe_by_data( ls_field-datatype ).
ls_column-name = ls_field-fieldname.
ls_column-type = lr_element.
INSERT ls_column INTO TABLE lt_columns.
ENDLOOP.
gt_columns[] = lt_columns.
* Create the structure type
lr_struct ?= cl_abap_structdescr=>create( p_components = lt_columns p_strict = abap_false ).
* Create data with reference to the type object
CREATE DATA lr_dref
TYPE HANDLE lr_struct.
* Create a value node
CREATE OBJECT lr_value_node
EXPORTING
iv_data_ref = lr_dref.
* Create a BO collection
CREATE OBJECT lr_bo_coll TYPE cl_crm_bol_bo_col.
* Add the value node to the BO collection
lr_bo_coll->add( lr_value_node ).
* Set the collection wrapper
set_collection( lr_bo_coll ).
ENDMETHOD.
GET_TABLE_LINE_SAMPLE Method :
METHOD get_table_line_sample.
DATA:
lr_custom_controller TYPE REF TO zl_z_tabl_u_cucodataupd_impl,
lr_coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
lr_entity TYPE REF TO cl_crm_bol_entity,
lr_table TYPE REF TO if_bol_bo_property_access,
lv_table TYPE string,
lv_tabname TYPE ddobjname,
lt_fields TYPE ddfields,
ls_field TYPE dfies,
lt_columns TYPE abap_component_tab,
ls_column TYPE abap_componentdescr,
lr_element TYPE REF TO cl_abap_datadescr,
lr_struct TYPE REF TO cl_abap_structdescr,
lr_itab TYPE REF TO cl_abap_tabledescr,
lr_line TYPE REF TO data,
lr_dref TYPE REF TO data.
FIELD-SYMBOLS :
<fs_outtab_t> TYPE ANY TABLE,
<fs_outtab_s> TYPE any.
lr_custom_controller ?= gr_cuco.
lr_coll_wrapper = lr_custom_controller->typed_context->dbtable->get_collection_wrapper( ).
lr_table ?= lr_coll_wrapper->get_current( ).
lv_table = lr_table->get_property_as_string( iv_attr_name = ‘TBMA_VAL’ ).
lv_tabname = lv_table.
CHECK lv_tabname IS NOT INITIAL.
CALL METHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
LOOP AT lt_fields INTO ls_field.
lr_element ?= cl_abap_elemdescr=>describe_by_data( ls_field-datatype ).
ls_column-name = ls_field-fieldname.
ls_column-type = lr_element.
INSERT ls_column INTO TABLE lt_columns.
ENDLOOP.
gt_columns[] = lt_columns.
IF lt_columns IS NOT INITIAL.
lr_struct ?= cl_abap_structdescr=>create( p_components = lt_columns p_strict = abap_false ).
lr_itab ?= cl_abap_tabledescr=>create( lr_struct ).
* Create a data with reference to type object
CREATE DATA lr_dref TYPE HANDLE lr_itab.
ASSIGN lr_dref->* TO <fs_outtab_t>.
* Create dynamic work area and assign to FS
CREATE DATA lr_line LIKE LINE OF <fs_outtab_t>.
rv_sample = lr_line.
ENDIF.
ENDMETHOD.
Save Data Method :
METHOD eh_onsave.
DATA:
lr_coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
lr_entity TYPE REF TO if_bol_bo_property_access,
lr_table TYPE REF TO if_bol_bo_property_access,
lv_table TYPE string,
lv_selection TYPE string,
lv_tabname TYPE ddobjname,
lt_fields TYPE ddfields,
ls_field TYPE dfies,
lt_tabledata TYPE REF TO data,
lv_sy_subrc TYPE sy-subrc VALUE 0,
lv_field_name TYPE char40,
lt_dref_seltable TYPE REF TO data,
ls_dref_line TYPE REF TO data,
lt_field TYPE string_table,
lt_field_val TYPE string_table,
lv_last_field TYPE string,
lv_index TYPE i,
lv_tabix TYPE i,
lr_value_node TYPE REF TO cl_bsp_wd_value_node,
lr_res_coll TYPE REF TO if_bol_bo_col,
lv_counter TYPE i,
lv_file_content_string TYPE string,
lr_custom_controller TYPE REF TO zl_z_tabl_u_cucodataupd_impl,
lr_collection TYPE REF TO if_bol_bo_col,
lr_msg_service TYPE REF TO cl_bsp_wd_message_service.
FIELD-SYMBOLS:
<lv_field> TYPE string,
<lv_field_val> TYPE string,
<ls_field> TYPE any,
<fs_dyn_table> TYPE table,
<fs_tabline> TYPE any.
CONSTANTS:
lc_comma TYPE c VALUE ‘,’.
lr_custom_controller = me->get_cust_controller( ).
lr_coll_wrapper = lr_custom_controller->typed_context->dbtable->get_collection_wrapper( ).
lr_table ?= lr_coll_wrapper->get_current( ).
lv_table = lr_table->get_property_as_string( iv_attr_name = ‘TBMA_VAL’ ).
lr_coll_wrapper = lr_custom_controller->typed_context->fileparam->get_collection_wrapper( ).
lr_entity ?= lr_coll_wrapper->get_current( ).
lv_file_content_string = lr_entity->get_property_as_string( iv_attr_name = ‘FILEDATA’ ).
lv_selection = lr_entity->get_property_as_string( iv_attr_name = ‘TYPE’ ).
CHECK lv_table IS NOT INITIAL.
lv_tabname = lv_table.
CALL METHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
SPLIT lv_file_content_string AT cl_abap_char_utilities=>cr_lf INTO TABLE lt_field.
TRY.
CREATE DATA lt_dref_seltable TYPE TABLE OF (lv_tabname) .
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN lt_dref_seltable->* TO <fs_dyn_table>.
TRY.
CREATE DATA ls_dref_line LIKE LINE OF <fs_dyn_table>.
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN ls_dref_line->* TO <fs_tabline>.
lv_counter = 1.
LOOP AT lt_field ASSIGNING <lv_field>.
IF lv_counter EQ 1.
READ TABLE lt_fields INTO ls_field INDEX lv_counter.
CONCATENATE ‘<fs_tabline>-‘ ls_field-fieldname INTO lv_field_name.
ASSIGN (lv_field_name) TO <ls_field>.
<ls_field> = sy-mandt.
lv_counter = lv_counter + 1.
ENDIF.
CASE lv_selection.
WHEN ‘1’.
SPLIT <lv_field> AT cl_abap_char_utilities=>horizontal_tab INTO TABLE lt_field_val.
WHEN ‘2’.
SPLIT <lv_field> AT lc_comma INTO TABLE lt_field_val.
ENDCASE.
LOOP AT lt_field_val ASSIGNING <lv_field_val>.
lv_tabix = sy-tabix.
READ TABLE lt_fields INTO ls_field INDEX lv_counter.
CONCATENATE ‘<fs_tabline>-‘ ls_field-fieldname INTO lv_field_name.
ASSIGN (lv_field_name) TO <ls_field>.
<ls_field> = <lv_field_val>.
lv_counter = lv_counter + 1.
ENDLOOP.
APPEND <fs_tabline> TO <fs_dyn_table>.
lv_counter = 1.
ENDLOOP.
IF NOT <fs_dyn_table>[] IS INITIAL.
CALL FUNCTION ‘ENQUEUE_E_TABLEE’
EXPORTING
mode_rstable = ‘E’
tabname = lv_tabname
* VARKEY =
* X_TABNAME = ‘ ‘
* X_VARKEY = ‘ ‘
* _SCOPE = ‘2’
* _WAIT = ‘ ‘
* _COLLECT = ‘ ‘
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc EQ 0.
MODIFY (lv_tabname) FROM TABLE <fs_dyn_table>.
IF sy-subrc EQ 0.
lr_msg_service = cl_bsp_wd_message_service=>get_instance( ).
lr_msg_service->add_message( iv_msg_type = ‘S’
iv_msg_id = ’00’
iv_msg_number = ‘001’
iv_msg_v1 = ‘Data Saved Successfully’ ).
COMMIT WORK.
ELSE.
ROLLBACK WORK.
ENDIF.
CALL FUNCTION ‘DEQUEUE_E_TABLEE’
EXPORTING
mode_rstable = ‘E’
tabname = lv_tabname.
* VARKEY =
* X_TABNAME = ‘ ‘
* X_VARKEY = ‘ ‘
* _SCOPE = ‘3’
* _SYNCHRON = ‘ ‘
* _COLLECT = ‘ ‘
ENDIF.
ENDIF.
ENDMETHOD.
Display Data :
METHOD do_prepare_output.
DATA:
lr_coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
lr_entity TYPE REF TO if_bol_bo_property_access,
lr_table TYPE REF TO if_bol_bo_property_access,
lv_table TYPE string,
lv_selection TYPE string,
lv_tabname TYPE ddobjname,
lt_fields TYPE ddfields,
ls_field TYPE dfies,
lt_tabledata TYPE REF TO data,
lv_sy_subrc TYPE sy-subrc VALUE 0,
lv_field_name TYPE char40,
lt_dref_seltable TYPE REF TO data,
ls_dref_line TYPE REF TO data,
lt_field TYPE string_table,
lt_field_val TYPE string_table,
lv_last_field TYPE string,
lv_index TYPE i,
lv_tabix TYPE i,
lr_value_node TYPE REF TO cl_bsp_wd_value_node,
lr_res_coll TYPE REF TO if_bol_bo_col,
lv_counter TYPE i,
lv_file_content_string TYPE string,
lr_custom_controller TYPE REF TO zl_z_tabl_u_cucodataupd_impl,
lr_collection TYPE REF TO if_bol_bo_col.
FIELD-SYMBOLS:
<lv_field> TYPE string,
<lv_field_val> TYPE string,
<ls_field> TYPE any,
<fs_dyn_table> TYPE table,
<fs_tabline> TYPE any.
CONSTANTS:
lc_comma TYPE c VALUE ‘,’.
lr_custom_controller = me->get_cust_controller( ).
lr_coll_wrapper = lr_custom_controller->typed_context->dbtable->get_collection_wrapper( ).
lr_table ?= lr_coll_wrapper->get_current( ).
lv_table = lr_table->get_property_as_string( iv_attr_name = ‘TBMA_VAL’ ).
lr_coll_wrapper = lr_custom_controller->typed_context->fileparam->get_collection_wrapper( ).
lr_entity ?= lr_coll_wrapper->get_current( ).
lv_file_content_string = lr_entity->get_property_as_string( iv_attr_name = ‘FILEDATA’ ).
lv_selection = lr_entity->get_property_as_string( iv_attr_name = ‘TYPE’ ).
CHECK lv_table IS NOT INITIAL.
CALL METHOD super->do_prepare_output.
* EXPORTING
* iv_first_time = ABAP_FALSE
lv_tabname = lv_table.
CALL METHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
SPLIT lv_file_content_string AT cl_abap_char_utilities=>cr_lf
INTO TABLE lt_field.
TRY.
CREATE DATA lt_dref_seltable TYPE TABLE OF (lv_tabname) .
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN lt_dref_seltable->* TO <fs_dyn_table>.
TRY.
CREATE DATA ls_dref_line LIKE LINE OF <fs_dyn_table>.
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN ls_dref_line->* TO <fs_tabline>.
lv_counter = 1.
LOOP AT lt_field ASSIGNING <lv_field>.
IF lv_counter EQ 1.
READ TABLE lt_fields INTO ls_field INDEX lv_counter.
CONCATENATE ‘<fs_tabline>-‘ ls_field-fieldname INTO lv_field_name.
ASSIGN (lv_field_name) TO <ls_field>.
<ls_field> = sy-mandt.
lv_counter = lv_counter + 1.
ENDIF.
CASE lv_selection.
WHEN ‘1’.
SPLIT <lv_field> AT cl_abap_char_utilities=>horizontal_tab
INTO TABLE lt_field_val.
WHEN ‘2’.
SPLIT <lv_field> AT lc_comma INTO TABLE lt_field_val.
ENDCASE.
LOOP AT lt_field_val ASSIGNING <lv_field_val>.
lv_tabix = sy-tabix.
READ TABLE lt_fields INTO ls_field INDEX lv_counter.
CONCATENATE ‘<fs_tabline>-‘ ls_field-fieldname INTO lv_field_name.
ASSIGN (lv_field_name) TO <ls_field>.
<ls_field> = <lv_field_val>.
lv_counter = lv_counter + 1.
ENDLOOP.
APPEND <fs_tabline> TO <fs_dyn_table>.
lv_counter = 1.
ENDLOOP.
CREATE OBJECT lr_collection TYPE cl_crm_bol_bo_col.
LOOP AT <fs_dyn_table> ASSIGNING <fs_tabline>.
CREATE OBJECT lr_value_node
EXPORTING
iv_data_ref = ls_dref_line.
lr_value_node->set_properties( <fs_tabline> ).
CALL METHOD lr_collection->add
EXPORTING
iv_entity = lr_value_node.
ENDLOOP.
* Display data
me->typed_context->filedata->set_collection( lr_collection ).
ENDMETHOD.
Passing Table Name to .htm page :
METHOD set_models.
DATA :
lv_table TYPE tabname16,
lr_custom_controller TYPE REF TO zl_z_tabl_u_cucodataupd_impl,
lr_coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,
lr_entity TYPE REF TO cl_crm_bol_entity,
lr_table TYPE REF TO if_bol_bo_property_access,
lv_tabname TYPE ddobjname.
lr_custom_controller = me->get_cust_controller( ).
lr_coll_wrapper = lr_custom_controller->typed_context->dbtable->get_collection_wrapper( ).
lr_table ?= lr_coll_wrapper->get_current( ).
lv_table = lr_table->get_property_as_string( iv_attr_name = ‘TBMA_VAL’ ).
CALL METHOD super->set_models
EXPORTING
view = view.
view->set_attribute(
name = ‘TableName’ “#EC NOTEXT
value = lv_table ).
ENDMETHOD.
Iterator Details :
Created a class ZCL_HTMLB_TABLEVIEW_ITERATOR , added interface IF_HTMLB_TABLEVIEW_ITERATOR implemented Method GET_COLUMN_DEFINITIONS and also implemented CONSTRUCTOR to pass columns data
Iterator Get Column Definitions Method details :
METHOD if_htmlb_tableview_iterator~get_column_definitions.
DATA:
ls_table_view TYPE tableviewcontrol,
lt_table_view TYPE tableviewcontroltab,
lr_filedata TYPE REF TO zl_z_tabl_u_dataview_cn00,
lt_columns TYPE abap_component_tab,
ls_column TYPE abap_componentdescr.
lt_columns[] = gr_filedata->gt_columns[].
LOOP AT lt_columns INTO ls_column.
ls_table_view-columnname = ls_column-name.
ls_table_view-title = ls_column-name.
ls_table_view-wrapping = abap_false.
ls_table_view-width = ‘100px’.
ls_table_view-horizontalalignment = ‘LEFT’.
APPEND ls_table_view TO p_column_definitions.
ENDLOOP.
ENDMETHOD.
Constructor Details :
METHOD constructor.
gr_filedata ?= ir_context_node.
ENDMETHOD.
TableView Details :
GET_V Method
METHOD get_v_tbma_val.
DATA:
ls_map TYPE if_bsp_wd_valuehelp_f4descr=>gtype_param_mapping,
lt_inmap TYPE if_bsp_wd_valuehelp_f4descr=>gtype_param_mapping_tab,
lt_outmap TYPE if_bsp_wd_valuehelp_f4descr=>gtype_param_mapping_tab.
ls_map-context_attr = ‘TBMA_VAL’.
ls_map-f4_attr = ‘TABNAME’.
APPEND ls_map TO: lt_inmap,lt_outmap.
CREATE OBJECT rv_valuehelp_descriptor TYPE
cl_bsp_wd_valuehelp_f4descr
EXPORTING
iv_help_id = ‘AXT_DBTABLE_SEARCH_HELP’
iv_help_id_kind = if_bsp_wd_valuehelp_f4descr=>help_id_kind_name
iv_input_mapping = lt_inmap
iv_output_mapping = lt_outmap.
ENDMETHOD.
Some very nice functionality Laxmana
Thank you Arden 🙂
great info Laxmana!! long time back we got the same requirement but managed some other way.
anyhow good blog.
regards,
ram
Thanks Ram.