Skip to Content

Introduction

When using SAP Gateway services with operations mapped to remote-enabled function modules (as opposed to the recommended code-based implementation), messages can be returned and presented with a variety of UI5 controls.


To demonstrate message handling, I created a Fiori compliant app within the Gateway Central Hub deployment scenario,

  • Back-end system with RFC development
  • Front-end system with web service development and app deployment
  • Web IDE for app development

The app displays messages in a Message Popover or Message Box when an entity is updated.

Message Popover

MessagePopover.JPG

Message Box

MessageBox.JPG

Back-end system

In the back-end SAP Business Suite system, a custom table and a corresponding table type have two fields,

  • THINGSID: The key
  • DESCRIPTION: A description to be edited

Remote-enabled function modules perform create, read, update, delete, and query operations on the table as indicated in the following table:

Function Module IMPORTING TYPE EXPORTING TYPE ABAP Keyword
Query Table Type SELECT
Read Table Table SELECT SINGLE
Update Table MODIFY
Delete Table DELETE
Create Table INSERT

Additionally, the update function module exports parameter ET_RETURN of type BAPIRET2_TAB to return a table of messages as described in Mapping Delete and Update Operations,

For demo purposes, I simply hard-coded six messages using BAPIRET2’s TYPE and MESSAGE fields, two messages per type: information, Warning, and Error.


is_return-type = 'I'.
is_return-message = 'Info message 1'.
APPEND is_return TO et_return.
is_return-type = 'I'.
is_return-message = 'Info message 2'.
APPEND is_return TO et_return.
is_return-type = 'W'.
is_return-message = 'Warning message 1'.
APPEND is_return TO et_return.
is_return-type = 'W'.
is_return-message = 'Warning message 2'.
APPEND is_return TO et_return.
is_return-type = 'E'.
is_return-message = 'Error message 1'.
APPEND is_return TO et_return.
is_return-type = 'E'.
is_return-message = 'Error message 2'.
APPEND is_return TO et_return.





The Gateway framework formulates traditional, verbose SAP messages if fields such as MESSAGE_V1 are used.

Front-end system

In the front-end system, a Gateway Service Builder project was created in transaction SEGW.

The data model entity ‘Thing’ was created by importing RFC/BOR interface parameters. Similarly, operations are mapped to the corresponding function module parameters.

In the entity ‘Thing’, property ‘Description’ is updatable.

Web IDE

Finally, we arrive at more glamorous activities involving SAPUI5, Fiori, and the ubiquitous The Cloud.

Web IDE provides templates for easily generating SAPUI5 apps from a Gateway service. Web IDE can be installed on-premises or on SAP HANA Cloud Platform using the SAP HANA Cloud Connector to access on-premises Gateway systems.

To quickly create the app, I used the Fiori Master Detail template with the Gateway service entity set ‘ThingsSet’ and replaced the Detail view content with a sap.ui.comp.smartform.SmartForm.

Detail.view.xml



<mvc:View
    controllerName="com.pmc.messages.view.Detail"
    xmlns="sap.m"
    xmlns:core="sap.ui.core"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns:l="sap.ui.layout"
    xmlns:f="sap.ui.layout.form"
    xmlns:smartField="sap.ui.comp.smartfield"
    xmlns:smartForm="sap.ui.comp.smartform">
    <Page
        id="detailPage"
        navButtonPress="onNavBack"
        title="{i18n>detailTitle}"
        showNavButton="{device>/isPhone}">
        <content>
            <smartForm:SmartForm
                id="smartForm"
                checkButton="false"
                editTogglable="true"
                editToggled="editToggled">
                <smartForm:Group label="Thing">
                    <smartForm:GroupElement>
                        <smartField:SmartField value="{ThingID}" />
                    </smartForm:GroupElement>
                    <smartForm:GroupElement>
                        <smartField:SmartField value="{Description}" />
                    </smartForm:GroupElement>
                </smartForm:Group>
            </smartForm:SmartForm>
        </content>
        <footer
            id="detailFooter">
            <Toolbar id="detailToolbar">
                <content>
                    <ToolbarSpacer/>
                    <Button
                        id="buttonMessages"
                        icon="sap-icon://alert"
                        press="messagePopoverOpen"
                        text="{controls>/buttonMessagesText}"
                        type="{controls>/buttonMessagesType}">
                    </Button>
                    <Button
                        id="buttonUpdate"
                        enabled="{controls>/buttonUpdateEnabled}"
                        press="thingUpdate"
                        icon="sap-icon://save">
                    </Button>
                </content>
            </Toolbar>
        </footer>
    </Page>
