Quantcast
Channel: SAPUI5 Developer Center
Viewing all 789 articles
Browse latest View live

BATCH PROCESSING WITH XSODATA

$
0
0

     This blog will take you through the steps of using odata batch processing. There are multiple scenarios where we might need batch processing, such as making a single call to insert/update/delete large amount of data. First, we will see how to bind data to table with odata.read(), further we will see how to add new data, update existing data and finally send a batch call to xsodata.


Prerequisite:

  • Basics of how to create and expose xsodata
  • Basic knowledge in UI5
  • Having a xsodata ready in hand to follow the tutorial. This tutorial has a xsodata with one table containing 3 columns.

 

Note: In this tutorial we’ll manually enter the key fields in the UI

 

UI Creation

                We’ll create a UI5 table which consist of 3 column, the rows are specified as input field which we can edit and add new rows on the go. Use the below code to create the view named “ODataBatch” with a sap.m.Table.


<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"            controllerName="treetabletest.OdataBatch" xmlns:html="http://www.w3.org/1999/xhtml">      <Page title="Title">            <content>                  <Table id="customerTable" class="sapUiMediumMarginTop" inset="false" items="{/customer}" visibleRowCount="5" navigationMode="Scrollbar">                              <headerToolbar>                                    <Toolbar design="Solid">                                    <Title text="Customer" level="H2"/>                                    <ToolbarSpacer></ToolbarSpacer>                                   <Button icon="sap-icon://add" type="Transparent" id="addReportButton" press="addCustomer"/>                                 </Toolbar>                              </headerToolbar>                              <columns>                                    <Column>                                          <Text text="ID" hAlign="Right"/>                                    </Column>                                    <Column>                                          <Text text="Name" hAlign="Center"/>                                    </Column>                                    <Column>                                          <Text text="Mobile"/>                                    </Column>                              </columns>                              <items>                                    <ColumnListItem>                                          <cells>                                                                                          <Input value="{ID}"/>                                                <Input value="{NAME}"/>                                                <Input value="{MOBILE}"/>                                          </cells>                                                                   </ColumnListItem>                              </items>                        </Table>            </content><footer>                  <Toolbar>                        <ToolbarSpacer/>                              <Button text="Save" type="Accept" press="submitBatch"></Button>                  </Toolbar>            </footer>      </Page></core:View>

 

Here items is binded with customer for which we will set the model in controller. Also notice the ColumnListItem has three input fields which is binded to ID, NAME and MOBILE. There is a toolbar in the table with an add icon button which will add an empty row in the table. A footer with Single button is added to submit the batch operation. This will give you a complete UI to learn all the needed operations. Next we move on to the controller part of the above UI. There we will learn about ODataModel and JSONModel.

 

Controller for UI

                Just defining the controller will instantiate it and the view is rendered. Once you run the application, it will render the UI which we created above (Refer screenshot below).


sap.ui.controller("treetabletest.OdataBatch", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* @memberOf treetabletest.OdataBatch
*/
});

    

Batch_1.PNG1. UI after controller instantiation

                Now as next step we will create a OData model and bind the data to the customer table using OData.read() method. All these steps will be done in init() method of the controller.


sap.ui.controller("treetabletest.OdataBatch", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* @memberOf treetabletest.OdataBatch
*/
custTableLength : 0,
onInit: function() {            oModel = new sap.ui.model.odata.ODataModel("http://LINKTOYOURODATA/TreeTableTest/Service/customer.xsodata");            this.getView().setModel(oModel);            oThis = this;            var jsonModel = new sap.ui.model.json.JSONModel();            oModel.read("customer",{                  success : function(oData, oResponse){                        jsonModel.setData({"customer" : oData.results});                        if(oData.results.length == 0)                              oThis.custTableLength = -1;                        else                              oThis.custTableLength = oData.results.length;                        oThis.getView().byId('customerTable').setModel(jsonModel);                  },                  error : function(err){                                            console.log(err);                  }            });      },
});

Batch_2.PNG

2. After Binding Model

     In the above code we have initialized a variable custTableLength, which will store the total number of entries bound to the table. This will be useful to differentiate the new rows that are created. By running the app we can see the data bound to the table with JSONModel.  Now we will define the addCustomer() method in controller. This will add a new row with empty text fields where user can create a customer. The method will push a new empty row to the model data by accessing the table.


addCustomer: function(oEvent){            modelData = this.getView().byId('customerTable').getModel().getData();            var newEntry = new Object();            newEntry.ID = "";            modelData.customer.push(newEntry);            this.getView().byId('customerTable').getModel().setData(modelData);      },

 

Batch_3.PNG

3. Creating a new row with empty text fields


     Here I’ll update row 2, change the name as Peter from John and fill the 3rd row. We’ll make PUT request for existing data, POST request for newly created ones and finally submitting a batch request. We’ll create submitBatch() function as below


submitBatch: function(){            var changeOperations = [];            v=this.getView().byId('customerTable').getModel().getData().customer;            for(var i=0; i<this.custTableLength; i++){                  sPath = "/customer("+v[i].ID+")";                  changeOperations.push(oModel.createBatchOperation(sPath,"PUT",v[i],null));            }            for(var i=this.custTableLength; i<v.length; i++){                  changeOperations.push(oModel.createBatchOperation("/customer","POST",v[i],null));            }                oModel.addBatchChangeOperations(changeOperations);            oModel.submitBatch(function(oData, oResponse, aErrorResponses){                  if(aErrorResponses.length>0){                        sap.m.MessageBox.alert("Error in Creating. Please try again...");                        console.log(aErrorResponses);                  }else{                        sap.m.MessageBox.alert("Batch Successfull", {});                  }                  });                                }

 

First we declare an array, changeOperations - to hold the list of request. The methods related to batch operations which we used are explained below


oModel.createBatchOperation(sPath, sMethod, oData, parameters)

sPath– String containing the path for collection

sMethod– PUT, POST, DELETE, GET

oData– data payload for create, update or delete

 

addBatchChangeOperations(aChangeOperations)

aChangeOperations– array of change operations

Here we will add change batch operations such as PUT, POST or DELETE. The operations in the array will be included in a single changeset. If illegal batch operations is added to the change nothing will be performed and false will be returned.


submitBatch(fnSuccess,fnError,bAsync,bImportData)

fnSuccess - a callback function which is called when the batch request has been successfully sent. Note: There might have errors occured in the single batch operations. These errors can be accessed in the aErrorResponses parameter in the callback handler. The handler can have the following parameters: oData, oResponse and aErrorResponses

fnError - a callback function which is called when the batch request failed. The handler can have the parameter: oError which contains additional error information

bAsync– true for Asynchronous request. Default: true

 

After successful batch process a confirmation message is displayed by our application. Error is displayed if something goes wrong.

 

** We used sap.m.MessageBox.alert(); so we need to insert the below code in the beginning of the controller.

jQuery.sap.require(“sap.m.MessageBox”) 

Batch_5.PNG

     4. One New row and Updated rows


Batch_6.PNG

5. Confirmation message displayed after successful batch operation

 

As stated in the beginning, the odata batch operations will go as a single changeset. The below image is a reference for the request which we are sending as a single changeset.

 

changeset.PNG

6. Changeset for the batch operation

 



Hope this blog helps you in creating batch operations. If you face any issues in creating batch operations just leave a comment below.


PS: The above example is just to give an overview on batch operations. You can use the generic event to handler for PUT request only for updated values.



OData is RESTful, what is REST ?

$
0
0

Introduction : SAP documentation refers that OData is RESTful but does not explain well what REST is ? The blog below is a compilation from other sources and throws some light on what is REST and provides some further links for self study.

Target audience :  SAP UI5 / Fiori Consultants

Date Published : 8th Feb 2016

 

Below is the common slide that comes up many times while reading up about OData in relation to SAP UI5 or Fiori.

Capture.PNG

 

6 Design Constraints of a RESTful Architecture


ss.jpg

  • Client-server architecture: The participants of a RESTful architecture must implement the client-server model, which allows for the client and server software components to be developed independently. It assumes that the client will take no part in long-term data storage and that the server will take no part in the presentation of the data it supplies. This principle is known as the Separation of Concerns.
  • Cacheability:  In order to improve performance and scalability, every server response must carry with it an indicator to denote whether or not it can be cached for future use. This is to prevent the client from working with outdated data.
  • Statelessness : The communication between participants must be stateless. A stateless interface requires the client to supply all the necessary information for the server to process the request. Session information must be held on the client side. The server can hold client state information, however, the state information must be known to, and addressable by the client.
  • Layered System : The communication between participants must be layered. When the client communicates with a server, it should not be able to distinguish whether it has communicated with the actual end-point server that will supply the requested information, or some intermediate server used for system scalability or security.
  • Uniform interface : between the clients and servers decouples the architecture. A uniform interface has the following characteristics:
    • The server must provide the client with a representation (for example a URL) of its resources.
    • A means must be provided for the client to manipulate those resources (for example provide operations such as Create, Read, Update, Delete, and so on).
    • All responses sent to the client must be self-describing.
    • The manipulation of server-side resources can only be performed by hypermedia (that is links) supplied by the server.
  • Code-On-Demand : The server is able to deliver code-on-demand to the client. At the request of the client, the server should be able to supply additional executable code to extend the client’s capabilities. This is addressed in OData by the use of function imports.

 

Links

http://www.odata.org/

https://en.wikipedia.org/wiki/Representational_state_transfer

http://rest.elkstein.org/

Using Geo Heatmaps with SAP UI5

$
0
0

2016-02-09 15_13_24-AkuaJs for SAP UI5 - Microsoft Edge.png

 

