Recently, I worked on a requirement where we had to add an action button on Fiori Elements List Report. Looked at various options but nothing seems straightforward. UI5 Demo Kit suggests using UI5 Extensions which I wanted to avoid if I could. There are some annotations related to function import which looked promising but I couldn’t find any blog/help document on how to actually use them in CDS and implement in the OData service. Then I saw actions using BOPF, but this report which I was working didn’t have any business object attached to it.
Looking at some SAP standard apps I finally figured out how to achieve this without UI5 extension in Web-IDE.
For the purpose of this blog, I’ll use tried and tested flight data model. You should be able to replicate the solution in your system using the code I’ve provided.
In this blog I’ll show you how to add action button(s) on Fiori Element List Page without making UI5 extension in Web-IDE or using BOPF.
In this Fiori Elements List report app, I am going to display a list of flight connections (from table SPFLI) and I’ll show to how to add actions which we can use to cancel the flight and reverse the cancellation. In part 1 of the blog, we will see basic implementation. To keep blog manageable (for me) I am going to keep additional features like message handling, enable/disable action buttons in part 2 of the blog.
As a starting point, I have this Fiori Elements List App which is based on CDS View. I have exposed CDS View via SEGW using Data Source Reference.
CDS View: ZI_FlightConnections
@AbapCatalog.sqlViewName: 'ZISPFLI01'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Flight Connections'
define view ZI_FlightConnections
as select from spfli
left outer join zspfli_act as CancellationInfo on spfli.carrid = CancellationInfo.carrid
and spfli.connid = CancellationInfo.connid
association [0..1] to U99_I_Airline as _Airline on $projection.Airline = _Airline.Airline
association [0..1] to U99_IAIRPORT as _AirportFrom on $projection.AirportFrom = _AirportFrom.Airport
association [0..1] to U99_IAIRPORT as _AirportTo on $projection.AirportTo = _AirportTo.Airport
association [0..1] to S_CityAirport as _CityFrom on $projection.CityFrom = _CityFrom.City
association [0..1] to S_CityAirport as _CityTo on $projection.CityTo = _CityTo.City
{
@ObjectModel.foreignKey.association: '_Airline'
@UI: { lineItem: [{ position: 10 }] , selectionField: [{ position: 10 }]}
key spfli.carrid as Airline,
@UI.lineItem: [{ position: 20 }]
key spfli.connid as FlightConnection,
@ObjectModel.foreignKey.association: '_CityTo'
@UI: { lineItem: [{ position: 40 }] , selectionField: [{ position: 15 }]}
spfli.cityfrom as CityFrom,
@ObjectModel.foreignKey.association: '_AirportFrom'
@UI: { lineItem: [{ position: 50 }] , selectionField: [{ position: 20 }]}
spfli.airpfrom as AirportFrom,
@ObjectModel.foreignKey.association: '_CityTo'
@UI: { lineItem: [{ position: 70 }] , selectionField: [{ position: 25 }]}
spfli.cityto as CityTo,
@ObjectModel.foreignKey.association: '_AirportTo'
@UI: { lineItem: [{ position: 80 }] , selectionField: [{ position: 30 }]}
spfli.airpto as AirportTo,
@UI.lineItem: [{ position: 90 }]
spfli.deptime as DepartureTime,
@UI.lineItem: [{ position: 100 }]
spfli.arrtime as ArrivalTime,
@UI.lineItem: [{ position: 120 }]
@EndUserText.label: 'Cancelled On'
CancellationInfo.cancelledon,
@UI.lineItem: [{ position: 130 }]
@EndUserText.label: 'Cancelled By'
CancellationInfo.cancelledby,
_Airline,
_AirportFrom,
_AirportTo,
_CityFrom,
_CityTo
}
SEGW: ZIFLTCON
Looking at some SAP standard apps I finally figured out how to achieve this without UI5 extension in Web-IDE.
For the purpose of this blog, I’ll use tried and tested flight data model. You should be able to replicate the solution in your system using the code I’ve provided.
Introduction
In this blog I’ll show you how to add action button(s) on Fiori Element List Page without making UI5 extension in Web-IDE or using BOPF.
Setting the Scene
In this Fiori Elements List report app, I am going to display a list of flight connections (from table SPFLI) and I’ll show to how to add actions which we can use to cancel the flight and reverse the cancellation. In part 1 of the blog, we will see basic implementation. To keep blog manageable (for me) I am going to keep additional features like message handling, enable/disable action buttons in part 2 of the blog.
As a starting point, I have this Fiori Elements List App which is based on CDS View. I have exposed CDS View via SEGW using Data Source Reference.
CDS View: ZI_FlightConnections
@AbapCatalog.sqlViewName: 'ZISPFLI01'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Flight Connections'
define view ZI_FlightConnections
as select from spfli
left outer join zspfli_act as CancellationInfo on spfli.carrid = CancellationInfo.carrid
and spfli.connid = CancellationInfo.connid
association [0..1] to U99_I_Airline as _Airline on $projection.Airline = _Airline.Airline
association [0..1] to U99_IAIRPORT as _AirportFrom on $projection.AirportFrom = _AirportFrom.Airport
association [0..1] to U99_IAIRPORT as _AirportTo on $projection.AirportTo = _AirportTo.Airport
association [0..1] to S_CityAirport as _CityFrom on $projection.CityFrom = _CityFrom.City
association [0..1] to S_CityAirport as _CityTo on $projection.CityTo = _CityTo.City
{
@ObjectModel.foreignKey.association: '_Airline'
@UI: { lineItem: [{ position: 10 }] , selectionField: [{ position: 10 }]}
key spfli.carrid as Airline,
@UI.lineItem: [{ position: 20 }]
key spfli.connid as FlightConnection,
@ObjectModel.foreignKey.association: '_CityTo'
@UI: { lineItem: [{ position: 40 }] , selectionField: [{ position: 15 }]}
spfli.cityfrom as CityFrom,
@ObjectModel.foreignKey.association: '_AirportFrom'
@UI: { lineItem: [{ position: 50 }] , selectionField: [{ position: 20 }]}
spfli.airpfrom as AirportFrom,
@ObjectModel.foreignKey.association: '_CityTo'
@UI: { lineItem: [{ position: 70 }] , selectionField: [{ position: 25 }]}
spfli.cityto as CityTo,
@ObjectModel.foreignKey.association: '_AirportTo'
@UI: { lineItem: [{ position: 80 }] , selectionField: [{ position: 30 }]}
spfli.airpto as AirportTo,
@UI.lineItem: [{ position: 90 }]
spfli.deptime as DepartureTime,
@UI.lineItem: [{ position: 100 }]
spfli.arrtime as ArrivalTime,
@UI.lineItem: [{ position: 120 }]
@EndUserText.label: 'Cancelled On'
CancellationInfo.cancelledon,
@UI.lineItem: [{ position: 130 }]
@EndUserText.label: 'Cancelled By'
CancellationInfo.cancelledby,
_Airline,
_AirportFrom,
_AirportTo,
_CityFrom,
_CityTo
}
SEGW: ZIFLTCON
Table: ZSPFLI_ACT
App
If you are struggling to get to this point I would recommend you check Fiori Elements Wiki Page, section How to Guides for List Report. Make note that I have exposed CDS via SEGW and not directly using OData.pubish annotation. This is important because its DPC_EXT and MPC_EXT classes which we will be using to add actions and put ABAP code to process these actions.
Adding Action Button
We are going to add two action buttons ‘Cancel Flight‘ and ‘Keep Flight‘. On these actions we will set and reset values in fields Cancelled on and Cancelled by.
To add action button first we will have to add function import in OData service following which we will add annotation in CDS View to display buttons and link it to function import name.
Adding Function Import
In DPC_EXT class add following private method. This code add function import to OData service. It defines importing parameters, return parameter etc.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_ZIFLTCON_MPC_EXT->ADD_ACTION
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_ACTION_NAME TYPE /IWBEP/MED_EXTERNAL_NAME
* +--------------------------------------------------------------------------------------</SIGNATURE>
method add_action.
data: lv_fc_fieldvalue type /iwbep/med_annotation_value,
lo_complex_type type ref to /iwbep/if_mgw_odata_cmplx_type,
lo_prop type ref to /iwbep/if_mgw_odata_property.
data(lo_action) = model->create_action( iv_action_name ).
"set return parameter
lo_action->set_return_entity_type( 'ZI_FlightConnectionsType' ) .
lo_action->set_return_entity_set( 'ZI_FlightConnections' ).
lo_action->set_http_method( 'PUT' ).
lo_action->set_return_multiplicity( /iwbep/if_mgw_med_odata_types=>gcs_cardinality-cardinality_1_1 ).
"specify input parameters
data(lo_parameter) = lo_action->create_input_parameter(
iv_parameter_name = 'Airline'
iv_abap_fieldname = 'AIRLINE' ).
lo_parameter->/iwbep/if_mgw_odata_property~set_type_edm_string( ).
lo_parameter->set_maxlength( iv_max_length = 3 ).
data(lo_parameter1) = lo_action->create_input_parameter(
iv_parameter_name = 'FlightConnection'
iv_abap_fieldname = 'FLIGHTCONNECTION' ).
lo_parameter1->/iwbep/if_mgw_odata_property~set_type_edm_string( ).
lo_parameter1->set_maxlength( iv_max_length = 4 ).
endmethod.
Redefine DEFINE method in DPC_EXT class and make call to ADD_ACTION method to add function imports.
method define.
super->define( ) .
add_action( iv_action_name = 'CancelFlight' ) .
add_action( iv_action_name = 'KeepFlight' ) .
endmethod.
Following above changes check OData service metadata have function import added to it.
Change to CDS to Add Action Buttons.
In CDS add following annotation (UI.lineitem) before field Airline. With this annotation we are defining button (label), and asking system to call respective function import on these actions.
define view ZI_FlightConnections
as select from spfli
....
{
@ObjectModel.foreignKey.association: '_Airline'
@UI: { lineItem: [{ position: 10 } ,
{ type: #FOR_ACTION, invocationGrouping: #CHANGE_SET, position: 0, dataAction: 'MPC_EXT:CancelFlight', label: 'Cancel Flight' },
{ type: #FOR_ACTION, invocationGrouping: #CHANGE_SET, position: 1, dataAction: 'MPC_EXT:KeepFlight' , label: 'Keep Flight' }] ,
selectionField: [{ position: 10 }]}
key spfli.carrid as Airline,
....
}
After above changes and activation you should be able to see action buttons on the list page.
Code to Process Action
Fiori Element List Report uses batch processing. To enable batch processing, in DPC_EXT class redefine method /iwbep/if_mgw_appl_srv_runtime~changeset_begin. Also, we will process all requests together, hence set cv_defer_mode = abap_true.
method /iwbep/if_mgw_appl_srv_runtime~changeset_begin.
cv_defer_mode = abap_true .
endmethod.
Next, redefine method /iwbep/if_mgw_appl_srv_runtime~changeset_process and put below code in it. Inline comment in code should give you clue one whats happening
method /iwbep/if_mgw_appl_srv_runtime~changeset_process.
data : lo_func_import_context type ref to /iwbep/if_mgw_req_func_import,
lt_parameters type /iwbep/t_mgw_name_value_pair,
ls_flight_con_status type zspfli_act,
ls_result type zcl_zifltcon_mpc_ext=>ts_zi_flightconnectionstype,
ls_changeset_response type /iwbep/if_mgw_appl_types=>ty_s_changeset_response.
"read requests where operation is execute action (EA)
loop at it_changeset_request assigning field-symbol(<lfs_changeset_request>)
where operation_type = /iwbep/if_mgw_appl_types=>gcs_operation_type-execute_action.
"find function name
lo_func_import_context ?= <lfs_changeset_request>-request_context .
data(lv_function_import_name) = lo_func_import_context->get_function_import_name( ) .
if lv_function_import_name = 'CancelFlight' or lv_function_import_name = 'KeepFlight' .
"read parameters
lt_parameters = lo_func_import_context->get_parameters( ).
ls_flight_con_status-carrid = lt_parameters[ name = 'AIRLINE' ]-value .
ls_flight_con_status-connid = lt_parameters[ name = 'FLIGHTCONNECTION' ]-value .
"set/reset values
case lv_function_import_name.
when 'CancelFlight'.
ls_flight_con_status-cancelledby = sy-uname .
ls_flight_con_status-cancelledon = sy-datum .
when 'KeepFlight'.
clear ls_flight_con_status-cancelledby .
clear ls_flight_con_status-cancelledon .
endcase .
modify zspfli_act from ls_flight_con_status .
"select new values
"do you know - even if you haven't yet committed the changes,
"system will return new data
"search 'transaction isolation levels' to read more on this
select single from zi_flightconnections fields *
where airline = @ls_flight_con_status-carrid
and flightconnection = @ls_flight_con_status-connid
into corresponding fields of @ls_result .
"prepare response with operation number and respective data,
"insert in CT_CHANGESET_RESPONSE
ls_changeset_response-operation_no = <lfs_changeset_request>-operation_no .
copy_data_to_ref(
exporting
is_data = ls_result
changing
cr_data = ls_changeset_response-entity_data ).
insert ls_changeset_response into table ct_changeset_response.
endif .
endloop .
endmethod.
Result
After activation buttons should work
Hi Sabrina,
ReplyDeletethanks for sharing this. It is nicely detailed and explained. I found it helpful because I am trying to enhance a standard Fiori Elements App and the underlying service has a business object attached. However, it is not possible to enhance CDS based BOPF objects, so adding actions there (and the CDS) is not an option. Taking your approach via an enhancement on the standard GW provider classes is the only way to do it as far as I can tell.
Kind regards,
Ben.