</mvc:View>






As described in the SmartForm samples, the SmartForm control “creates a form for an OData entity set based on the OData metadata”. Since property ‘Description’ is updatable in the OData metadata, the description is updatable in change mode.


SmartForm

SmartForm.JPG

I use a local JSON model to handle control properties such as type and enabled. In the Detail view’s controller, the SmartForm’s editToggled function enables and disables a Save button by setting the model property to which the Save button’s enabled property is bound.


editToggled: function(oEvent){
     var oModel = this.getView().getModel("controls"),
            bEnabled = oEvent.getParameter("editable");
     if(bEnabled === true){
            oModel.setProperty("/buttonUpdateEnabled", true);
     } else {
            oModel.setProperty("/buttonUpdateEnabled", false);
     }
},





If a SmartForm’s property bindings are changed such as editing the Description property, the changes can be submitted and an Update operation triggered using the OData model’s submitChanges method.

The Save button’s press function:

  • Gets the view’s model
  • Calls the model’s submitChanges method
  • Performs a success or error callback

The error callback:

  • Parses the response
  • Creates an array of messages
  • Sets the array of message to a model which is bound to the Message Popover

Additionally, a Message Box is created for demo purposes.

Below are the Save button’s press function thingUpdate() as well as the Message Popover.

thingUpdate


    thingUpdate: function(){
        var oView = this.getView(),
            oModel = oView.getModel(),
            oModelControls = oView.getModel("controls"),
            oModelMessages = oView.getModel("messages");
        oModel.submitChanges(
            function(){
                // Success
            },
            function(oError){
                var oBody = JSON.parse(oError.response.body),
                    errorDetails = oBody.error.innererror.errordetails,
                    aErrorDetails = [],
                    sMessage = "";
                    if(errorDetails){
                        aErrorDetails = errorDetails.reduce(function(a,b){
                            function indexOfProperty (a, b){
                                for (var i=0;i<a.length;i++){
                                    if(a[i].message == b.message){
                                        return i;
                                    }
                                }
                                return -1;
                            }
                            if (indexOfProperty(a,b) < 0 ) a.push(b);
                                return a;
                        },[]);
                        for(i = 0, len = aErrorDetails.length; i < len; i++){
                            var message = aErrorDetails[i].message + "\n\n";
                            sMessage += message;
                        }
                
                        jQuery.sap.require("sap.m.MessageBox");
                        sap.m.MessageBox.show( sMessage, sap.m.MessageBox.Icon.NONE, "Update Messages" );
                
                        oModelControls.setProperty("/buttonMessagesText",aErrorDetails.length);
                        oModelControls.setProperty("/buttonMessagesType", "Emphasized");
                        oModelMessages.setProperty("/messageSet",aErrorDetails);
                
                    }
            }
        );
    },





The reduce() function eliminates duplicate array objects (messages) as suggested at Stack Overflow.

MessagePopover.fragment.xml


<core:FragmentDefinition
    xmlns="sap.m"
    xmlns:core="sap.ui.core">
    <MessagePopover
        items="{/messageSet}">
        <MessagePopoverItem
            type="{
                path: 'severity',
                formatter: 'com.pmc.messages.util.Formatter.formatMessageType'
            }"
            title="{
                path: 'severity',
                formatter: 'com.pmc.messages.util.Formatter.formatMessageTitle'
            }"
            description="{message}">
        </MessagePopoverItem>
    </MessagePopover>
</core:FragmentDefinition>






Messages

Messages.JPG

Conclusion

Overall, I tried to let the tools do the hard work,

  • Created remote-enabled function modules for basic CRUDQ operations
  • Returned a structure or table of type BAPIRET2
  • Used the Gateway Service Builder to import the service data model and map the operations
  • Used Web IDE to generate a Fiori Master Detail template from the Gateway service
  • Used a sap.ui.comp.smartform.SmartForm control for changing an entity and submitting the changes
  • Presented returned messages in a Message Popover control in a fragment XML view

— Scott Stefanich

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

  1. MUTHU KUMARAN

    Hi Scott,

    Thanks for the nice blog!

    Message Popover Item is deprecated now. Can you please let us know, how to use Message item instead(Shown in UI5 API reference)?

    When I directly add the aggregation MessageItem for Message popover, It threw an error.

     

    Thanks,

    Muthu

    (0) 

Leave a Reply