1
votes

I am trying to use OData V4 with SAPUI5. Although it seems quite straight forward, I am facing couple of issues.

I am using sap.ui.layout.sample.SimpleFormToolbar sample from Demokit. Implemented a OData V4 service to display the data in the simple form.

Changes i have done in this app:
1. manifest.json and
2. Page.view.xml for Context Binding of form control
3. Removed code reference to mockdata in controller and index.html

However, I am not able to get data with following errors:

2019-07-07 08:58:23.736110 Failed to update path /Suppliers(12345)/Country - **Error: Must not change a property before it has been read**

**Uncaught Error: Must not change a property before it has been read**

Another error is related batch mode. I have not implemented any batch processing in Odata impl.

2019-07-07 08:58:24.279114 **$batch failed** - Error: Network error
2019-07-07 08:58:24.281175 Failed to read path /Suppliers(12345) - Error: **HTTP request was not processed because $batch failed**

The code i am using is:

//manifest.json

{
    "_version": "1.12.0",
    "sap.app": {
        "id": "sap.ui.layout.sample.SimpleFormToolbar",
        "applicationVersion": {
            "version": "1.0.0"
        },
        "dataSources": {
          "supplierOData": {
            "uri": "https://supplierappp1014576trial.hanatrial.ondemand.com/SupplierApp/SupplierService.svc/",
            "type": "OData",
            "settings": {
              "odataVersion": "4.0"
            }
          }
        }
    },
    "sap.ui5": {
        "rootView": {
            "viewName": "sap.ui.layout.sample.SimpleFormToolbar.Page",
            "type": "XML",
            "async": true
        },
        "dependencies": {
            "libs": {
                "sap.ui.layout": {}
            }
        },
        "models": {
            "": {
                "dataSource": "supplierOData",
                "settings" : {
                    "synchronizationMode" : "None"
                }
            }
        },
        "config": {
            "sample": {
                "files": [
                    "Page.view.xml",
                    "Page.controller.js",
                    "manifest.json"
                ]
            }
        }
    }
}

//Page.view.xml

<mvc:View
    controllerName="sap.ui.layout.sample.SimpleFormToolbar.Page"
    xmlns:l="sap.ui.layout"
    xmlns:f="sap.ui.layout.form"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns:core="sap.ui.core"
    xmlns="sap.m">
    <VBox class="sapUiSmallMargin">
        <f:SimpleForm id="SimpleFormToolbar"
            binding="{/Suppliers(12345)}"
            editable="true"
            layout="ResponsiveGridLayout"
            labelSpanXL="4"
            labelSpanL="3"
            labelSpanM="4"
            labelSpanS="12"
            adjustLabelSpan="false"
            emptySpanXL="0"
            emptySpanL="4"
            emptySpanM="0"
            emptySpanS="0"
            columnsXL="2"
            columnsL="1"
            columnsM="1"
            singleContainerFullSize="false"
            ariaLabelledBy="Title1" >
            <f:toolbar>
                <Toolbar id="TB1">
                    <Title id="Title1" text="Address" level="H4" titleStyle="H4"/>
                    <ToolbarSpacer />
                    <Button icon="sap-icon://settings"/>
                    <Button icon="sap-icon://drop-down-list" />
                </Toolbar>
            </f:toolbar>
            <f:content>
                <Toolbar ariaLabelledBy="Title2">
                    <Title id="Title2" text="Office" level="H5" titleStyle="H5"/>
                    <ToolbarSpacer />
                    <Button icon="sap-icon://settings"/>
                </Toolbar>
                <Label text="Name" />
                <Input value="{SupplierName}" />
                <Label text="Street/No." />
                <Input value="{Street}">
                </Input>
                <Input value="{HouseNumber}">
                    <layoutData>
                        <l:GridData span="XL2 L1 M3 S4" />
                    </layoutData>
                </Input>
                <Label text="ZIP Code/City" />
                <Input value="{ZIPCode}">
                    <layoutData>
                        <l:GridData span="XL2 L1 M3 S4" />
                    </layoutData>
                </Input>
                <Input value="{City}" />
                <Label text="Country" />
                <Select id="country" selectedKey="{Country}">
                    <items>
                        <core:Item text="England" key="England"/>
                        <core:Item text="Germany" key="Germany"/>
                        <core:Item text="USA" key="USA"/>
                    </items>
                </Select>
                <Toolbar ariaLabelledBy="Title3">
                    <Title id="Title3" text="Online" level="H5" titleStyle="H5"/>
                    <ToolbarSpacer />
                    <Button icon="sap-icon://settings"/>
                </Toolbar>
                <Label text="Web" />
                <Input value="{Url}" type="Url" />
                <Label text="Twitter" />
                <Input value="{Twitter}" />
            </f:content>
        </f:SimpleForm>
    </VBox>
</mvc:View>

//Page.controller.js

sap.ui.define([
        'jquery.sap.global',
        'sap/ui/core/mvc/Controller',
        'sap/ui/model/json/JSONModel',
        'sap/ui/model/odata/v4/ODataModel'
    ], function(jQuery, Controller, JSONModel, ODataModel) {
    "use strict";

    var PageController = Controller.extend("sap.ui.layout.sample.SimpleFormToolbar.Page", {

        onInit: function (oEvent) {
            console.log("hello");

            jQuery.get({
                url: "/SupplierService/SupplierService.svc/Suppliers(12345)",
                success: function(data) {
                    console.log( "Recieved data: " + data);
                },
                error: function(error) {
                    // your error logic
                    console.log("Error while requesting odata: " + error);
                }
            });


        }

    });


    return PageController;

});

//index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="expires" content="0">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fullscreen – with toolbar</title>

    <script id="sap-ui-bootstrap"
        src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
        data-sap-ui-theme="sap_belize"
        data-sap-ui-resourceroots='{
            "sap.ui.layout.sample.SimpleFormToolbar": "./",
            "sap.ui.demo.mock": "mockdata"
        }'
        data-sap-ui-compatVersion="edge"
        data-sap-ui-async="true"
        data-sap-ui-preload=""
        data-sap-ui-frameOptions="trusted"
        data-sap-ui-oninit="module:sap/ui/core/ComponentSupport">
    </script>
</head>

<body class="sapUiBody" id="content">
    <div data-sap-ui-component
        data-name="sap.ui.layout.sample.SimpleFormToolbar"
        data-height="100%"
        data-id="container"
        data-settings='{"id" : "sap.ui.layout.sample.SimpleFormToolbar"}'
        style="height: 100%">
    </div>
</body>
</html>

I have added jquery call just to see if the odata is working or not.

Command used for CORS issue: "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --disable-gpu --user-data-dir=~/chromeTemp

I am actually pointing to odata service in the same project. The same is deployed on Sap Cloud: https://supplierappp1014576trial.hanatrial.ondemand.com/SupplierApp/SupplierService.svc/

Thanks for your time.

  • EDIT:

Added the solution as an answer below.

1

1 Answers

2
votes
  • The error:

    "must not change a property before it has been read" is understood to be CORS issue. Accepting Cross origin requests on server side can be done by configuring web.xml. Note that this should be re-evaluated for production use.

<filter>
          <filter-name>CorsFilter</filter-name>
          <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>CorsFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
  • The error:

    "$batch failed - Error: Network error" is resolved by changing groupId to $direct. This means we are sending individual network calls to odata service.


"models": {
            "": {
                "dataSource": "supplierOData",
                "settings" : {
                    "synchronizationMode" : "None",
                    "groupId": "$direct"
                }
            }
        },

This took away those errors and I see the data is rendered into form fields.

Thanks for your attention.