Lately I wrote this article about maps in UI5  Using Geo Maps with SAP UI5  .In here I focused on how we can visualize data by coloring certain areas like districts or countries. Sometimes however you might not either have a shape file at hand or your data is referring to GPS coordinates (instead of areas) . In this case using a Heatmap is more approriate. I have recently added such a control into my charting library and will show how it can be used in an UI5 app here. The control is based on Google Maps and this heatmap library here. Lets start by creating a simple UI5 App and by adding the required dependencies for the heatmap and the AkuaJs charting library.

 

<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script><script src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/heatmap/heatmap.min.js"></script><script src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/heatmap/gmaps-heatmap.js"></script><script data-main="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/main.js" src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/require.js"></script><script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"            id="sap-ui-bootstrap"            data-sap-ui-libs="sap.m"            data-sap-ui-theme="sap_bluecrystal"></script>

 

Next we will just define some quantitative data, add the map control to the app and hook it up to our data. The AkuaJs library is based on a multidimensional  data model so every data point has the form E(D("coordinates"), { lat: 51.76, lng: -1.55 }) where the D() function defines the dimension and the E() function defines an element of the corresponding dimension. A value is assigned by creating a Tuple with the T() function: T([E(D("coordinates"), { lat: 51.76, lng: -1.55 }), E(D("text"), "Point 1")], 16) . The assignment of a quantitative value to  a corresponding coordinate  is based on the longitude / latitude coordinates passed in the first E() function, the corresponding label is passed in the second E() function of a tuple. A more detailed documentation of the AkuaJs API can be found here.

The Map control is added like shown in the listing below and has the following properties that need / can be configured:


  • axis0: here we pass the list of long / lat coordinates
  • connection: here we pass the quantitive data that needs to be visualized
  • numberFormats: the number format in D3 notation
  • center: the Longitude / Latitude coordinates of the map
  • zoom: the initial zoom factor
  • showMarkers: set to true if Google Maps markers shall also be displayed in the map
  • click: a function to listen to click events whenever a marker is clicked

 

<!DOCTYPE html><html><head>    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">    <title>Geo Heatmap  Sample</title>      <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>    <script src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/heatmap/heatmap.min.js"></script>    <script src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/heatmap/gmaps-heatmap.js"></script>     <script src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/D3/d3.min.js"></script>    <script data-main="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/main.js" src="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/require.js"></script>    <link rel="stylesheet" href="https://cdn.rawgit.com/Qrist0ph/AkuaJs/latest/dist/plain/libs/nvd3/nv.d3.min.css" type="text/css" />    <script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"            id="sap-ui-bootstrap"            data-sap-ui-libs="sap.m"            data-sap-ui-theme="sap_bluecrystal">    </script>    <script type="text/javascript">        jQuery.sap.registerModulePath('AkuaJs', 'https://cdn.rawgit.com/Qrist0ph/AkuaJs-UI5/latest/build/AkuaJs');              jQuery.sap.require("AkuaJs.GeoHeatmap");        var tuples = [           T([E(D("coordinates"), { lat: 51.76, lng: -1.55 }), E(D("text"), "Point 1")], 16),           T([E(D("coordinates"), { lat: 50.75, lng: -1.55 }), E(D("text"), "Point 2")], 22),           T([E(D("coordinates"), { lat: 48.15, lng: 9.4667 }), E(D("text"), "Point 3")], 30),           T([E(D("coordinates"), { lat: 52.35, lng: 4.9167 }), E(D("text"), "Point 4")], 28),        ]        new AkuaJs.GeoHeatmap({            axis0: A({                crosslists: [TCL(tuples)]            }),            connection: tuples,            numberFormat: ',.2',            showMarkers: true,            center: { lat: 52.35, lng: 4.9167 },            zoom: 6        })         .placeAt('center');    </script></head><body>    <div id="center"></div></body></html>

Some Best Practices derived from the SAP Fiori Templates in SAP Web IDE

$
0
0

Some Best Practices derived from the SAP Fiori Templates in SAP Web IDE.

 

In 2015, the attentive observer will have witnessed an evolution of static demo applications in the demokit into real SAP Fiori templates in SAP Web IDE. Kickstarting applichttp://scn.sap.com/servlet/JiveServlet/showImage/38-133175-814233/template-images.PNGation development has never been easier. But besides planting these applications on SAP Fiori home turf, this process also affected the programming model, helped to close gaps and fostered the integration and usability of features across the different technological layers in general (Runtime, Controls, UShell). Now it’s about time to read between the lines of code and flesh out some things that really make developing apps with SAPUI5 much easier.

 

 

But before we get started let`s first have a look what we are talking about. There are actually several ways to make use of the example app coding I will talk about:

  1. Find them in the demoapps section of the SAPUI5 Demokit (actually you will find them in the OpenUI5 Demokit as non-flp versions as well).
  2. Generate your own app from templates directly in SAP Web IDE.
  3. Browser the code on github (OpenUI5 versions only: master-detail / worklist)

 

 

 

Full MVC plus light view models


Data binding is something you have to embrace. It works best if you assess it with the right level of abstraction. In the end it’s about nothing more than having the ability to keep things in sync. The programming model in SAPUI5 with its controls, their bindable properties and descriptive xml-views paired with functional js-controllers means that view models are undeniably the way to centrally orchestrate your views with one dedicated interface. If only everything in life was as easy as calling ‘setProperty’ on one of your models...

Still, full MMVC is possible, but for lightweight SAP Fiori applications, a model that simply controls the state of your view might make sense in most use cases.

 

Descriptor aka manifest.json

 

Being descriptive is not just a matter of serialization. But it still helps in that regard. Thanks to the new descriptor concept in SAPUI5, all application-specific configuration relevant for the external technical environment is now aggregated into one central file. It’s as simple as not having to read an entire book if you can already judge it by its cover. Machines like it that way. And your app development routines will also profit from that. Access the descriptor attributes via APIand safe lines of code by descriptive i18n and OData model creation and configuration.

Here’s more documentation about this.

 

BaseController.js

 

One of my favorites to be honest. Although this guy is not even a controller, he is the most instantiated in your application. And because everyone who writes code runs into the dilemma of repeating himself on a daily basis, we all should love him. Put all your reusable functionality on his shoulders. He can handle it, and he’ll carry these generics through your application. And once you reach the point where you need to be more specific: simply override in this child!

 

sap.m.routing.Router

 

Your app is nothing without its views. The old world of sap.ui.core.routing.Router in SAPUI5 was dark and inscrutable. Although it was possible to create deep links to specific routes, do hash-based navigation and on-demand view instantiation, its hands did not reach very far. Implementing complex UI-patterns like master-detail or even cross-pattern with routing was no fun at all, leaving you to deal with complex sub-route configurations.

The new contender for giving you a masterclass in routing is the sap.m.routing.Router

It comes with more detailed configuration options: By exposing targets to the developer, for instance, it’s now possible to define multiple targets per route. No more having to deal with complex cascading configuration into sub-routes, instead a clear route – target relationship. On top of this, check out greedy routes, catchall config, asynchronous view loading and much more. You can sure expect a lot from this ‘new guy in town’.

 

Folder structure

http://scn.sap.com/servlet/JiveServlet/showImage/38-133175-814241/folders.PNG

If you think structuring your application is a no-brainer, you’ve probably never developed in a huge ecosystem made up of various technologies, tools and dependencies. Just think of questions like how to separate tests from productive code (and this is not only about test files). Think of CI: how can this work if your test suite

s are all scattered around individual apps? Or even worse: not there at all? When it comes to maintenance or bug fixing, it becomes even more obvious that some conventions really help to speed up the process. It`s like in your

local supermarket: you’ll find your milk next to the cheese and all veg in one place. Embrace uniformity! Anything else makes no sense!

Inside the templates, we see the MVC footprint very clearly. Usage of the model folder for all files that manipulate your data, the controller folder for all your hard working application logic, and the view folder for all views and fragments. If you really need an utils folder for all your little helpers, you might have to think about making some clear decisions regarding the responsibilities of your assets. Finally there is a folder for everything surrounding the mock server (metadata, annotations, and your local server logic), a test folder for test files and standalone runnables (yes, this is a component-based application, no index.html needed) and finally the Component.js next to the manifest.json on the top level of the app to rule them all.

 

Mock server handling

 

Nope, a mock server is not something you can order at your local hardware retailer! And yes, it is something that comes with SAPUI5... but once again nope, it’s not SAPUI5’s responsibility to provide its functionality out of the box. Mock server is an API. And just like all other things in SAPUI5 are handled, you have to instantiate it, configure it and then enjoy the work it does for you. Full control but also full responsibility. That is the way to go.

Use it to mock your OData service for offline development, do ninja-stuff to test your error handling and finally mock whatever path you want. Inspiration can be found here, and pure documentation here.

 

Content densities (compact vs. cozy)

 

If you want to experience compact and cozy, you simply have to open the Explored app and click on the gear icon in the top right corner of the master list. Here you’ll find one setting called “Compact Content Densities”. Switch it on and you’ll get the entire Explored app displayed in the more desktop-friendly compact mode while the default for the sap.m library displays in “cozy” for mobile scenarios (which is in fact a throw-back to the past when the “m” in sap.m stood for mobile, whereas you could now say the m stands for modern).

Technically this is nothing but CSS. In the case of the Explored app, this class is set straight to the body tag of your html. All the controls below have selectors in their CSS that wait for this in the body to tick in and influence appearance. Now assume you will run your application in a container like the SAP Fiori launchpad and this will potentially control this via settings, as we find in Explored. There has to be a contract, and this is the body tag to allow one to override the other. The logic in the Component.jswill help you make the right assumptions regarding what your container already did for you (plus a default selection if nothing has been set) and the right class will be set to the App-control in the App.controller.js. Also use this logic down the line to this class, to controls in the static area of your DOM like sap.m.Dialog for instance.

 

