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 TYPEREFTO 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 TYPEREFTO zl_z_tabl_u_cucodataupd_impl,
lr_controller TYPEREFTO zl_z_tabl_u_dataview_impl,
lr_coll_wrapper TYPEREFTO cl_bsp_wd_collection_wrapper,
lr_entity TYPEREFTO cl_crm_bol_entity,
lr_table TYPEREFTO 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 TYPEREFTO cl_abap_datadescr,
lr_struct TYPEREFTO cl_abap_structdescr,
lr_itab TYPEREFTO cl_abap_tabledescr,
lr_line TYPEREFTOdata,
lr_dref TYPEREFTOdata,
lr_value_node TYPEREFTO cl_bsp_wd_value_node,
lr_bo_coll TYPEREFTO if_bol_bo_col.
super->if_bsp_model~init(id = id
owner = owner ).
CHECK owner ISBOUND.
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.
CHECKNOT lv_tabname ISINITIAL.
CALLMETHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
LOOPAT 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 INTOTABLE 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
CREATEDATA lr_dref
TYPE HANDLE lr_struct.
* Create a value node
CREATEOBJECT lr_value_node
EXPORTING
iv_data_ref = lr_dref.
* Create a BO collection
CREATEOBJECT 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 TYPEREFTO zl_z_tabl_u_cucodataupd_impl,
lr_coll_wrapper TYPEREFTO cl_bsp_wd_collection_wrapper,
lr_entity TYPEREFTO cl_crm_bol_entity,
lr_table TYPEREFTO 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 TYPEREFTO cl_abap_datadescr,
lr_struct TYPEREFTO cl_abap_structdescr,
lr_itab TYPEREFTO cl_abap_tabledescr,
lr_line TYPEREFTOdata,
lr_dref TYPEREFTOdata.
FIELD-SYMBOLS :
<fs_outtab_t> TYPEANYTABLE,
<fs_outtab_s> TYPEany.
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 ISNOTINITIAL.
CALLMETHOD lr_custom_controller->get_table_fields
EXPORTING
iv_tabname = lv_tabname
IMPORTING
et_fields = lt_fields.
LOOPAT 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 INTOTABLE lt_columns.
ENDLOOP.
gt_columns[] = lt_columns.
IF lt_columns ISNOTINITIAL.
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
CREATEDATA lr_dref TYPE HANDLE lr_itab.
ASSIGN lr_dref->* TO<fs_outtab_t>.
* Create dynamic work area and assign to FS
CREATEDATA lr_line LIKELINEOF<fs_outtab_t>.
rv_sample = lr_line.
ENDIF.
ENDMETHOD.
Save Data Method :
METHOD eh_onsave.
DATA:
lr_coll_wrapper TYPEREFTO cl_bsp_wd_collection_wrapper,
lr_entity TYPEREFTO if_bol_bo_property_access,
lr_table TYPEREFTO 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 TYPEREFTOdata,
lv_sy_subrc TYPE sy-subrc VALUE 0,
lv_field_name TYPE char40,
lt_dref_seltable TYPEREFTOdata,
ls_dref_line TYPEREFTOdata,
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 TYPEREFTO cl_bsp_wd_value_node,
lr_res_coll TYPEREFTO if_bol_bo_col,
lv_counter TYPE i,
lv_file_content_string TYPE string,
lr_custom_controller TYPEREFTO zl_z_tabl_u_cucodataupd_impl,
lr_collection TYPEREFTO if_bol_bo_col,
lr_msg_service TYPEREFTO cl_bsp_wd_message_service.
FIELD-SYMBOLS:
<lv_field> TYPE string,
<lv_field_val> TYPE string,
<ls_field> TYPEany,
<fs_dyn_table> TYPEtable,
<fs_tabline> TYPEany.
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 ISNOTINITIAL.
lv_tabname = lv_table.
CALLMETHOD 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 INTOTABLE lt_field.
TRY.
CREATEDATA lt_dref_seltable TYPETABLEOF(lv_tabname) .
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN lt_dref_seltable->* TO<fs_dyn_table>.
TRY.
CREATEDATA ls_dref_line LIKELINEOF<fs_dyn_table>.
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN ls_dref_line->* TO<fs_tabline>.
lv_counter = 1.
LOOPAT lt_field ASSIGNING<lv_field>.
IF lv_counter EQ1.
READTABLE 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 INTOTABLE lt_field_val.
WHEN'2'.
SPLIT<lv_field>AT lc_comma INTOTABLE lt_field_val.
ENDCASE.
LOOPAT lt_field_val ASSIGNING<lv_field_val>.
lv_tabix = sy-tabix.
READTABLE 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.
IFNOT<fs_dyn_table>[] ISINITIAL.
CALLFUNCTION'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 EQ0.
MODIFY(lv_tabname)FROMTABLE<fs_dyn_table>.
IF sy-subrc EQ0.
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').
COMMITWORK.
ELSE.
ROLLBACKWORK.
ENDIF.
CALLFUNCTION'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 TYPEREFTO cl_bsp_wd_collection_wrapper,
lr_entity TYPEREFTO if_bol_bo_property_access,
lr_table TYPEREFTO 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 TYPEREFTOdata,
lv_sy_subrc TYPE sy-subrc VALUE 0,
lv_field_name TYPE char40,
lt_dref_seltable TYPEREFTOdata,
ls_dref_line TYPEREFTOdata,
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 TYPEREFTO cl_bsp_wd_value_node,
lr_res_coll TYPEREFTO if_bol_bo_col,
lv_counter TYPE i,
lv_file_content_string TYPE string,
lr_custom_controller TYPEREFTO zl_z_tabl_u_cucodataupd_impl,
lr_collection TYPEREFTO if_bol_bo_col.
FIELD-SYMBOLS:
<lv_field> TYPE string,
<lv_field_val> TYPE string,
<ls_field> TYPEany,
<fs_dyn_table> TYPEtable,
<fs_tabline> TYPEany.
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 ISNOTINITIAL.
CALLMETHOD super->do_prepare_output.
* EXPORTING
* iv_first_time = ABAP_FALSE
lv_tabname = lv_table.
CALLMETHOD 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
INTOTABLE lt_field.
TRY.CREATEDATA lt_dref_seltable TYPETABLEOF(lv_tabname) .
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN lt_dref_seltable->* TO<fs_dyn_table>.
TRY.
CREATEDATA ls_dref_line LIKELINEOF<fs_dyn_table>.
CATCH cx_sy_create_data_error.
RETURN.
ENDTRY.
ASSIGN ls_dref_line->* TO<fs_tabline>.
lv_counter = 1.
LOOPAT lt_field ASSIGNING<lv_field>.
IF lv_counter EQ1.
READTABLE 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
INTOTABLE lt_field_val.
WHEN'2'.
SPLIT<lv_field>AT lc_comma INTOTABLE lt_field_val.
ENDCASE.
LOOPAT lt_field_val ASSIGNING<lv_field_val>.
lv_tabix = sy-tabix.
READTABLE 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.
CREATEOBJECT lr_collection TYPE cl_crm_bol_bo_col.
LOOPAT<fs_dyn_table>ASSIGNING<fs_tabline>.
CREATEOBJECT lr_value_node
EXPORTING
iv_data_ref = ls_dref_line.
lr_value_node->set_properties(<fs_tabline>).
CALLMETHOD 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 TYPEREFTO zl_z_tabl_u_cucodataupd_impl,
lr_coll_wrapper TYPEREFTO cl_bsp_wd_collection_wrapper,
lr_entity TYPEREFTO cl_crm_bol_entity,
lr_table TYPEREFTO 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').
CALLMETHOD 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 TYPEREFTO zl_z_tabl_u_dataview_cn00,
lt_columns TYPE abap_component_tab,
ls_column TYPE abap_componentdescr.
lt_columns[] = gr_filedata->gt_columns[].
LOOPAT 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.
CREATEOBJECT 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.
Runtime Repository Details :
The below snapshot shows the final runtime repository objects.
![Runtime Repository.JPG]()
Component Execution Details :
File Types:
File Contents - Text File :
File Contents - CSV File
Sample Table - 1:
Sample Table -2 :
Table ZCONFIG_DATA_1 provided in the component , columns displayed in the table view as per the provided table , selected the text file and loaded the text file using "Upload" button:
Saved the data using "Save" button , table data after successful data load
Table ZCONFIG_DATA_2 provided in the component , columns displayed in the table view as per the provided table , selected the CSV file and loaded the CSV file using "Upload" button: