Technical Articles
Fiori Elements: Actions and Function Imports in List Report
In that blog, I will explain all about Actions in Fiori Elements. I said Actions because for Fiori Elements template an OData Function Import stands for Actions.
So what will cover this blog :
- How to embedded Function Import into Fiori Element
- How to make popup message
- How to hack the response message
- Error/Warning message
- Success/Info message
- How to navigate
I will do the same for the Object Page soon.
Function Import to Actions
Let’s start by showing you, on which Function Import I will based my post.
CopySO is the name of my function which is the feature to copy a sale order. It has one input parameter which is SONumber.
After re-generate the SEGW project and clear the metadata, you can implement the function. In the DPC_EXT class, redefine the method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION and add any code for the moment.
In your WebIDE project, insert the following annotation to render visible the action:
The result will be this one :
We can move the button on the line by adding the following annotation :
<Record Type="UI.DataFieldForAction">
<PropertyValue Property="Action" String="ZJBE_DEMO_SMART_SO_SRV.ZJBE_DEMO_SMART_SO_SRV_Entities/CopySO"/>
<PropertyValue Property="Label" String="{@i18n>COPY_SALE}"/>
<PropertyValue Property="Inline" Bool="true"/>
</Record>
Select a line and click on the button Copy Sale, you should have this behaviour :
It asks you to enter the SONumber which is a mandatory field of your Function Import, that is correct. But in the scenario, you probably want the system automatically put the Document Number in the action.
To do so, you have to name your action’s input parameter, the same as your entity. In our example the SONumber should be rename by Vbeln.
After renaming your input parameter, the behaviour should be better. If you want to pass multiple value, the logic is the same, add multiple input with the same name of the main entity.
Ok, it doesn’t look like very well. It is normal because for the moment in the Back End we have not yet implemented the EXECUTE_ACTION method. But if we do a debug we should get the rigth key :
The error page we’ve got is because we have not sent anything from the Back End to the Fiori Element framework. We will continue, step by step to discover all the possibility of those Actions 🙂
Confirmation popup
Let’s carry on with a confirmation popup. In some case we want to inform your end user to take care of a deletion action or something else.
To do so, in the WebIDE add a new annotation by selecting your Function Import :
And then add the annotation IsActionCritical:
Save and execute the application, and look at the difference :
Now we would like to customize the text from that Popup. In your i18n.property file, you can add a line with this key : ACTION_CONFIRM|<FunctionImportName>. In our example it should be this :
The result :
Handle the Response
At this stage, you have well customized the front-end part. Now we want our Function Import responding in the rigth manner. To do so, let’s go to the BackEnd part and play with the response body.
Sucess message
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA(lo_msg_container) = me->mo_context->get_message_container( ).
DATA ls_response TYPE zcl_jbe_demo_smart_so_mpc=>ts_soheader.
CASE iv_action_name.
WHEN 'CopySO'.
lo_msg_container->add_message_text_only(
EXPORTING
iv_msg_type = /iwbep/cl_cos_logger=>success " Message Type - defined by GCS_MESSAGE_TYPE
iv_msg_text = 'The copy is a success' " Message Text
iv_entity_type = 'SOHeader' " Entity type/name
iv_message_target = '/#TRANSIENT#' " Target (reference) (e.g. Property ID) of a message
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_msg_container.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Warning Message
As you can see the Document Number is shown in the message. If you want to modify this text, you have to add the annotation UI.HeaderInfo like this :
And the popup looks like this :
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA(lo_msg_container) = me->mo_context->get_message_container( ).
DATA ls_response TYPE zcl_jbe_demo_smart_so_mpc=>ts_soheader.
CASE iv_action_name.
WHEN 'CopySO'.
lo_msg_container->add_message_text_only(
EXPORTING
iv_msg_type = /iwbep/cl_cos_logger=>warning " Message Type - defined by GCS_MESSAGE_TYPE
iv_msg_text = 'The copy is a success' " Message Text
iv_entity_type = 'SOHeader' " Entity type/name
iv_message_target = '/#TRANSIENT#' " Target (reference) (e.g. Property ID) of a message
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_msg_container.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Info message
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA(lo_msg_container) = me->mo_context->get_message_container( ).
DATA ls_response TYPE zcl_jbe_demo_smart_so_mpc=>ts_soheader.
CASE iv_action_name.
WHEN 'CopySO'.
lo_msg_container->add_message_text_only(
EXPORTING
iv_msg_type = /iwbep/cl_cos_logger=>info " Message Type - defined by GCS_MESSAGE_TYPE
iv_msg_text = 'The copy is a success' " Message Text
iv_entity_type = 'SOHeader' " Entity type/name
iv_message_target = '/#TRANSIENT#' " Target (reference) (e.g. Property ID) of a message
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_msg_container.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Error message
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA(lo_msg_container) = me->mo_context->get_message_container( ).
DATA ls_response TYPE zcl_jbe_demo_smart_so_mpc=>ts_soheader.
CASE iv_action_name.
WHEN 'CopySO'.
lo_msg_container->add_message_text_only(
EXPORTING
iv_msg_type = /iwbep/cl_cos_logger=>error " Message Type - defined by GCS_MESSAGE_TYPE
iv_msg_text = 'The copyhas failed.' " Message Text
iv_entity_type = 'SOHeader' " Entity type/name
iv_message_target = '/#TRANSIENT#' " Target (reference) (e.g. Property ID) of a message
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_msg_container.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
Response to Navigation
If the response is success you would like to options :
- Navigate to the newly created object
- Do nothing, no navigation
For the first one, you have to return the Key of the newly created object in the Back End :
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA ls_response TYPE zcl_jbe_demo_smart_so_mpc=>ts_soheader.
CASE iv_action_name.
WHEN 'CopySO'.
" We assume that 34 is a newly created object
ls_response-vbeln = '34'.
me->copy_data_to_ref(
EXPORTING
is_data = ls_response
CHANGING
cr_data = er_data
).
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
In my exemple I select the line 33, and want to navigate to the newly created object (let says 34) after clicking the Copy Sale button :
it should navigate automatically to the object 34:
Conclusion
Hope it will help you to create and use Fiori Elements in a good manner and do a well user experience. My purpose is to show you how to do things without extension.
Enjoy 😉
Auto navigation to the object page is a very cool feature. Thanks for sharing Joseph BERTHE
Thanks you. Hope it helps you.
Thanks for sharing this Joseph BERTHE. I'm sure this will come in handy in a Fiori Elements project.
Thanks Pierre Dominique
Good Morning.
Congratulations, execelente post.
It helped with many doubts that I had.
Thank you for your comment. I'm glad that it helps you.
Nice to know this feature, I think we can also add the annotation in mpc_ext - Define() method right?
Will that work?
Thanks.
In fact, in the MPC you can elaborate an annotation file with more or less all annotation. But I use to separate the UI annotation in separate file in the WebIDE and all sap:<anno> in the MPC.
One thing is sure.... it is a little mess with those annotation. Some are in the backend, some in CDS views, some in a file in WebIDE and some in separate file stored in backed.... Pioufff what a mess 🙂
Regards,
Hi Berthe,
Nice Blog.
I have query ,Is the action same as BOPF BO action.
Thank you,
Syam
Thanks Joseph - added to Fiori elements wiki!
Thanks Jocelyn Dart
Thank you so much! Obviously this is required in order for the fiori element template to display the message in the default message box...
Hi Joseph,
I please want to ask for the possibility of custom Action button functionality to have compare the two selected row of smart table .
I was thinking to achive this by using fragment where selected row will appear and the data comes from new entity based on the passed filter value of selected rows value.
Aslo I could have save and update(for changed one) functionality in that fragment for which I could write a code in controller.
Please let me your feedback.
Thanks
Peeyush Ranjan
Hi,
Becarefull, If you do too much custom code, think about creating a Freestyle application. Custom code in Fiori Element can become quickly a nigthmare.
Regards,
Joseph
Thank you!
I Write the response like you
But on the fiori I have this message:
Can you please tell me how to change the message to the message toast like you?
And how to remove the yellow text?
Hi,
Sorry for the delay, What I observe is the behaviour of this popup depend on the UI5 version.
In wich version of UI5 are you ?
Regards,
Joseph
Thank you for the reply! I use version 1.52.
Hi Joseph,
Thanks for this wonderful post, I have been using your blogs for my developments.
I had a question regarding the fragment that`s generated for actions. Can we change the default footer buttons(labels). It always copies the action label and the cancel button.
Thanks,
Rahul
Hello,
I'm not sure it is possible.
Regqrds,
Joseph
Hi Joseph,
Nice Blog !
2 Doubts:
When u said: "After renaming your input parameter, the behaviour should be better. If you want to pass multiple value, the logic is the same, add multiple input with the same name of the main entity." What do you mean by this ? Is it if I have multi select option enabled then can I pass multiple values of Vbeln ? Can you please help.
Also, I see some 2 filter buttons in the toolbar of your table. How did u add those ?
Regards,
Vaibhav
Hi Joseph,
nice one. Function Imports can even be annotated in the backend and do not need to be annotated in the frontend 🙂
I have a question, do you happen to know whether one can suppress the navigation to the object page even though one returns the key of the new (or, in our case, changed) entity?
Regards,
Philipp
Hello,
It is maybe possible, if you embedded you callFunction méthode into the securedExection method. But never try that.
Regards,
Joseph
Hello Joseph (and all others),
thank you for this excellent blog. I tried to create a function and in SEGW it looks like this:
My annotation-file looks like this:
<Record Type=”UI.DataFieldForAction”>
<PropertyValue Property=”Action” String=”SBK_HCM_TIMESHEET01_SRV.SBK_HCM_TIMESHEET01_SRV_Entities/Release”/>
<PropertyValue Property=”Label” String=”Release”/>
</Record>
Function Import Parameter Guid is the same as in the entity. But if I mark an entry my list, and press the button, I still get the pop-up to enter a value (which is not possible).
Any ideas?
Thank you
Achim
Hello,
Is the Guid attribute is the key of your entity ? If not, it should be.
Regards
Hi
How would you add the Action in the table toolbar as well as inline, so you can either execute it on single line by pressing on the button or select multiple instances and do it via toolbar?
I did not find a way to do this....
Hi Joseph,
thank you for the excellent blog. This is very helpful!
One question:
Do you know how to create a function import which appears on the list report toolbar active without selecting a line (Like the standard "Create" button from BOPF)?
Thanks in advance.
Kind regards
Axel
Amazing post. Subscribed!
Thanks 🙂
Thanks Joseph for this excellent blog post!
Is there any way to achieve a success message toast without raising an exception in the backend?
Somehow I feel like exceptions should only be raised when errors occur.
Br,
Philipp
Hello,
In fact, raise business exception is not mandatory. You can populate the message manager with success message without to raise exception. It should work.
Regards,
Hello,
thank you for this article, it helped a lot!
I have a requirement to open a pdf document from a line in a list report. I have created the function import to return the PDF in binary and the code in backend is correctly executed, but I don't understand how to use the result of the function import in frontend. After the action, nothing happens, and it doesn't navigate to the object page as it should do if I understand what you wrote.
Do you know how to get the result of the function import in frontend?
Best Regards,
Vincent