Use SAP Web IDE

 

Ok! I have to confess this one isn’t really a best or “good” practice. Let`s call it a teaser. In the end you decide for yourself, but let me give you some reasons why developing apps with SAPUI5 and SAP Web IDE makes perfect sense.

First of all, SAP Web IDE builds on top of SAPUI5 - it actually uses SAPUI5 internally and was built to develop SAPUI5 applications. This is not just to prove that SAPUI5 is a powerful toolset, it also means that some developer dreams are finally close to coming true:

Think about WYSIWYG (aka Layout Editor; drag and drop to model your views), Descriptor Editor for the manifest.json (no more wasting time looking up complex configuration options), code snippets (tests, views, controllers – forget the obvious, let`s write more code instead) and many more cool things. Just check it out.

And once you’re on top of it, start extending the tool itself. Build your own templates, tools, side panels and much more. It’s an open party and you’re always invited! All you need is the documentation to get started

 

Final Words? Not this time! Everything’s been said already. Now it`s up to you to jump on the template train and get your project started!

Fiori launchpad security - Which SHA certificate am I using ?

$
0
0

Well, this is my first blog.

 

I will explain two concepts here.

 

  1. End of support for the SHA-1 algorithm used within online certificates (Most Fiori launchpad uses this certificate)
  2. New Security tab in chrome DevTools to find out everything about the certificate used and the connection type. In addition, it gives you the handy ability to drill down further to inspect all resources coming from that origin via the Network Panel

 

As technology evolves, it is critical to stay ahead of those who wish to defeat cryptographic technologies for their malicious benefit.

 

SHA-1 is a hash algorithm used to encrypt websites. While SHA-1 uses hashes which are 160 bits long, there are also other standards -- namely SHA-2, which implements a variety of hash sizes, and SHA-3, which is yet to become commercial or widely adopted as a standard.

 

From early 2016, Chrome will display a certificate error if websites are signed with an SHA-1-based signature, use an SHA-1 certificate issued after 1 January 2016 or are chained to a public CA.

 

How to know if your Fiori launchpad is secure ? Current solution for those of you who want data about page security is to

  1. Click onto the little lock icon next to the URL
  2. Then parse the info available on the “Connection” tab.

 

The newSecurity panel introduced in Chrome 48 makes it a lot easier to see any issues you have with certificates and mixed content. You can head to it directly in DevTools or by clicking on the URL bar’s lock icon. Screen shot below for refrence


sha.PNG

The initiative to migrate from SHA-1 to SHA-256 (SHA-2) is the next proactive phase to better secure websites, intranet communications, and applications. Organizations need to develop a migration plan for any SHA-1 SSL and code signing certificates that expired after December 31, 2015.


Hope this blog gives insight into securing launchpad. Especially: Users accessing launchpad from mobile browser instead of using Fiori client.

New Version of SAP Web IDE Released for Local Installation

$
0
0

The version of SAP Web IDE Local Installation has been updated to SAP Web IDE 1602 (based on the January release of SAP Web IDE on HANA Cloud Platform).


The local installation version allows you to experience the SAP Web IDE capabilities and see how simple it is to create and extend SAP Fiori/SAPUI5/hybrid applications with SAP Web IDE.

 

It is available for test and evaluation purposes (non-productive usage only) via SCN, and contains many new features.

 

We strongly recommend our cloud offering as this allows you to benefit from the latest features of SAP Web IDE without any installation effort.

It also enables seamless integration with SAP HANA Cloud Platform services e.g. Fiori launchpad, Git, Fiori Cloud edition, HCP Mobile services and additional future integrations like HCI, Usage Analytics.

 

Based on the interest from customers, we are looking into releasing a local version of the SAP Web IDE also for productive usage in 2016.

We are currently examining the legal framework and conditions under which such a version should be released (e.g. what will be the capabilities, support model, etc.)

We plan to share more updates on the topic towards our 1605 release (May 2016).

 

The focus of SAP's strategy will remain delivering SAP Web IDE with the full set of capabilities and full support via SAP HANA Cloud Platform.

 

Stay tuned for more updates…


Master/Detail Kapsel Offline Application

$
0
0

Prerequisites

  • Make sure you have an OData service which supports CRUD operations and the service has been configured as HCP destination to access it from SAP Web IDE.
  • Make sure you have setup Hybrid App Toolkit environment (all prerequisites, including MobileSDK3 SP06) in your local machine. To setup Hybrid App Toolkit, refer tohttps://help.hana.ondemand.com/webide_hat/frameset.htm.
  • You have started the Hybrid Toolkit Connector and is listening to port 9010
  • You have configured an Hybrid Application in SMP3 Server based on the backend URL you are going to use to create the Offline Application

 

StepActionsExpected Results
Enable “Hybrid App Toolkit” External Plugin
  1. 1.  
Start SAP Web IDE
  1. 2.  
  2. Press ToolsàPreferencesmenu
Preferences pane displayed
  1. 3.  
  2. Select Pluginsà Optional Plugins in preferences pane
  1. 4.  
In Plugin Repository, select “SAP Plugins”.
  1. 5.  
Select to enable the “Hybrid App Toolkit plugin” and press “Save” button.External Plugin is enabled
  1. 6.  
Refresh the browser
Create New Project based on SAPUI5 Master Detail Kapsel Offline Applicaion Template
  1. 7.  
  2. Press FileàNewàProject from Templatemenu
New Project wizard opened
  1. 8.  
  2. Select “SAPUI5 Mobile Applicationsà SAPUI5 Master Detail Kapsel Offline Application” template and press Next
  1. 9.  
Specify a project name and press Next
  1. 10.
In Data Connection section, select “Service URL” and select “SMP IGW Service” for the  Service Information from the list
  1. 11.
Enter user credentials as smpAdmin/s3pAdmin when promptedService is connected and display the collections in the Details section
  1. 12.
press Next
  1. 13.
In Template Customization, fill-up the entries as below
Project Namespacemd (its optional)
Master Section
TitleProduct List
OData CollectionProduct
Search PlaceholderSearch
Search TooltipSearch for items in list
Search FieldName
Master Data Fields
Item TitleName
Numeric AttributePrice
Units AttributeCurrencyCode
Detail Section
TitleProduct Details
Additional Attribute1Category
Additional Attribute2ShortDescription
Create/Edit Section
Create Input for Key ColumnsSelected
Information Section
OData NavigationSupplierDetails
Navigation Attribute1SupplierName
Navigation Attribute2EmailAddress
Navigation Attribute3Country
Press Next
  1. 14.
Press FinishNew Master Detail Offline Project is created and displayed in Workspace.
Preview in SAP Web IDE
  1. 15.
Expand Project folder in Repository Browser
  1. 16.
  2. Select index.html and press Run à Run menu
Application Preview window open in a new browser tab
  1. 17.
When prompted for user credentials in Application Preview window, enter smpAdmin/s3pAdmin and click Logon.Application loads the data in the Application preview view window based on the attributes configured in Template customization section
  1. 18.
Click on a List item in left-hand sideThe right-hand side frame loads the detail screen based on the clicked row
Configure Project Settings for  Hybrid Mobile App
  1. 19.
In SAP Web IDE, right-click on the project folder , select “Project Settings” context menu
  1. 20.
Select “Device Configuration” section in Project Setting
  1. 21.
Complete the device configuration with the following.Application Section
App Name<specify a name>
App ID<specify the app id configured in SMP3 Server>
Description<enter some app description>
Version
  1. 1.0.0
Platforms
On WindowsSelect Android only
On MacSelect iOS and Android (if you have both)
Plugins
CordovaDevice, Network Connection
KapselLogon Manager, Offline OData
SMP Server
Host<specify your SMP hostname or ip address>
Port<specify your connection port>
  1. Note: Master/Detail Hybrid application retrieves data from SMP server and hence, Application ID needs to be setup on a SMP Server and the same Application ID needs to be specified in the Project Settings à Device Configuration.
  1. 22.
Press Save and Press Close in Project Setting DialogThe project setting dialog is saved and closed.
Run On - Android Device
  • To run on Android device, Android device is connect to the laptop through USB cable
  • You must have installed Google USB driver from Android SDK Manager.
  1. 23.
In Repository Browser, select the Project
  1. 24.
  2. Right click on the project and selectRunàRun On  àAndroid Device menu
Web IDE issues a command to local Hybrid Connector server to create a Cordova project and Web IDE console display the log messages from the connector about the progress
  1. 25.
Project compiled and .apk file is generated, installed and launched on  Android device In the launched application, SMP3 Logon Form appears as a first screen.
  1. 26.
Enter the following credentials to the SMP3 Logon Form in the application
UsersmpAdmin
Passwords3pAdmin
Security Configdefault
And press Register button
Successfully registers the application to the SMP3 Server and Passcode screen appears
  1. 27.
Press “Disable Passcode” button and press “Submit” buttonSuccessfully logon to the SMP3 server and the application’s Master page appears with Product List data
  1. 28.
Press on a row in Master pageNavigate to detail page displaying Product details and the Supplier  information
  1. 29.
Press Edit button in detail pageThe product details page toggles to edit mode and display the Product data in an Edit Form.
  1. 30.
Change the product price and press Save buttonData successfully changed and toggle the detail page from edit mode to read-only mode
  1. 31.
Since the update is performed when the device in online mode, verify the changes in backend service
  1. 32.
Press Back button in Title barPage navigates back to Master Page.
  1. 33.
Press Back button on the Android Device (phone or tablet) until the application closedApplication closed and Android device home screen appears
Run in Airplane mode – on Android Device (Offline mode)
  1. 34.
  2. In the Android device, choose Settings àWireless and network àMore settings
  1. 35.
Turn on Airplane mode in the more settingsAndroid device is now in Airplane mode
  1. 36.
Go back to the Home screen and run the applicationThe application now retrieves the data from Offline store and function properly as before (when it is in online mode)
  1. 37.
Press a row in Master pageNavigate to detail page displaying Product details and the Supplier  information
  1. 38.
Press Edit button in detail pageThe product details page toggles to edit mode
  1. 39.
Update product in the edit page and press save button.Data saved and toggle the page to read mode
  1. P.S. Since the device is in airplane mode, the data persist in the offline store & will be synced when device gets a connectivity.
  1. 40.
Press plus icon on Master pageBlank Product form in create mode appears in detail page.
  1. 41.
Add a new product data in the Product form and press Save buttonNote: Atleast enter values for ProductId,  Name,Price, SupplierId, CurrencyUnit columnsNew product created in offline store.
  1. 42.
Verify the changes in the back-end dataThe changes are not pushed to the back-end and hence the changes are not reflected in the back-end data
  1. 43.
Turn-off airplane mode in the device.Device connected back to network (Wifi/3G/4G)
  1. 44.
Start the application againApplication started and pushed the changes persisted in the offline store to the backend.
  1. 45.
Verify the changes in back-endChanges are available in the back-end now.

Appendix – A: Setting Up Gateway Service (IGW) on SMP3 Gateway CockpitIf you have installed your own SMP3 (SAP Mobile Platform) Server in your local environment, then you will have SAP Gateway Cockpit icon added to your desktop.The following steps describe the setting up an odata service on SAP Gateway Cockpit. Makesure you already started the SAP Mobile Platform service (SMP3 service)

  1. Double-click on “SAP Gateway Cockpit” icon in the desktop. It will open the SAP Gateway Cockpit on the browser
  1. Enter the admin credentials in the Gateway Cockpit logon screen and press Log On button.

 

  1. Select “DESTINATIONS” tab in the cockpit and press “New Destination” button
  1. Select “JPA” as destination type, “JPA” as destination name and “com.sap.espm.model” as Persistent Unit as below

 

  1. Click “Save” button. The new destination “JPA” is added.
  1. Select “SERVICES” tab and select the default “EspmService” to add a destination to this service.

 

  1. Click the hyperlink “EspmService” in the service list. It will open the Service details dialog as below

 

  1. Click “Add Destination” button and select “JPA” destination you added in step 4 and click “OK”. Click “Close” button to close the dialog.

 

  1. Click “Open Service Document” link in the service list. This will open the service document in a browser. Enter SMP admin user credentials when prompted. It will list the service collections as below

   This completes the setting-up of IGW odata service on SMP3 Gateway cockpitAppendix – B: Setting Up Application on SMP3 ServerMake sure that you have added the certificate of the SMP3 Gateway server to the SMP 3.0 server before setting up the Application on SMP3 server.  To add a certificate, refer to http://danielva-xpvm.dhcp.oak.sap.corp/webworkflows/Getting_Started/index.html#odatademo

  1. Logon to SMP3 Server admin console (https://<serverhost>:8083/Admin )

 

  1. Click on the Application tab in Admin console

  

  1. Click “New” button and fill-up the following in the new Application dialog

             

  1. Click Save button. The Application detail screen appears.
  1. Click “BACK END” tab and fill-up the backend end-point as https://<your smphost>:8083/gateway/odata/sap/EspmService;v=1/, as below

 

  1. Click “Add” button in SSO Mechanisms section and add the “Technical User (Basic)” SSO mechanism as below.
  1. Click “AUTHENTICATION” tab, select  Existing Profile tab and select “default” as Profile name

 

  1. Click “Save” and click “Close” button.  It will return to the Applications list page and the created application appears in the list as below

  

  1. Click the “ping” button to verify the back-end URL is reachable from SMP3 Server as below

 

 

This completes the steps to setup Application on your own SMP server.

Manifest Routing in SAP Web IDE

$
0
0

In this blog I will use the ES4 system which is publicly available.  If you do not have an account on the system see

 

Sign up and get started with the SAP Gateway - Demo Consumption System

 

If you are unfamiliar with setting up a destination see

 

How to configure an external GW system with SAP Web IDE

 

which details connecting to the older ES1 system, but make sure to set the connection up for ES4.  If you are new to SAP Web IDE see

 

SAP Web IDE - Enablement

 

This blog deals with apps that utilize a manifest.json file.  If your have an app where the routes are defined in the Component.js see

 

Creating a Fiori Starter Application with an Additional View



Create An App


Lets start by creating a Master Detail app.  First choose File -> New -> Project from Template

Choose SAP Fiori Master Detail Application with Available Version set to SAPUI5 1.32 or greater

Choose Next and provide a project name for example OrdersDemo

Choose Next and with the Source Service Catalog selected choose your ES4 system and the service EPM_REF_APPS_PO_APV_SRV

Choose Next and provide the following template values

 

Screen Shot 2016-02-12 at 10.19.36 AM.png

 

Choose Next and Finish to complete the template.

 

Within the app navigate to webapp/test/testFLP.html and choose the Run option and verify that your app is working as expected.

Screen Shot 2016-02-12 at 10.05.43 AM.png

 


Adding a View

 

Right click on the webapp/view folder and choose New -> File providing the name ItemDetails.view.xml.   Add the following content to the view

 

<mvc:View controllerName="com.po.demo.controller.ItemDetails" xmlns:semantic="sap.m.semantic" xmlns:core="sap.ui.core"  xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:form="sap.ui.layout.form">  <semantic:DetailPage  id="itempage"  navButtonPress="onNavBack"  showNavButton="{device>/system/phone}"  title="Item Details">  <semantic:content>  <form:SimpleForm minWidth="1024">  <core:Title text="Item Details"/>  <Label text="Product"/>  <Text text="{Product}"/>  <Label text="ID"/>  <Text text="{POId}"/>  <Label text="Position"/>  <Text text="{POItemPos}"/>  <Label text="DeliveryDate"/>  <Text text="{DeliveryDate}"/>  </form:SimpleForm>  </semantic:content>  </semantic:DetailPage></mvc:View>

 

 

Create another file in the directory webapp/controller providing the nameItemDetails.controller.js.  Add the following content to the controller

 

sap.ui.define([  "com/po/demo/controller/BaseController"  ], function (BaseController) {  "use strict";  return BaseController.extend("com.po.demo.controller.ItemDetails", {  });  }
);

 

 


Adding Routes

 

Open webapp/manifest.json which will open in the Descriptor Editor.  You also have the option to view the raw file by choosing the Code Editor option at the bottom left of the file.

 

In the Descriptor Editor choose the Routing tab at the top of the editor.  Add a new Target under the Manage Targets section providing the values

 

Name: itemDetails

View Name: ItemDetails

ID : itemDetails

 

Next add a new route under the Routes section with the values

 

Name: itemDetails

Pattern: PurchaseOrders/{objectId}/PurchaseOrderItems/{posId}

Targets: master, itemDetails

 

Screen Shot 2016-02-12 at 3.44.03 PM.png

 

 

 

Now lets add the coding in the Details view to navigate to our new view.  Open the webapp/view/Details.view.xml and add the properties press and type with the following values as shown.

 

</columns>  <items>  <ColumnListItem press="goToItemDetail" type="Navigation">  <cells>  <ObjectIdentifier  title="{Product}"  text="{POItemPos}"/>

 

 

Next open webapp/controller/Details.controller.js and define the goToItemDetail function as follows

 

goToItemDetail : function(oEvent){  var sPOId = oEvent.getSource().getBindingContext().getProperty("POId")  var sPOItemPos = oEvent.getSource().getBindingContext().getProperty("POItemPos")  this.getRouter().navTo("itemDetails", {  objectId : sPOId,  posId: sPOItemPos  });  }

 

 

Finally in the file webapp/view/ItemDetails.controller.js we can add the coding to handle the navigation and binding of our new view.

 

sap.ui.define([  "com/po/demo/controller/BaseController"  ], function (BaseController) {  "use strict";  return BaseController.extend("com.po.demo.controller.ItemDetails", {  onInit : function () {  this.getRouter().getRoute("itemDetails").attachPatternMatched(this._onItemDetailsMatched, this);  },  _onItemDetailsMatched: function(oEvent){  var sObjectPath = this.getModel().createKey("PurchaseOrderItems", {  POId :  oEvent.getParameter("arguments").objectId,  POItemPos :  oEvent.getParameter("arguments").posId  });  var context =  oEvent.getParameter("arguments").context;  this.getView().bindContext("/" + sObjectPath);  }  });  }
);

 

 

Now when we load our app we should be able to select one of the items in the PurchaseOrderItems table and this should navigate us to our new view.

 

Screen Shot 2016-02-12 at 2.44.32 PM.png


UI5 ValueHelpDialog Helper / Wrapper object

$
0
0

Introduction

 

UI5 has a lot of components that you can use with great out-of-the-box features. With only a few lines of coding you can use these UI5 components. But some more advanced UI5 components require more than just a few lines. For example the ValueHelpDialog requires a lot of coding to use.

 

For more information about the component:     

https://sapui5.hana.ondemand.com/explored.html#/entity/sap.ui.comp.valuehelpdialog.ValueHelpDialog/samples

 

I needed to use the ValueHelpDialog and I don’t like it to have too much code in my controller. Therefore I created a helper/wrapper object for the ValueHelpDialog. With this helper/wrapper I could just use the ValueHelpDialg with a few lines of code in my controller. But I also made it more generic and easier to use.

 

To help other developers that want to use this UI5 component I share this helper/wrapper object.

 

 

How to use this ValueHelpDialog Helper/Wrapper

 

  • Same as for the normal ValueHelpDialog, add the input field to your view:
    • Give the input field an ID
    • Define a function for the valueHelpRequest event

 

<MultiInput id="valuehelp1" valueHelpRequest="onValueHelpRequest" valueHelpOnly="true" />
  • Configure all the fields of the table in the valuehelp in the onInit of the controller
    • For every column:
      • Label --> The label of the column
      • Key --> define a column id
      • Iskey --> set column as key
        • Two keys are required
      • Searchable --> add a field to the advanced search
      • Width --> set the width of a column
      • Search --> the main search of the ValueHelpDialog

 

this.fields = [                                                     {label:"Column1", key: "Col1", searchable:false, iskey:true,search:true},                                                     {label:"Column2",key:"Col2", searchable:true, iskey:true},                                                     {label:"Column3",key:"Col3", searchable:true,width:"30rem"}                                                  ];
  • Create an object of the ValueHelpDialog Helper/Dialog in the onInit of the controller
    • The constructor requires
      • Model with the data
      • Inputfield
      • Fields configuration
      • Title

 

this.valuehelp = new ValueHelpHelper(this.getView().getModel(),this.getView().byId("valuehelp1"),this.fields,"Title");

 

  • In the onValueHelpRequest function you can now just open the ValueHelpDialog
    • Function requires:
      • Binding
      • onSelectionCallback
      • onCancelCallback

 

onValueHelpRequest: function() {  var me = this;
this.valuehelp.openValueHelp("/items",
function(selection,ctx){                var oView = this.getView();                console.log("Selection text: " + selection.getText());                console.log("Selection key: " + selection.getKey());               },
function(ctx){                console.log("cancel");
},this);
}

Full code of the controller:

sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel",
"be/wl/valuehelp/controllers/ValueHelpHelper"
], function (Controller, JSONModel,ValueHelpHelper) {
"use strict";
return Controller.extend("be.wl.valuehelp.controllers.main", {     
onInit:function(){    
var items = [{Col1:"row1 col1",Col2:"row1 col2",Col3:"row1 col3"},                     {Col1:"row2 col1",Col2:"row2 col2",Col3:"row2 col3"}];
this.getView().setModel(new JSONModel({items:items}));
this.fields = [                                                           {label:"Column1", key: "Col1", searchable:false, iskey:true,search:true},                                                           {label:"Column2",key:"Col2", searchable:true, iskey:true},                                                           {label:"Column3",key:"Col3", searchable:true,width:"30rem"}                                                     ];                                               this.valuehelp = new ValueHelpHelper(this.getView().getModel(),this.getView().byId("valuehelp1"),this.fields,"Title");      },                          onValueHelpRequest: function() {                                     var me = this;
this.valuehelp.openValueHelp("/items",                                       function(selection,ctx){                                                   var oView = this.getView();                                                   console.log("Selection text: " + selection.getText());                                                   console.log("Selection key: " + selection.getKey());                                                                                     },                                       function(ctx){                                                   console.log("cancel");                                     },this);                          }    });
});

Demo

  • Main search comes from the configuration property search
  • Additional search fields comes from the configuration property searchable

demo1.png

After search:

demo2.png

 

After selection you'll get the two keys in the input field:

demo3.png

 

You can find the full code and demo on plunker:

https://plnkr.co/edit/S4lUbxkCcnR2VJ7APzTb?p=preview

 

Hope it’s useful!

 

Kind regards,

Wouter

Creating hierarchical data using Content-ID Referencing in a Change Set (Batch Request) in hybrid application

$
0
0

There is a limitation in OData specifications that does not allow deep inserts 1:N for Offline applications.  However, you can use Content-ID referencing in a Change Set (batch request) to overcome this limitation.  Please refer to the OData specifications on Referencing Requests in a Change Set.  Note that the OData producer must support Content-ID referencing in order for this to work.

 

In our example, we will use the universally available OData Service found in http://services.odata.org.  Since this involves updating the backend data, use the link to create a full access (Read-Write) service.  The OData Service should look something similar to this.  http://services.odata.org/(S(i01sargg1imht0wuq102ghz1))/V2/OData/OData.svc/.  The OData version must be V2 and note the placement of the V2 string in the URL.

 

Note:  SAP Gateway 740 SP13 and above supports Content-ID referencing.  SAP Gateway 2.0 SP12 is also scheduled to support Content-ID referencing.  However, it is recommended to use the newer SAP Gateway 740 SP13 or above.

Difference between deep insert and Content-ID referencing in a change set (batch request) ?

There are quite a few similarities between deep insert and Content-ID referencing in a change set (batch request).  Both these approaches can be used to insert hierarchical data.  The table below describes some of the differences between deep insert and Content-ID referencing in a change set (batch request).

 

Deep Insert

Content-ID referencing in a change set (batch request)

Deep insert allows creating hierarchical data using a single payload in a single request

Multiple requests are grouped into a single request

Deep Insert is somewhat easier. The single payload in the POST request is in the same format as that of a GET request with $expand

If a MIME part representing an Insert request within a ChangeSet includes a Content-ID header, then the new entity represented by that part may be referenced by subsequent requests within the same ChangeSet by referring to the Content-ID value prefixed with a “$” character.

Most OData providers support deep insert – including Integration Gateway

Integration Gateway does not support Content-ID referencing in a batch request.  However, there are other 3rd party OData producers that support Content-ID referencing in a change set.

Limitation in OData specification does not allow for deep inserts 1:N for Offline applications

No such limitation. Hierarchical data can be inserted in both Online and Offline applications

 

 

Setting up the application definition in HCPms

Setting up the application definition in HCPms is fairly straightforward.  The publicly available OData Service does not require any authentication. To keep things simple, the application definition will also not have any authentication.  I have included a few screenshots on how to set up the application definition in HCPms.

 

Application ID

com.sap.batch

Name

Content ID referencing

Type

Hybrid

Description

Content ID referencing

Vendor

SAP

Security Configuration

None (not recommended)

Back-End URL

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/

Proxy Type

Internet

Authentication

No authentication (not recommended)

 

batch1.png

 

batch2.png

 

Application Configuration file

 

[endpoint]

name=com.sap.batch

prepopulate_offline_db=Y

content_id_header_location=operation

 

 

batch3.png

 

Note:  The application configuration file is used to let HCPms know the location of the Content-ID.  This is because a lot of OData providers (including the OData Service that is being used in this blog) incorrectly requires the Content-ID as part of the operation header.  SAP Gateway correctly requires the Content-ID as part of the MIME header.  So if you are using SAP Gateway, then you would use the value ‘mime’ instead of ‘operation’.

Creating hierarchical data with 1:N relationship using Content-ID referencing in a Change Set (batch request)

The code to submit the Content-ID referencing is the same for both Online and Offline Stores.  The first step is to create the body of the request object that contains the parent and the child entities.  We will create 1 parent entity (Categories) and 2 child entities (Products).   Note that the child entities use the Content-ID (requestUri: "$1/Products") to reference the parent entity.

 

The request object is then created using the POST method.  The $batch is appended to the request URI (requestUri: getEndPointURL() + "/$batch") since this is a batch request.

 

function batchRequest() {

        var oHeaders = {

        };

 

var params = {

__batchRequests: [{

__changeRequests: [{

                    requestUri: getEndPointURL() + "/Categories",

method: "POST",

headers: {

"Content-ID": "1"

},

data: {

"ID": 5,

                        "Name": "Toys"

}

                },

                {

requestUri: "$1/Products",

method: "POST",

data: {

"Description": "UBS ChessMaster Software",

"DiscontinuedDate": "2013-01-01T00:00:00",

"ID": 510,

"Name": "ChessMaster 10th Edition",

"Price": "5.6",

"Rating": 5,

"ReleaseDate": "2010-01-01T00:00:00"

}

                },

                {

requestUri: "$1/Products",

method: "POST",

data: {

"Description": "Lego Blocks",

"DiscontinuedDate": "2013-01-01T00:00:00",

"ID": 511,

"Name": "Hasbro Ltd",

"Price": "23.50",

"Rating": 4,

"ReleaseDate": "2010-01-01T00:00:00"

}

                }

                ]

            }

            ]

        };

 

        oHeaders['Authorization'] = authStr;

 

        var request = {

headers: oHeaders,

requestUri: getEndPointURL() + "/$batch",

method: "POST",

            data: params

        };

 

OData.request(request, responseCallback, errorCallback, OData.batchHandler);

    }

 

Running the application (Online)

Running the application in Online mode is simple.  After you Onboard successfully, click on the Read button.  You should see 9 entries for the Products table.

 

batch4.png

 

Browse to the OData Service to confirm there are 9 entries for Products as well…  Also confirm there are 3 entries for Categories.

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products/$count

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories/$count

 

Click on the Batch request – Insert button.  This should submit both the Parent and the Child entities to the backend.  Click on Read button and notice there are 11 entries for the Product table.

 

batch5.png

 

Browse to the OData Service to confirm there are 11 entries for Products as well…  Also confirm there are 4 entries for Categories.

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products/$count

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories/$count

 

Note:  Since we are hard-coding the ID values, you cannot insert the same values again.

 

Running the application (Offline)

Running the application in Offline mode is simple as well.  After you Onboard successfully, you must open the Offline Store.  After the Offline Store is opened (the status will indicate that it is opened), click on Read.

 

batch6.png

 

Browse to the OData Service to confirm there are 9 entries for Products as well…  Also confirm there are 3 entries for Categories.

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products/$count

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories/$count

 

Click on the Batch request – Insert button.  This should submit both the Parent and the Child entities to the local Offline Store. Click on Read button and notice there are 11 entries for the Product table.  Note:  The relationship is established between the Parent and the Child entities because we are using Content-ID referencing when performing the insert.

 

batch7.png

 

Browse to the OData Service to confirm there are only 9 entries for Products.  This is because the insert was done against the local Offline Store only.  Also confirm there are 3 entries for Categories.

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products/$count

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories/$count

 

 

Click on Flush Store. After flush is complete (status will indicate that flush is complete), click on Read.  You will notice that there are still 11 entries for the Products table.  Behind the scenes, the new rows have now been sent to the backend.

 

batch8.png

 

Browse to the OData Service to confirm there are 11 entries for Products as well…  Also confirm there are 4 entries for Categories.

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Products/$count

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories

 

http://services.odata.org/(S(rt5puvtqg2ax2ka2tepwsonq))/V2/OData/OData.svc/Categories/$count

 

Additionally, you can also click on Refresh Store.  Note:  Since we are hard-coding the ID values, you cannot insert the same values again.

 

Viewing contents of the Offline Store (Optional)

Starting with SAP Mobile Platform SDK SP11, a utility called iLoData.exe is shipped along with the installation files.  This utility is useful for reading the contents of the Offline Store.  In addition, this utility can be used for performing CUD operations as well.  Flush and Refresh can also be executed using this utility.

 

  • Browse to the <Install Media>\modules\OfflineODataTools folder. There is a zip file named OfflineODataTools.zip.  Unzip the file to extract iLoData.exe.
  • Copy the Offline Store UDB files.  For Windows hybrid application, this can be found under %localappdata%\Packages\<Your package folder>.  There will be 2 UDB files.  Copy them both to the same location as the iLoData.exe.  For example – ProductsOfflineStore.udb, ProductsOfflineStore.rq.udb
  • Run iLoData.exe with the following command to open the Offline Store.  For a complete list of arguments that can be passed, type in ilodata.exe /?

 

 

ilodata.exe service_root=com.sap.batch store_name=ProductsOfflineStore  appcid=a6de15ce-ba6a-41dd-90a2-2603573589f0

  • Run any OData commands to read the contents of the Offline Store.  For example

 

get /Products

get /Products/$count

get /Categories

get /Categories/$count

get /Categories(5)/Products


 

 

I have attached the index.html file for the hybrid application.  Please refer to the blog on how to set up SAP Web IDE application to run on Windows 10.  In addition, please refer to the blog on getting started with Kapsel. 

How to create a Fiori Overview Page leveraging an on premise OData service and deploy it to an on premise Fiori Launchpad

$
0
0

In my previous blog How to make your OData entities work with the Fiori Overview Page and Cards leveraging the new SAP Web IDE annotation modeler I described the basic steps to create a Fiori Overview Page with a table Card based on an Internet OData service, focusing on how to create the annotation file with new SAP Web IDE annotation modeler and how to adjust the manifst.json within Web IDE respectively.

 

In this blog I will focus on the differences when creating a Fiori Overview Page leveraging an on premise OData service and deploy the result to an on premise Fiori Launchpad. This is similar do deploying a Fiori Application to an on Premise Fiori Lauchpad, as I have described it in my previous blog Verify your Gateway (Frontend) Installation in 45 Minutes, but I will highlight the differences.

 

To start with, you need a HANA Cloud Connector to make your on premise OData service available in the Web IDE during design time and to deploy the Fiori Overview Page to your on premise Fiori Launch Pad:

SAP HANA Cloud Connector.png

To consume the on premise service and to deploy the Fiori Overview Page to the ABAP repository, access to the following resources including all sub-paths needs to be allowed:

 

  • /sap/bc/adt
  • /sap/bc/ui5_ui5
  • /sap/opu/odata

 

In the HANA cloud platform, we need the following corresponding destinations are needed:

UIAddOn.png

UI5.png

OData.png

For this blog I am using the Reference SFlight Data Provider. If not already done so, this service would have to be enabled:

Activate and Maintain Services.png

With these preparations, a Fiori Overview Page can be build based on this service:

Data Connection.png

As before, a local skeleton annotation file needs to be provided:

 

<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"

                xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData">

                <edmx:DataServices m:DataServiceVersion="2.0">

                                <Schema Namespace="RMTSAMPLEFLIGHT_2" sap:schema-version="1" xmlns="http://docs.oasis-open.org/odata/ns/edm">

                                </Schema>

                </edmx:DataServices>

</edmx:Edmx>

Annotation Selection.png

And also some template customization:

Template Customization.png

With that we are done and our project got created. Next the path to the annotation file to localService/RMTSAMPLEFLIGHT_2 has to be correctrd to where it is in fact stored:

manifest.png

This enables us to use the Annotation Modeler to annotate the TravelAgencyCollection to use with a LineItem containing the DataFields Name, City and Country:

Annotation Structure.png

Next a Table Card can be added based on the same service:

Configure Datasource.png

Finally we select the TravelAgencyCollection as the Entity Set and provide the Header Elements:

New Card.png

When we now run the Fiori Overview Page as a SAP Fiori Content on Sandbox, we see our card populated with travel agent information from the on premise OData service:

SAP Fiori Content on Sandbox.png

Now we go further and deploy this Fiori Overview Page to our on premise Fiori Launchpad:

Deploy a New Application.png

We chose the destination we created before:

Deployment Options.png

And deploy it as a new application:

Deploy a New Application.png

As a result we find our Fiori Overview Page as a BSP Application in the ABAP Development Workbench. Especially important is the path /sap/bc/ui5_ui5/sap/zflight/webapp:

Web Application Builder.png

First we create a Launchpad (Role):

Overview of Launchpads.png

And then a New Application within the Launchpad. Especially important are

  • Application Parameter URL: /sap/bc/ui5_ui5/sap/zflight/webapp
  • Additional Information: SAPUI5.Component=zflight

As you have seen them in the ABAP Development Workbench:

Change Launchpad.png

Finally we need a corresponding Semantic Object:

Semantic Object.png

With this, a new Catalog can be created:

Create Catalog.png

Next we create a Tile within your Catalog. Important here is the Semantic Object, we created before:

Tile.png

And a Target Mapping for which again the Semantic Object is important but also the Launchpad (Role) and Application Alias that we configured before:

Target Mapping.png

To conclude the Fiori Launchpad configuration we create a Group to represent our user role:

Create Group.png

And assign the Tile from your Catalog to it:

Add Tile to Group.png

Finally we create a Single Role, assign your Fiori Launchpad Catalog and Group to it and assign it to your user:

Change Roles.png

With this we got on premise access our Fiori Overview Page:

Assistant.png

With its Card rendering like a charm:

Travel Management.png

To make this Fiori Overview Page work on premise, you would have to be at least on SAPUI5 version 1.32.0 as shown in the manifest.json:

minUI5Version.png

This blog content has been developed on a NetWeaver 7.50 system, with SAPUI5 version 1.32.12:

SAP UI5 development toolkit for HTML5.png

OpenUI5 boilerplate based on OLingo, JPA and Spring Boot

$
0
0

Fire_Phoenix_1.jpg

It happens quite often that you quickly want to get something running with OpenUI5 and OData, quickly smack it on a web-server or cloud instance, but just don't look forward building the project completely start from scratch. Think hackathons, in which time is very limited already... That's when an OpenUI5 boilerplate would come in handy.


That's why I have compiled a relatively small application that connects to a database (mysql by default), builds to a jar, allows you to model your data using JPA (and the JPA diagram editor), exposes the model through OData and has a tiny OpenUI5 application that uses the OData and shows the content of the database.


For convenience, a base-diagram for the JPA diagram editor has been provided as well. Once the datamodel is finished, the application with update the data model of the connected database on first run.


By default, the application comes with just one entity: Members, that is automatically populated with a few names from Application.java


Once the application is running, you can browse to http://localhost:8080 to run the sample OpenUI5 application that is using the OData service. The service itself is available from http://localhost:8080/odata.svc.


The only thing you need for this, is a local install of Maven and Java 1.8, once you have that just clone the github repository to your computer:


git clone https://github.com/jpenninkhof/odata-boilerplate.git


Modify file "/src/main/resources/application.properties" to connect to your own database.


And run it:

 

mvn spring-boot:run


On first run, the application will introspect the database that it has been connected to, and will make sure the database is in sync with it's internal model. If necessary tables will be created or altered.


And with that, you're ready to run the OpenUI sample app from http://localhost:8080/openui5-boilerplate

openui5-boilerplate.png

Contributions are welcome. Just fork it and submit a pull request.


Related links:


The Software Craftsmanship movement...accountabilty or elitism ?

$
0
0

     I recently "attended" the virtual hack.summit() conference (https://hacksummit.org/). It was actually pretty great....an amazing assortment of speakers from all backgrounds (from the co-founder of Stack Overflow to the creator of Google Glasses to the creator of Ruby on Rails to the "big data" manager of Facebook and on and on). The sessions were very interactive "fireside chats" with each speaker, all of which were amazingly open and informal. One topic that came up in several was the notion of "software craftsmanship". Maybe I have just been too "head down" in my own work over the years, but this was a new one on me (I think it really got started around 2011 anyways haha). Heard of it?

 

    Well, one of the speakers was Robert Martin(https://en.wikipedia.org/wiki/Robert_Cecil_Martin)....also known as "Uncle Bob"...who was one of the creators of the "Agile Manifesto"...and later the "Software Craftsmanship Manifesto". As I understand it, the idea of "software craftsmanship" was born out of what he and others saw happening in the Agile world. As he put it, when Agile began, it was a "programmers' thing"....meant for developers. As Agile caught on, he saw where there were lots of people being certified as "Scrum Masters" who had absolutely no programming background...often project managers looking for a new role. This did not sit well with him as he thought "how can someone with no programming background really understand and appreciate Agile and its outcome....to produce great code". So, he (and others) hit upon the idea of "software craftsmanship" (Manifesto for Software Craftsmanship) where the "craft" itself of programming/development is held to a higher level.....in an nutshell as they state "raising the bar of professional software development by practicing it and helping others learn the craft". As Bob stated, when he started coding, it couldn't kill you....today however, software can kill people or crash economies literally because of how dependent most all things in our world are on it....therefore, we must hold it's creation to a higher level. Personally, I can see the merits of this on the one hand....don't we all who develop software/apps/etc want to crank out good, well-written code? do not all of us hold ourselves to a certain level such that we create code we are proud of?...well sadly, the answer is "no"....so in that sense, I can see where they are going with this.

 

    On the flip side of this was David Heinermeier's (creator of Ruby on Rails) session. When asked his thoughts on "software craftsmanship", he had a MUCH different view. He argued that those considering themselves "craftsman" get too caught up on the "beauty" of their work (and it becomes an ego thing) versus producing the functioning software intended. Furthermore, it lends itself to a kind of elitism among the programming world. For example, you might get those "craftsman" types considering themselves above/better than say some guy learning PHP that cranked out a great site because the "craftsman" might argue PHP is not a real language....but isn't it still all programming? And that too is another point of contention for him.....he got into programming because it is so open and accepting. You do not have to be a trained programmer or software engineer to pick up programming and do it. All you need is an interest in it....and a passion for it and learning does not hurt either. (haha) Attempting to divide the already divided developer community (often wrongly segmented by degree/certification, development language, world region, age, etc.) by yet another "scale" is just more evil than good.

 

   Feel free to Google arguments on both sides of this...there are lots out there (like I said up front, this was a new idea to me, so I spent a bit of time researching both sides as well). I am curious to hear your thoughts on it as well (and if you think it can/should be applied in our SAP world!). I think you can also still sign-up for the hack.summit() site (use promo code CODESCHOOL) and view all the recordings of the sessions.

Troubleshooting Deployment to an ABAP System from SAP Web IDE

$
0
0

Introduction

 

SAP Web IDE offers the ability to deploy applications into your ABAP system as a new app or as an update to an existing one.

All you have to do it to right-click your app and choose Deploy -> Deploy to SAPUI5 ABAP Repository, fill in the necessary information such as name, description and package, and click Finish.

 

Technical Details

 

  • When the system is selected in the first step of the wizard, we execute a call to get the discovery XML of the /sap/bc/adt service (issuing GET for /sap/bc/adt/discovery). Then we analyze the result XML to verify all is valid to proceed. If something is missing or there was a problem issuing the request we show an error (more details below).
  • A new application is deployed on the server by issuing POST/PUT requests for its resources.
  • Upon update of an existing application, we deploy the entire app and not only the changed resources, because there is no tracking on changes being done to the app outside of SAP Web IDE and by other users. This is similar to the functionality of the /UI5/UI5_REPOSITORY_LOAD function (with slight difference).

 

Troubleshooting

 

Here are some problems and solutions that I've gathered from my experience here on SCN:


  • Problem: My ABAP system is showing in SAP Web IDE but not in this wizard.

        Solution: Make sure you have the dev_abap WebIDEUsage configured in your destination in HCP cockpit.


  • Problem: I get an error when my system is selected in the first step of the wizard.

        Solution: This can happen for several reasons:

    • An "authorization" error is displayed because the /sap/bc/adt/ service isn't activated in transaction SICF. Example: Re: Authorization error when connecting to Gateway from WebIDE
    • A "forbidden" error is displayed due to missing authorizations to access /sap/bc/adt/discovery. The best way to check this is by trying to access the discovery in the browser directly from the system's host and port and not via SAP Web IDE using the same credentials, and see if the user gets a valid response. Examples: Re: WebIDE deploy error ,Not able to access Gateway system from WEB IDE
    • A "forbidden" error is displayed with no prompt for user credentials because the ICF node for ADT is configured with fixed user credentials. The solution would be to remove the fixed user credentials. This can also occur during the deployment process and result in an "CSRF token validation failed" error. Example: CSRF token validation failed while deploying extended fiori application to ABAP Repository
    • A "forbidden" error is displayed because SAP Note 1977537 is not implemented (Introduction of XHR client authentication). If you have not implemented this note or if it needs an update, make sure you implement the latest version of the note.
    • The following error is displayed: "Cannot select the system. Check the configuration for ABAP Development Tools". This can be due to missing prerequisites, or missing authorizations, see example: Error Connecting to ABAP Repository from webIDE.

  • Problem: I can only deploy to $TMP package.
    Solution: Either a note implementation is missing, or some note's status needs a reset due to the SAP_BASIS version. Please follow the prerequisites mentioned in our documentation.

  • Problem: I'm getting an error after selecting a package and in the browser's network trace I see "CSRF token validation failed" error when trying to
    reach /sap/bc/adt/cts/transportchecks service.
    Solution: In short, this issue may happen because the backend system expects a request with HTTPS and receives a request with HTTP or vice versa.
    Then it performs a redirect which makes the CSRF token invalid. Make sure to configure the destination in HCP cockpit and Cloud Connector in the
    same way the backend expects to get it (or change the security configuration of your backend system).

 

  • Problem: I'm getting this error upon deployment: "Cannot deploy application XXX: Remote creation in customer namespace not possible".
    Solution: The target system is running in SAP mode.You can either use the SAP namespace in the given application name, or change the system to work in customer mode if possible. Alternatively an empty app can be created with report /UI5/UI5_REPOSITORY_LOAD via SAPGUI and then you can deploy into it.

  • Problem: First folders are deployed successfully but the first file gets an HTTP 500 error.
    Solution: Probably a problem with the Web Dispatcher. Open a ticket for the Web Dispatcher component.

  • Problem: I'm getting this error upon deployment: "No development license for user XXX".
    Solution: This is the standard behavior of an ABAP system. To deploy, the user has to be registered as a developer in the system.

  • Problem: I'm getting this error upon deployment: "Object X is already locked in request Y of user Z".
    Solution: Make sure to select the right transport in the wizard. If selecting a transport isn't possible check the prerequisites and make sure all relevant notes are implemented, and that you have all relevant authorizations for the /sap/bc/adt/cts/transportchecks service.

  • Problem: I'm getting this error upon deployment: "Cannot deploy the application. Virus scan server error. No virus scan profile is selected as the default".
    Solution: You need to select a virus scan profile in your backend system or switch it off. Example: Re: Cannot deploy application in ABAP Repository - Virus scan server error


  • Problem: I'm getting this error upon deployment: "Cannot deploy the application: Request XXX is not a local request". The transport request is created as part of the wizard.
    Solution: Both the package and the new transport request have a transport layer assigned to them. In this case, the package has a local transport layer assigned to it, but the transport request created is not a local request. See SAP Note 2121673 that deals with inconsistencies in the transport handling, and how such inconsistencies might result in this error. Check whether you have the latest release of this note and that the package is defined as described in the note.

  • Problem:Empty files aren't being deployed.
    Solution: Implement SAP Note 2211746.

 


More Tips

 

  • Whenever you experience an issue with the deployment and ask for help, it's very helpful to attach the network trace available in the browser's Developer Tools, specifically the failed request and its response. Also attach how your destination is configured.

  • You can see the progress of the deployment in the SAPWeb IDE Console (available from the View menu).

Console.PNG

Use Chrome development Tool to compare Rendering performance between SAPUI5 and React

$
0
0

I have been working as a Fiori application developer and nowadays I have read quite a lot of blogs which introduce how to build web application using React.  React is an open-source JavaScript library providing a view for data rendered as HTML. You can find more information from Wikipedia and its source code from github.

 

Most of those blogs have mentioned that React has quite good performance but don't contain detail performance data. Since I have been using SAP UI5 framework in my daily work, I am curious about the performance comparison between SAPUI5 and React regarding the topic of page rendering.

 

Comparison environment setup

 

I have implemented a most simple application separately via UI5 and React to measure their page rendering performance difference.

 

The application has the following appearance: it consists of a TextField with a given numbers of TextArea. The number of TextArea is controlled via code. Every time you type something in the TextField, the text you have typed will be written in all of the TextField as well.

 

clipboard1.png

The UI5 implementation

 

I use Json view to implement this application. The source code of "sample.view.js" has been listed below. The variable "_NUMBER" controls the number of TextAreas.

 

sap.ui.jsview("compareReact.sample", {
_NUMBER: 100,
_textAreas: [],
getControllerName : function() {  return "compareReact.sample";
},
createContent : function(oController) {  var that = this;  var oInput1 = new sap.ui.commons.TextField('input1');  oInput1.setValue("Hello!");  oInput1.attachLiveChange(function(event){   // console.log('Text changed to :'+ oInput1.getValue());   for( var i = 0; i < that._NUMBER; i++){     that._textAreas[i].setValue(event.getParameter("liveValue"));   }   }  );  this.oLayout = new sap.ui.layout.VerticalLayout("Layout1", {          content:[oInput1]        });  for( var i = 0; i < this._NUMBER; i++){   var oInput = new sap.ui.commons.TextArea('text' + i);   this.oLayout.addContent(oInput);   this._textAreas.push(oInput);  }  return this.oLayout;
}
});

The React implementation

 

The source code could be found from my github.

 

For those who are not familiar with React, let me briefly introduce this source code:

 

When I studied React for the first time, I was confused by the "syntax error" for example in line 28 and 32~36. Actually this is the supported syntax on script tag with type "text/babel" ( in line 10 ). Using this JSXgrammar, it is allowed to insert native HTML markup into JavaScript code.

 

clipboard2.png

And keep in mind, such JSX code will be translated to native JavaScript when the page is rendered, by browser.min.js. For steps how to get and debug converted JavaScript source code, please refer to my blog How to get and debug converted source code in React.

 

In line 12, a customized ReactComponent is created which encapsulates the logic how the view should be rendered and what is the data source of this view. For me, I would like to treat the function render() as createContent() in SAPUI5 Json view, and setState() as the ClientModel handling in SAPUI5. You see the line 33 "value={value}" and shouldn't this be the same logic as SAPUI5 data binding?

 

When there is live-change event occurred, the callback function "this.handleChange" specified in line 33 will be called, which will then trigger ReactComponent.setState and finally render() will be called to refresh the page.

 

The created ReactComponent could be used the same way as native HTML tag to insert into the page.

clipboard3.png


The code above has exactly the same logic as what we do in every UI5 application:

clipboard4.png

Use Chrome timeline to measure performance

 

 

I will use the tab "TimeLine" to measure performance. There is already a good article introducing how to use this tab by Google.

 

UI5 application result

 

I start comparison by specifying the number of TextArea as 100. First start UI5 application. I type "3" for six times and I get the following measurement result:

 

1. The six areas marked with black bold underline represent the performance data for each of the six "3" type action. As I only focus on rendering stuff, I can ignore the orange color for "Scripting". So the total rendering time for scenario with 100 TextArea are 36.3ms and Painting time is 6.9ms.

 

clipboard4.png

You might be confused by the terms "layouting", "rendering" and "painting"? Read this awesome blog How browsers work-Behind the scenes of modern web browsers to understand their exactly meaning.


And have you noticed the small red icon for "Long frame"?

clipboard6.png

You can click the hyperlink "jank" to know more detail about "Long frame".

 

By clicking the corresponding rectangle with different color, you can get a detail view under tab "Event Log".

clipboard7.png


For example, below detail view shows that the code in line 416 of TextField.js:formatted has triggered the style recalculation which consumes 1.8ms.

clipboard9.png

Click the hyperlink and we are eable to see the exact line with its context. In this case, we first get the native HTML DOM node in line 399 and fill its attribute value in line 416 with the character we have typed.

clipboard10.png

And how is this 36 FPS ( frame per second ) calculated? 36 FPS = 1 / 27.7ms * 1000, means 36 frames per second.

clipboard1.png

According to Google documentation, "Each of those frames has a budget of just over 16 ms (1 second / 60 = 16.66 ms). In reality, however, the browser has housekeeping work to do, so all of your work needs to be completed inside10 ms. When you fail to meet this budget the frame rate drops, and the content judders on screen. This is often referred to asjank, and it negatively impacts the user's experience.", this is the reason why this frame with duration 27.7 ms is marked with red indicator for "Long frame".

 

React application result

 

We can easily find that there is no Long frame for the six frames rendered in React, total rendering time is 19.5 ms ( while UI5 is 36.3 ms  ) and painting time 5.4 ms ( UI5 6.9 ms ).

clipboard2.png


React has much better performance than UI5 ( 63 FPS vs 36 FPS ).


clipboard3.png

Actually there is no apparent difference between UI5 and React on Layouting; The bottleneck for UI5 lays in the T.setValue which consumes the 46.2% of total time.

clipboard4.png

In React, the code to change the native HTML node value, setTextContent in react.js:16904, only consumes 0.6ms.

clipboard5.png

The pixel pipeline

 

As documented by Google, "Most devices today refresh their screens 60 times a second. If there’s an animation or transition running, or the user is scrolling the pages, the browser needs to match the device’s refresh rate and put up 1 new picture, or frame, for each of those screen refreshes.  Each of those frames has a budget of just over 16 ms (1 second / 60 = 16.66 ms). In reality, however, the browser has housekeeping work to do, so all of your work needs to be completed inside 10 ms. "

 

That is to say, for any frame, it is better to avoid the total duration of the five mentioned steps ( 1. JavaScript 2. Style calculation 3. Layout 4. Paint 5. Composite ) not exceed 10 ms.


clipboard8.png

Further reading

 

For your convenience, I list all the document which I think worth further reading into this part:

 

 

I am also considering to rewrite the UI5 sample with model binding ( bind the value of both TextField and TextArea to a Json model field ) and then re-compare the rendering performance difference.


Routing Source Code

$
0
0

Hi Friends,

To switch between different pages we use

a)Navigation

b)Routing

How ever Navigation is Simple, but coming to Routing it is bit tricky if you are a newbie to UI5, because it consists of Component.js File and some declarations need to be done in index.html.

As i felt it is useful to newbie's who are just started learning UI5.

I practiced this Demo example from the below blog.

Demonstration code for Navigation and Routing in SAPUI5

While developing this application i faced many issues.

Daniel Hohmann actively replied to discussion created and helped me a lot to get it to good shape.

Please feel free to comment for the working file attached and suggest if i miss any programming standards

 

Regards,

Shekar.

SAPUI5 Table Navigation with Tab Key

$
0
0

Hi guys,

I guess it's no secret that the table handling in editable tables is not the best in SAPUI5.

Especially the keyboard navigation is, in my opinion, unnecessarily complicated (press tab to jump out of the input field, navigate with arrow keys to next input field, press tab again to jump into said input field). This was not acceptable for my clients, so I searched for another way.

 

After struggling for a while I created this discussion, where showed me his solution for table tab navigation.

I took his coding and extended it for my needs (sap.m input fields, backward navigation, consideration of read-only columns) and here is the result:

 

JS Bin - Table Navigation with Tab Key

 

The navigation with tab and SHIFT+tab works (almost ) perfectly fine.

It takes a bit of coding, but the function can easily be reused as it is.

 

What do you think of this solution? Any ideas for improvements?

 

 

Cheers,

Klaus

Binding data from Odata function Import in SAPUI5 XML Views

$
0
0

Hi all,

 

Recently I had an requirement, wherein, I had to bind the data from my function imports in odata services to my controls in XML view.

However, most of the solutions i found had achieved the same by doing a "oModel.callFunction()" in their controllers.

I was able to find a solution and thought I would share it in a blog post here.

 

Here is the sample code

 

 

 

<MultiComboBox items="{ path:'/myFunctionImport', parameters: { custom: { 'param1': '\'value1\'' } } }">  <core:Item key="{Id}" text="{Text}"/></MultiComboBox>

 

 

Thanks,

Krishna

Debug UI5 apps on Chrome for Android (USB Debugging)

$
0
0

Chrome for desktop has emulator. So why debugging on device is required?

During a recent regression test cycle, a problem was reported in one of our UI5 app - an Input field not working as expected on Chrome(ver 48) in a Samsung Galaxy Tab.

 

I quickly switched on Emulator on Chrome(for desktop) and chose Nexus 7 as device, tested that app and everything worked like a charm. So why the problem reported by testing team?

 

Obviously, there is a difference between the rendering/handling of app on an actual device and in emulation. (Alert: this was my first hand experience so had to write it down).

 

Note: I could have chosen Galaxy SIII or Note 3 as an option but app was marked as incompatible with phones(due to functional reasons, UI5 shouldn't be cursed for it).

 

Getting to the root cause

Only way to find out is to debug the app on a tablet. A quick search give this link to debug applications while running in Chrome on Android. But, this doesn't work as Samsung Tab was not detected in Chrome Inspect.

 

So to make USB debugging work:

1. Download the Samsung Galaxy drivers from it's respective support page. For Galaxy Tab 3, I found the drivers(PC Sync) here.

2. Install drivers, restart the machine and make sure device is connected as Media Device(MTP)

3. Follow the process mentioned in Google document. Start Chrome Inspect and refresh.

4. It still doesn't work.

5. Some blogs suggested that this should be tried with Chrome Canary. But it didn't help. (Later I realized after correct steps that device was detected in both normal Chrome and Canary)

 

Now what?

This discussion came to rescue. Seems something was changed in Chrome that creates some problems with some devices. Lot of somes !!!

A re-iterated version of the steps mentioned in the rescue-blog:

 

  1. Open your app in phone or tablet, which is to be debugged, in Chrome
  2. On desktop, Download and install Android SDK ("SDK Tools Only" section)
  3. Then open up the Command prompt and enter path to installation folder(that you gave during installation). In my case path was: C:\Users\myUserName\AppData\Local\Android\sdk\platform-tools
  4. Run the command adb devices by typing it and pressing enter
  5. Check if you get the prompt on your device, and say yes to it
  6. If everything went well, then something like the following should come up

          Sc1.jpg

  1. Refresh the chrome inspect
  2. If you miss the prompt or still can't see your device in Inspect Devices run the following commands one by one (excluding the ") "adb kill-server" "adb start-server" "adb devices"

 

And this was the Eureka moment. My app showed up in the Chrome Inspect:

 

SC2.jpg

Now just choose Inspect and enjoy the debugging !


P.S. Any suggestions, corrections, additions, subtractions and multiplications are welcome.

Concurrency Control using ETags in a SAPUI5 application

Viewing all 789 articles
Browse latest View live




Latest Images