Β
This blog covers RAP development using a custom entity, showcasing data with UI annotations, and surpassing the standard SAP data preview limit through the use of pagination.
Lets Start….
Step 1: Create a custom entity with the fields that need to be displayed or sent to the frontend.
@EndUserText.label: ‘Custom entity for fetching data’
@ObjectModel.query.implementedBy: ‘ABAP:ZCL_IMPLEMENT_EXT’ //This is the class where the data is handle and processed
@UI:{ headerInfo:{ typeName: ‘RAP Learn’,
typeNamePlural: ‘RAP Learn’,
title: { label: ‘RAP Learn’,
type: #STANDARD,
value: ‘component’
},
description: { value: ‘obj_desc’ },
typeImageUrl: ‘sap-icon://activity-items’ //Show Icon image on header of object layout
}
}
@Search.searchable: true //for Searching the data from the output which is also need to implement in the implemented class above
define root custom entity ZCE_MAIN
{
.facet : [{
id: ‘ID1’,
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label : ‘Component detail’,
position: 10
},
{
id: ‘FG1’,
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
label : ‘Validity Date’,
targetQualifier: ‘FG1’,
position: 10
}]
: { selectionField: [{ position: 10 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4MATNR’ , element: ‘matnr’ } ,
additionalBinding: [{ localElement: ‘werks’, element: ‘werks’ },
{ localElement: ‘stlan’ , element: ‘stlan’ },
{ localElement: ‘stlal’ , element: ‘stlal’ }]}]
@Consumption.filter.selectionType: #SINGLE
key matnr : matnr;
: { selectionField: [{ position: 20 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4WERKS’, element: ‘werks’ }
}]
@Consumption.filter.selectionType: #SINGLE
key werks : werks_d;
: { selectionField: [{ position: 30 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4STLAN’ , element: ‘stlan’ }
}]
@Consumption.filter.selectionType: #SINGLE
key stlan : stlan;
: { selectionField: [{ position: 40 }]}
@Consumption.filter.mandatory: true
@Consumption.filter.selectionType: #SINGLE
key stlal : stlal;
: { lineItem: [{ position: 10 }], identification: [{ position: 10 }]}
@EndUserText.label: ‘Level’
key bom_level : abap.dec( 2, 0 );
: { lineItem: [{ position: 20 }], identification: [{ position: 20 }]}
@EndUserText.label: ‘Component’
.defaultSearchElement: true
key component : idnrk;
: { selectionField: [{ position: 50 }]}
@Consumption.filter.mandatory: true
@Consumption.filter.selectionType: #SINGLE
@EndUserText.label: ‘Date’
zdate : abap.dats;
: { lineItem: [{ position: 30, cssDefault: { width: ’13rem’ } }], identification: [{ position: 30 }]}
@EndUserText.label: ‘Object Description’
.defaultSearchElement: true
obj_desc : maktx;
: { lineItem: [{ position: 35, cssDefault: { width: ‘8rem’ } }], identification: [{ position: 35 }]}
@EndUserText.label: ‘Quantity’
comp_qty : kmpmg_bi;
: { lineItem: [{ position: 45 }], identification: [{ position: 45 }]}
@EndUserText.label: ‘Unit’
comp_unit : kmpme;
: { lineItem: [{ position: 55 }], fieldGroup: [{ position: 10 , qualifier: ‘FG1’, label: ‘Valid From’ }]}
@EndUserText.label: ‘Valid from’
valid_from : datuv_bi;
: { lineItem: [{ position: 65 }], fieldGroup: [{ position: 11 , qualifier: ‘FG1’, label: ‘Valid To’ }]}
@EndUserText.label: ‘Valid to’
valid_to : datub_bi;
}
While using the RAP framework, metadata extensions cannot be created for custom entities. Therefore, annotations must be directly included in the custom entity code itself for UI purposes.
Step 2 : Create an implementation class for the custom entity mentioned above and name itΒ ZCL_IMPLEMENT_EXTΒ or use the custom name specified in the second line of the code.
CLASS zcl_implement_ext DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
SHARED MEMORY ENABLED .
PUBLIC SECTION.
DATA : et_final TYPE TABLE OF zce_main.
INTERFACES if_rap_query_provider .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_IMPLEMENT_EXT IMPLEMENTATION.
METHOD if_rap_query_provider~select.
CASE io_request->get_entity_id( ).
WHEN ‘ZCE_MAIN’.
TRY.
DATA(lv_skip) = io_request->get_paging( )->get_offset( ). “gets the skip part from URL which means number of data to be skipped and default is 0 but later on it gets add by 20… till last data not get fetched
DATA(lv_top) = io_request->get_paging( )->get_page_size( ). “gets the top part from URL which means number of data required and default is 20
DATA(lt_filter) = io_request->get_filter( )->get_as_ranges( ). “gets the input value which is either pass in our filters or when click on single data line item
CATCH cx_rap_query_filter_no_range.
“handle exception
ENDTRY.
IF lv_top < 0.
*********** Start Logic
“Put logic for single data fetch in which it will trigger when you are going for object page while clicking on single item from display table
“Take inputs from LT_filter table for sending that particular data click
*********** End Logic
IF io_request->is_total_numb_of_rec_requested( ).
io_response->set_total_number_of_records( lines( et_final ) ).
ENDIF.
IF io_request->is_data_requested( ).
io_response->set_data( et_final ).
ENDIF.
ELSE.
*********** Start Logic
“Put logic for actual multiple data fetch in which it will trigger when you click go button or any sort of actions like search, sort, excel download….
“Take inputs from LT_filter table for required data fetch
*********** End Logic
ENDIF.
********** Searching Logic
DATA(lv_search) = io_request->get_search_expression( ). “gets the value from Search field in the UI
IF lv_search IS NOT INITIAL.
DATA lt_search LIKE et_final.
lv_search = |*{ lv_search }*|.
lt_search = VALUE #( BASE lt_search
FOR ls_f IN et_final
WHERE ( field1 CP lv_search OR “Put required field to be search instead of field1,field2…..
field2 CP lv_search OR
field3 cp lv_search OR
field4 cp lv_search OR
( ls_f ) ).
et_final = lt_search.
ENDIF.
***********End of Searching logic
***********Sorting logic
DATA(lt_sort_elements) = io_request->get_sort_elements( ). “gets the detail table of ascending and descending of field we wants to be sorted from UI
IF lt_sort_elements IS NOT INITIAL.
LOOP AT lt_sort_elements INTO DATA(ls_sort).
IF ls_sort-descending <> ‘X’.
SORT et_final BY (ls_sort-element_name) ASCENDING.
ELSE.
SORT et_final BY (ls_sort-element_name) DESCENDING.
ENDIF.
ENDLOOP.
ENDIF.
**********End of sorting logic
**********Paging- logic for loading more data wrt Standard set amount of data
IF lv_top IS NOT INITIAL OR lv_skip IS NOT INITIAL.
/iwbep/cl_mgw_data_util=>paging( EXPORTING is_paging = VALUE #( top = lv_top
skip = lv_skip )
CHANGING ct_data = et_final ).
ENDIF.
*********End of Pagination
IF io_request->is_total_numb_of_rec_requested( ).
io_response->set_total_number_of_records( lines( et_final ) ). “set number of initial data to display overall
ENDIF.
IF io_request->is_data_requested( ).
io_response->set_data( et_final ). “Set data into the entity
ENDIF.
ENDIF.
ENDCASE.
ENDMETHOD.
ENDCLASS.
The aforementioned class plays a crucial role as it encapsulates the entire logic for data processing, including searching, sorting, and most importantly, setting data for our custom entity.
Step 3 : Create Service Definition of the Custom entityΒ
To create a service definition, simply right-click the custom entity in the Project Explorer, click ‘New Service Definition’, fill in the required inputs, and your service definition will be created.
@EndUserText.label: ‘Service definition’
define service ZSD_MAIN {
expose ZCE_MAIN;
expose ZIV_F4MATNR; “This is for ValueHelp Definition, and it’s okay not to expose it.
expose ZIV_F4WERKS;
expose ZIV_F4STLAN;
}
Let’s take a look at one of the interface views of the ValueHelpDefinition.
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for ValueHelpDefinition – MATNR’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZIV_F4MATNR
as select distinct from mast
left outer join makt on makt.matnr = mast.matnr
{
: { selectionField: [{ position: 10 }] , lineItem: [{ position: 10 }]}
@EndUserText.label: ‘Material No’
key mast.matnr,
@Consumption.filter.hidden: true
key mast.werks,
@Consumption.filter.hidden: true
key mast.stlan,
@Consumption.filter.hidden: true
key mast.stlal,
@Consumption.filter.hidden: true
: { lineItem: [{ position: 20 }]}
@EndUserText.label: ‘Material Desc’
makt.maktx
}
Step 4 : Create a Service Binding for the aforementioned service definition.
To create a service binding, simply right-click the created service definition in the Project Explorer, click ‘New Service Binding’, fill in the required inputs, and your service binding will be created. While creating the Service Binding, I selected OData V2 – UI. Then, activate and publish the service. To view the UI output, you can use the Preview option in Eclipse to see the output as shown in the image below.
Β
In conclusion, using RAP with custom entities and pagination facilitates efficient data handling. With UI annotations, you can easily preview and refine the user interface. We hope this guide has been helpful. Stay tuned for more tips!
Β
Note: This program is created for a remote system. For cloud environments, you can use a service consumption model or access data through a remote system API in the implementation class.
Β
βΒ Β This blog covers RAP development using a custom entity, showcasing data with UI annotations, and surpassing the standard SAP data preview limit through the use of pagination.Lets Start….Step 1: Create a custom entity with the fields that need to be displayed or sent to the frontend.@EndUserText.label: ‘Custom entity for fetching data’
@ObjectModel.query.implementedBy: ‘ABAP:ZCL_IMPLEMENT_EXT’ //This is the class where the data is handle and processed
@UI:{ headerInfo:{ typeName: ‘RAP Learn’,
typeNamePlural: ‘RAP Learn’,
title: { label: ‘RAP Learn’,
type: #STANDARD,
value: ‘component’
},
description: { value: ‘obj_desc’ },
typeImageUrl: ‘sap-icon://activity-items’ //Show Icon image on header of object layout
}
}
@Search.searchable: true //for Searching the data from the output which is also need to implement in the implemented class above
define root custom entity ZCE_MAIN
{
.facet : [{
id: ‘ID1’,
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label : ‘Component detail’,
position: 10
},
{
id: ‘FG1’,
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
label : ‘Validity Date’,
targetQualifier: ‘FG1’,
position: 10
}]
: { selectionField: [{ position: 10 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4MATNR’ , element: ‘matnr’ } ,
additionalBinding: [{ localElement: ‘werks’, element: ‘werks’ },
{ localElement: ‘stlan’ , element: ‘stlan’ },
{ localElement: ‘stlal’ , element: ‘stlal’ }]}]
@Consumption.filter.selectionType: #SINGLE
key matnr : matnr;
: { selectionField: [{ position: 20 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4WERKS’, element: ‘werks’ }
}]
@Consumption.filter.selectionType: #SINGLE
key werks : werks_d;
: { selectionField: [{ position: 30 }]}
@Consumption.filter.mandatory: true
@Consumption.valueHelpDefinition: [{
entity : { name: ‘ZIV_F4STLAN’ , element: ‘stlan’ }
}]
@Consumption.filter.selectionType: #SINGLE
key stlan : stlan;
: { selectionField: [{ position: 40 }]}
@Consumption.filter.mandatory: true
@Consumption.filter.selectionType: #SINGLE
key stlal : stlal;
: { lineItem: [{ position: 10 }], identification: [{ position: 10 }]}
@EndUserText.label: ‘Level’
key bom_level : abap.dec( 2, 0 );
: { lineItem: [{ position: 20 }], identification: [{ position: 20 }]}
@EndUserText.label: ‘Component’
.defaultSearchElement: true
key component : idnrk;
: { selectionField: [{ position: 50 }]}
@Consumption.filter.mandatory: true
@Consumption.filter.selectionType: #SINGLE
@EndUserText.label: ‘Date’
zdate : abap.dats;
: { lineItem: [{ position: 30, cssDefault: { width: ’13rem’ } }], identification: [{ position: 30 }]}
@EndUserText.label: ‘Object Description’
.defaultSearchElement: true
obj_desc : maktx;
: { lineItem: [{ position: 35, cssDefault: { width: ‘8rem’ } }], identification: [{ position: 35 }]}
@EndUserText.label: ‘Quantity’
comp_qty : kmpmg_bi;
: { lineItem: [{ position: 45 }], identification: [{ position: 45 }]}
@EndUserText.label: ‘Unit’
comp_unit : kmpme;
: { lineItem: [{ position: 55 }], fieldGroup: [{ position: 10 , qualifier: ‘FG1’, label: ‘Valid From’ }]}
@EndUserText.label: ‘Valid from’
valid_from : datuv_bi;
: { lineItem: [{ position: 65 }], fieldGroup: [{ position: 11 , qualifier: ‘FG1’, label: ‘Valid To’ }]}
@EndUserText.label: ‘Valid to’
valid_to : datub_bi;
}While using the RAP framework, metadata extensions cannot be created for custom entities. Therefore, annotations must be directly included in the custom entity code itself for UI purposes.Step 2 : Create an implementation class for the custom entity mentioned above and name itΒ ZCL_IMPLEMENT_EXTΒ or use the custom name specified in the second line of the code.CLASS zcl_implement_ext DEFINITION
PUBLIC
FINAL
CREATE PUBLIC
SHARED MEMORY ENABLED .
PUBLIC SECTION.
DATA : et_final TYPE TABLE OF zce_main.
INTERFACES if_rap_query_provider .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_IMPLEMENT_EXT IMPLEMENTATION.
METHOD if_rap_query_provider~select.
CASE io_request->get_entity_id( ).
WHEN ‘ZCE_MAIN’.
TRY.
DATA(lv_skip) = io_request->get_paging( )->get_offset( ). “gets the skip part from URL which means number of data to be skipped and default is 0 but later on it gets add by 20… till last data not get fetched
DATA(lv_top) = io_request->get_paging( )->get_page_size( ). “gets the top part from URL which means number of data required and default is 20
DATA(lt_filter) = io_request->get_filter( )->get_as_ranges( ). “gets the input value which is either pass in our filters or when click on single data line item
CATCH cx_rap_query_filter_no_range.
“handle exception
ENDTRY.
IF lv_top < 0.
*********** Start Logic
“Put logic for single data fetch in which it will trigger when you are going for object page while clicking on single item from display table
“Take inputs from LT_filter table for sending that particular data click
*********** End Logic
IF io_request->is_total_numb_of_rec_requested( ).
io_response->set_total_number_of_records( lines( et_final ) ).
ENDIF.
IF io_request->is_data_requested( ).
io_response->set_data( et_final ).
ENDIF.
ELSE.
*********** Start Logic
“Put logic for actual multiple data fetch in which it will trigger when you click go button or any sort of actions like search, sort, excel download….
“Take inputs from LT_filter table for required data fetch
*********** End Logic
ENDIF.
********** Searching Logic
DATA(lv_search) = io_request->get_search_expression( ). “gets the value from Search field in the UI
IF lv_search IS NOT INITIAL.
DATA lt_search LIKE et_final.
lv_search = |*{ lv_search }*|.
lt_search = VALUE #( BASE lt_search
FOR ls_f IN et_final
WHERE ( field1 CP lv_search OR “Put required field to be search instead of field1,field2…..
field2 CP lv_search OR
field3 cp lv_search OR
field4 cp lv_search OR
( ls_f ) ).
et_final = lt_search.
ENDIF.
***********End of Searching logic
***********Sorting logic
DATA(lt_sort_elements) = io_request->get_sort_elements( ). “gets the detail table of ascending and descending of field we wants to be sorted from UI
IF lt_sort_elements IS NOT INITIAL.
LOOP AT lt_sort_elements INTO DATA(ls_sort).
IF ls_sort-descending <> ‘X’.
SORT et_final BY (ls_sort-element_name) ASCENDING.
ELSE.
SORT et_final BY (ls_sort-element_name) DESCENDING.
ENDIF.
ENDLOOP.
ENDIF.
**********End of sorting logic
**********Paging- logic for loading more data wrt Standard set amount of data
IF lv_top IS NOT INITIAL OR lv_skip IS NOT INITIAL.
/iwbep/cl_mgw_data_util=>paging( EXPORTING is_paging = VALUE #( top = lv_top
skip = lv_skip )
CHANGING ct_data = et_final ).
ENDIF.
*********End of Pagination
IF io_request->is_total_numb_of_rec_requested( ).
io_response->set_total_number_of_records( lines( et_final ) ). “set number of initial data to display overall
ENDIF.
IF io_request->is_data_requested( ).
io_response->set_data( et_final ). “Set data into the entity
ENDIF.
ENDIF.
ENDCASE.
ENDMETHOD.
ENDCLASS.The aforementioned class plays a crucial role as it encapsulates the entire logic for data processing, including searching, sorting, and most importantly, setting data for our custom entity.Step 3 : Create Service Definition of the Custom entityΒ To create a service definition, simply right-click the custom entity in the Project Explorer, click ‘New Service Definition’, fill in the required inputs, and your service definition will be created.@EndUserText.label: ‘Service definition’
define service ZSD_MAIN {
expose ZCE_MAIN;
expose ZIV_F4MATNR; “This is for ValueHelp Definition, and it’s okay not to expose it.
expose ZIV_F4WERKS;
expose ZIV_F4STLAN;
}Let’s take a look at one of the interface views of the ValueHelpDefinition.@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for ValueHelpDefinition – MATNR’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZIV_F4MATNR
as select distinct from mast
left outer join makt on makt.matnr = mast.matnr
{
: { selectionField: [{ position: 10 }] , lineItem: [{ position: 10 }]}
@EndUserText.label: ‘Material No’
key mast.matnr,
@Consumption.filter.hidden: true
key mast.werks,
@Consumption.filter.hidden: true
key mast.stlan,
@Consumption.filter.hidden: true
key mast.stlal,
@Consumption.filter.hidden: true
: { lineItem: [{ position: 20 }]}
@EndUserText.label: ‘Material Desc’
makt.maktx
}Step 4 : Create a Service Binding for the aforementioned service definition.To create a service binding, simply right-click the created service definition in the Project Explorer, click ‘New Service Binding’, fill in the required inputs, and your service binding will be created. While creating the Service Binding, I selected OData V2 – UI. Then, activate and publish the service. To view the UI output, you can use the Preview option in Eclipse to see the output as shown in the image below.Β In conclusion, using RAP with custom entities and pagination facilitates efficient data handling. With UI annotations, you can easily preview and refine the user interface. We hope this guide has been helpful. Stay tuned for more tips!Β Note: This program is created for a remote system. For cloud environments, you can use a service consumption model or access data through a remote system API in the implementation class.Β Β Β Read MoreΒ Technology Blog Posts by Members articlesΒ
#SAP
#SAPTechnologyblog