Sometimes in our requirement we need to read data dynamically based on some condition, like columns, table/ internal table name may changes as per user input. During one such requirement we need replicate se16 like transaction for Fiori application. Here we need to show table and table data based on the table name given in input field.
In this blog I would explain the steps to achieve the same. We will go through the odata creation, logic to collect table config and data and then consume odata service on SAP ui5 application.
Output would be like as below. In input field provide any table name and on submitting, application should load table data.
In this blog I would explain the steps to achieve the same. We will go through the odata creation, logic to collect table config and data and then consume odata service on SAP ui5 application.
Output would be like as below. In input field provide any table name and on submitting, application should load table data.
First of all create 2 entities for collecting table field information and data like below.
Entity sets
Primary entity: DynamicField to contain configuration information of table
And second entity: DynamicData to contain data for the table
Now create a method in DPC class to identify the table name, extract field information and data for table and save this data in entityset.
Here we have written logic to
Fetch table name coming from UI screen
Fetch Table fields
Fetch Table data
And then combine whole data in single entity
Logic to fetch table fields and description
DATA: lo_table TYPE REF TO cl_abap_tabledescr,
lo_struc TYPE REF TO cl_abap_structdescr,
lo_eleme TYPE REF TO cl_abap_elemdescr,
lr_dref TYPE REF TO data,
ls_fileds TYPE LINE OF zcl_zdyn_p1_mpc=>tt_dynamicfield,
lt_fields TYPE zcl_zdyn_p1_mpc=>tt_dynamicfield.
CREATE DATA lr_dref TYPE STANDARD TABLE OF (iv_tablename).
ASSIGN lr_dref->* TO FIELD-SYMBOL(<fs_itab>).
lo_table ?= cl_abap_typedescr=>describe_by_data( <fs_itab> ).
lo_struc ?= lo_table->get_table_line_type( ).
DATA(lt_ddic) = lo_struc->get_ddic_object( ).
LOOP AT lt_ddic ASSIGNING FIELD-SYMBOL(<fs_ddic>).
lo_eleme ?= cl_abap_elemdescr=>describe_by_name( <fs_ddic>-rollname ).
DATA(ls_dfies) = lo_eleme->get_ddic_field( ).
ls_fileds-abap_typekind = <fs_ddic>-fieldname.
ls_fileds-description = ls_dfies-scrtext_l.
ls_fileds-position = ls_dfies-position.
ls_fileds-keyflag = ls_dfies-keyflag.
ls_fileds-inttype = ls_dfies-inttype.
ls_fileds-leng = ls_dfies-leng.
APPEND ls_fileds TO lt_fields.
ENDLOOP.
CALL METHOD me->/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref
EXPORTING
is_data = lt_fields
CHANGING
cr_data = rt_fields.
Fetch table data
METHOD get_table_data.
DATA : ld_data TYPE REF TO data,
ld_where TYPE edpline,
lt_where TYPE TABLE OF edpline.
FIELD-SYMBOLS: <ft_data> TYPE ANY TABLE,
<ft_data_w> TYPE ANY TABLE,
<ft_fields> TYPE zcl_zdyn_p1_mpc=>tt_dynamicfield.
ASSIGN it_fields->* TO <ft_fields>.
DATA(ld_search) = me->get_search( it_filter ).
CREATE DATA ld_data TYPE TABLE OF (iv_tablename).
ASSIGN ld_data->* TO <ft_data>.
ASSIGN ld_data->* TO <ft_data_w>.
IF ld_search IS INITIAL.
SELECT * FROM (iv_tablename) INTO TABLE <ft_data>.
ELSE.
LOOP AT <ft_fields> ASSIGNING FIELD-SYMBOL(<fs_fields>).
IF <fs_fields>-inttype EQ ‘P’ OR <fs_fields>-inttype EQ ‘b’ OR <fs_fields>-inttype EQ ‘I’.
* ld_where = <fs_fields>-abap_typekind && ‘ = ‘ && ld_search .
ELSE.
ld_where = <fs_fields>-abap_typekind && ‘ =’ && | ‘| && ld_search && |’| .
APPEND ld_where TO lt_where.
SELECT * FROM (iv_tablename) INTO TABLE <ft_data_w> WHERE (ld_where).
ENDIF.
CLEAR ld_where.
refresh <ft_data_w> .
ENDLOOP.
ENDIF.
CALL METHOD me->/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref
EXPORTING
is_data = <ft_data>
CHANGING
cr_data = rt_data.
ENDMETHOD.
Now we will combine whole data into single entity that is lt_field_data
This field is complex structure which will combine our earlier declared entity types. So we will expose data in nested structure to UI5 application
METHOD process_data.
DATA : lt_field_data TYPE STANDARD TABLE OF zcl_zdyn_p1_mpc_ext=>ty_dynamicfielddata,
ls_field_data TYPE zcl_zdyn_p1_mpc_ext=>ty_dynamicfielddata,
ls_data TYPE LINE OF zcl_zdyn_p1_mpc_ext=>tt_dynamicdata_field,
lo_sysuuid TYPE REF TO cl_system_uuid,
ld_counter type char2.
FIELD-SYMBOLS:<ft_fields> TYPE table,
<ft_data> TYPE table.
ASSIGN it_fields->* TO <ft_fields>.
LOOP AT <ft_fields> ASSIGNING FIELD-SYMBOL(<fs_fields>).
me->move_corresponding(
EXPORTING
id_source_data = <fs_fields>
IMPORTING
ed_target_data = ls_field_data
) .
ld_counter = ld_counter + 1.
ls_field_data-TABNAME16 = ld_tablename.
ls_field_data-position = ld_counter.
APPEND ls_field_data TO lt_field_data.
ENDLOOP.
ASSIGN it_data->* TO <ft_data>.
CREATE OBJECT lo_sysuuid .
ld_counter = 0.
LOOP AT <ft_data> ASSIGNING FIELD-SYMBOL(<fs_data>).
TRY.
DATA(lv_uuid) = lo_sysuuid->if_system_uuid~create_uuid_c32( ).
CATCH cx_uuid_error .
ENDTRY.
LOOP AT lt_field_data ASSIGNING FIELD-SYMBOL(<fs_field_data>).
ASSIGN COMPONENT <fs_field_data>-abap_typekind OF STRUCTURE <fs_data> TO FIELD-SYMBOL(<fv_data>).
ls_data-key = lv_uuid.
ls_data-fieldname = <fs_field_data>-abap_typekind.
ls_data-value = <fv_data>.
append ls_data to <fs_field_data>-dataset.
ENDLOOP .
ENDLOOP.
CALL METHOD me->/iwbep/if_mgw_conv_srv_runtime~copy_data_to_ref
EXPORTING
is_data = lt_field_data
CHANGING
cr_data = tr_data.
ENDMETHOD.
At last when you have finished with data processing call expanded entity set and call the above primary method i.e.
implement get_expanded_entityset and call get_dynamic_field_data
Now if you register and execute the service:
You will get the table structure and data returned in nested structure as below
UI5 application
Create a sapui5 project and connect your odata service to the application
Create tableview.xml as below, create table with basic attributes only
<mvc:View xmlns:html=”http://www.w3.org/1999/xhtml” xmlns:mvc=”sap.ui.core.mvc” xmlns:u=”sap.ui.unified” xmlns:c=”sap.ui.core”
xmlns:m=”sap.m” xmlns:t=”sap.ui.table” controllerName=”dynDynamicTab.controller.DynTabView” displayBlock=”true”>
<m:Page id = “page” showHeader=”true” enableScrolling=”false” class=”sapUiContentPadding” title=”Data Browser”>
<m:Input placeholder=”Enter table name” submit = “onSubmit” value=”zemp_info” id=”tablename” showValueHelp=”true” valueHelpRequest=”onSearch”></m:Input>
<m:Button id = “search” text=”Load” press=’onLoad’ visible = “false” ></m:Button>
<m:Label id = “count” text=”” ></m:Label>
<m:content>
<t:Table id=”tableid” visibleRowCount=”20″ enableSelectAll=”false” threshold=”15″ enableBusyIndicator=”true” ariaLabelledBy=”title”></t:Table>
</m:content>
</m:Page>
</mvc:View>
Inside tableview.controller
Load odatamodel
var oModelVariantO1 = new sap.ui.model.odata.ODataModel(“/sap/opu/odata/SAP/ZDYN_P1_SRV/”, true);
var oJsonModel1 = new sap.ui.model.json.JSONModel();
sap.ui.core.BusyIndicator.show(0);
On click of button or submit event of input field read data from backend as below
fetch table name frominput control and concatenate with url for reading
var url = “DynamicFieldSet?$filter=tablename eq ‘” + this.byId(“tablename”).getValue() + “‘ &$expand=DataSet”;
oModelVariantO1.read(url, {
success: function(oData, response) {
// console.log(oData);
sap.ui.core.BusyIndicator.hide();
that.odata = oData;
that.writedata(that.odata);
},
error: function(err) {
sap.ui.core.BusyIndicator.hide();
}
});
Under function writedata we have received all the results from back end
Get rows and columns separately from results array. Bind rows and columns and then you can see the output in your screen
writedata: function(results) {
var row_array = [];
var array = results.results;
var no_of_rows = results.results[0].DataSet.results;
this.byId(“count”).setText(no_of_rows.length + ‘ Records’);
no_of_rows.forEach(function(entry1, j) {
var obj = {};
var j_value = j;
array.forEach(function(entry, i) {
var field = results.results[i].DataSet.results[j_value];
var fieldvalue = field.value;
//var fieldname = results.results[i].description;
var fieldname = field.name;
Object.defineProperty(obj, fieldname, {
value: fieldvalue //set data1 and data 2 accordingly
});
});
row_array.push(obj);
});
var jsonmodel = new sap.ui.model.json.JSONModel();
jsonmodel.setData({
rows: row_array,
columns: results.results
});
var oTable = this.getView().byId(“tableid”);
oTable.setModel(jsonmodel);
oTable.bindColumns(“/columns”, function(sId, oContext) {
var columnName = oContext.getObject().name;
// var columntemp = oContext.getObject().name;
return new sap.ui.table.Column({
label: columnName,
template: columnName,
sortProperty: columnName,
filterProperty: columnName
});
});
oTable.bindRows(“/rows”);
});
},
When we get the odata from back end system, we identify the row and column for the output table and bind the rows and column to out put table.
Output Screen
Here is in this example we have bound the row and columns with fieldname properties, additionally we can bind field description, position as well to the output table. Please let me know if your views on this approach and suggestion.
No comments:
Post a Comment