Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
scott_stefanich
Active Participant

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

Message Box

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 ModuleIMPORTING TYPEEXPORTING TYPEABAP Keyword
QueryTable TypeSELECT
ReadTableTableSELECT SINGLE
UpdateTableMODIFY
DeleteTableDELETE
CreateTableINSERT

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

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

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

2 Comments