SAPUI5 Tutorial with WebIDE. Part XI. An ABAPer’s Second SAPUI5 App

In our earlier post, we tried to show all the issues faced by an ABAPer in his/her first SAPUI5 development. One of our readers suggested putting another article with some more issues and its resolutions. He argued that it is a very good way to learn from other’s mistake. Today, we would like to continue in the same line and add on to the list of hiccups faced by the novice SAPUI5 developer.

My second UI development had the below requirement.

First View:

  1. Date as an input field along with two other input fields.
  2. Show error message is user tries to execute without entering the Date

Second View:

1. User wants to see the Count of incomplete Purchase Requisition Line Items

Third View:

1. When the user hits Show PReq, the PReq summary should be displayed.

Fourth View:

1. When the user clicks any PReq, it’s details need to be displayed.

Pretty simple and straightforward requirement. Let us start developing it.

We developed the backend OData project and activated the OData service. We would not talk about the OData part as it is ABAP and ABAPer can figure out the logic pretty easily.

Here, we would put forth only the UI5 issues which we faced.

To begin with, we created 5 views and embedded V_Input into V_Root and then navigated from V_Input to V_Count to V_PReqH(Header) and finally to V_PReqD (Detail). We assume, by now you know how to create views and maintain the patterns and targets in the manifest file.

We have attached the complete project from WebIDE at the end of this article. If you face any difficulty during your development, you can directly import the zipped file to your WebIDE and check the project.

Let us know if you still face any issue.

Issue No 1 faced in my second SAPUI5 App: Not able to put space in front of Label of fields. Not able to put space after the input fields.

Look at the below screen prints. When we open this app in our mobile, the fields tend to hide at the left-handside edges. The users did not like it. They wanted some margins in the left and also some gap after every input field.

Original code snippet.

I tried to give space in the layout editor of the View, but I was not successful. After some research, I found the below two class would do the needful for us.

class=”sapUiSmallMarginBegin”
class=”sapUiSmallMarginBottom”

Check the output now. We have good margins both horizontally and vertically.

Issue No 2 faced in my second SAPUI5 App: How to show more than 100 entries in drop down i.e in the combo box?

We have already dedicated a separate article on this topic. Please read How to ovoverwritehe default 100 set by SAP for UI.

If your dropdown or your item table is not showing more than 100 records. Worry not. It is SAP’s way to avoid unintentional performance problem. The most common method to over write this 100 number is to use oModel.setSizeLimit(‘999’) method. But, we found a better one.

Just add a property length: 999 and your combo box would show data up to 999. You can show any number and 999 is just an example.

Forget oModel.setSizeLimit(count) and remember length: count.

Issue No 3 faced in my second SAPUI5 App: OData Service failing when some fields of the entity set returned no data (i.e empty).

This was a strange issue. Our OData worked fine for some cases and for some cases it errored out with status 500 and status reason Internal Server Error.

After debugging the GetEntitySet method we found that it failed only when some fields were blank. For our case whenever there was no data in the Erdat (created date) field, our service failed with the below error.

“Invalid format (return table): Row Number 1, Property Name ‘Erdat’, Property Value ”

After some head scratching, we found that the solution was itself in the Error Text. The key word was “Property Value”.

Check the column “Nullable” of the entity property. It is not checked.

We just need to make the Nullable as ‘X’ and our OData would work even when it returns blank. Isn’t the solution so simple? But we wasted almost half a day to find it.

The right way is shown below.

Similarly, if some Filters and Sorts are not working, I believe we need to set these properties just like Nullable (although we have not tried it yet).

Issue No 4 faced in my second SAPUI5 App: The Date value sent from UI is not in correct format. Error log “Invalid token detected at position”.

Let me elaborate a bit. Since I have a date as input field in the UI, my requirement was to use this data as the filter and retrieve the count of Purchase requisitions.

Basically, I wanted to get a filter URI like:

/sap/opu/odata/sap/ZGW_PREQ_SRV/PReqSet/?$filter=Erdat gt datetime’2017-04-20′

To my surprise, the Model did not return me any value. I checked the /n/IWFND/ERROR_LOG t-code and found the below message.

So, I planned to test and debug using t-code /n/IWFND/GW_CLIENT using below URI.

/sap/opu/odata/sap/ZGW_PREQ_SRV/PReqSet/?$filter=Erdat gt datetime‘2017-04-20’

But it did not go to debug mode at all. It exited with the below message.

After some analysis and going through different forums, I found that the date field expects time as well.

Erdat gt datetime’2017-04-20T00:00:00‘

Check, we have added a default T00:00:00. You can, however, give real time if you want to filter using time as well. We just sent dummy time (T00:00:00) to match what OData was expecting.

/sap/opu/odata/sap/ZGW_PREQ_SRV/PReqSet/?$filter=Erdat gt datetime’2017-04-20T00:00:00‘

Tested in backend and it worked perfectly.

So, I had to change my UI code as below.

I did not understand why we need to send T00:00:00. But as long as it works, I will remember this and keep using it.

Issue No 5 faced in my second SAPUI5 App: Define an internal table (Array) and define an object.

Syntax to define an array in UI.
var textData = [];

Syntax to define an object in UI.
var oJson = {};

Issue No 6 faced in my second SAPUI5 App: How to pass data from one function to another function in UI?

The date, purchasing group and plant data would be passed to View 2 when Get PReq Count button is hit using Router->Pattern.

In one funtion (_onRouteFound) of the controller of View 2, the data is read from the pattern and saved in local variables.

_onRouteFound: function(oEvt) { 
var oArgument  = oEvt.getParameter(“arguments”); 
var lv_date      = oArgument.p_date; 
var lv_pgroup = oArgument.p_grp; 
var lv_plant     = oArgument.p_plant; 

.  
}

In another function (ShowPReq), we need to access the same data lv_date, lv_pgroup, lv_plant. But how?

Seasoned UI developers might find this issue too silly. But, I really struggled. Finally, I achieved it as below.

Step 1: Instantiate a local JSON model for the controller. I did it in function 1 i.e. onInit.

Step 2: Define an object and fill it with the variable data. I did it in function 2 i.e. _onRouteFound.

Step 3: Set the object data from step 2 to the local JSON model for the controller in step 1. I did it in function 2 i.e. _onRouteFound.

Step 4: Read the data from the local JSON model wherever you need it in the controller. I did it in function 3 i.e. ShowPReq.

Step 1: Instantiating a local JSON model to be used in this controller

this.myLocalModel = new sap.ui.model.json.JSONModel();

Step 2: Define an object and fill it with the variable data.

oJson.vdate is like inline declaration in SAP ABAP. It gets created at run-time.

Step 3: Set the object data to the local JSON model for the controller.

// Set the local data to the Model

this.myLocalModel.setData(oJson);

Step 4: Read the data from the local JSON model wherever you need it in the controller.

We have set the data in the local model in above step. Here we just need to read the Data. And the syntax is model.oData.variable.

// Syntax to read data from local model

var lv_date = this.myLocalModel.oData.vdate;

Issue No 7 faced in my second SAPUI5 App: How to generate the necessary URI for the backend OData Service and save the response from the OData Service? Basically how to declare a model and consume it?

The above code is self-explanatory. Knowing it for the first time is the only issue.

// Declare and Define the Model

var oModelM = new sap.ui.model.odata.ODataModel(“/sap/opu/odata/sap/ZGW_PREQ_SRV/”);

// Prepare the Entity with the URI

// PReqSet/?$filter=Erdat gt datetime’2017-04-20T00:00:00′ and and Ekgrp eq ’25’ and Werks eq ‘4030’

var Entity = “PReqSet” + datefilter + pgroupfilter + plantfilter;

// Declare an array

var textData = [];

// Read Entity using the Model

oModelM.read(Entity, null, null, false, function(oData, response) {

// Keep the results in an Arry

textData = oData.results;

});

Issue No 8 faced in my second SAPUI5 App: How to get the count of number of rows in an array?

In ABAP we can use LINES or DESCRIBE syntax to get the number of lines in an internal table. But finding that for UI script was again a new syntax for an ABAPer. This fellow was not that difficult though. J

ArrayName.length is what we need to do.

// Get the numberof entries in the array var v_count = ” ” + textData.length + ” Purchase Requisitions Line Items are not complete.”;

Issue No 9 faced in my second SAPUI5 App: How to SET the calculated run time data to the View Element?

The requirement was to show the above message in the second view. The count would be calculated at run time and the sentence would be framed using ‘+’ (concatenate) statement. We have the data, but how was I supposed to set it to the screen elements to be displayed?

getView().byId(“Id name”).setText(variable name) helped me.

// Set the data to the View Field Element
this.getView().byId(“Count”).setText(v_count);

These were ridiculously simple stuff which I shared today. But believe me, if you are a fresher in UI5, every new thing is an uphill task. You scramble through the internet, look into GitHub and get drowned in the vast ocean of information. But sometimes what you need is just these simple syntax to complete your task and deliver your App.

Hopefully, newbies would find these useful and experienced folks would want to add to this list and help us in learning. Please provide your feedback and let us know if you have some more issues which you faced during the initial days of your UI development.

Most of the issues I revealed above were from one View Controller. Therefore I am sharing the code for easy reference for the SAPUI5 enthusiasts.

sap.ui.define([“sap/ui/core/mvc/Controller”], function(Controller) {
“use strict”;
return Controller.extend(“ZPReq.controller.V_Count”, {
onInit: function() {

// Instantiating a local model to be used in this controller
this.myLocalModel = new sap.ui.model.json.JSONModel();
debugger;
// Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
// Validate/Match the Router Details sent from Input Controller
oRouter.getRoute(“Route_Count”).attachMatched(this._onRouteFound, this);
},
// Custom Method to bind the elements using the Event Arguments
_onRouteFound: function(oEvt) {

debugger;
var oArgument = oEvt.getParameter(“arguments”);
var lv_date = oArgument.p_date;
var lv_pgroup = oArgument.p_grp;
var lv_plant = oArgument.p_plant;
var datefilter = “?$filter=Erdat gt datetime'” + lv_date + “T00:00:00′”;
var pgroupfilter = “and Ekgrp eq ‘” + lv_pgroup + “‘”;
var plantfilter = “and Werks eq ‘” + lv_plant + “‘”;

// Declare and Define the Model
var oModelM = new sap.ui.model.odata.ODataModel(“/sap/opu/odata/sap/ZGW_PREQ_SRV/”);

// Prepare the Entity with the URI
// PReqSet/?$filter=Erdat gt datetime’2017-04-20T00:00:00′ and and Ekgrp eq ’25’ and Werks eq ‘4030’
var Entity = “PReqSet” + datefilter + pgroupfilter + plantfilter;
// Declare an array
var textData = [];
// Read Entity using the Model
oModelM.read(Entity, null, null, false, function(oData, response) {
// Keep the results in an Arry
textData = oData.results;
});

// Get the number of entries in the arry
var v_count = ” ” + textData.length + ” Purchase Requisitions Line Items are not complete.”;

// Set the data to the View Field Element
this.getView().byId(“Count”).setText(v_count);

var oJson = {};
oJson.vdate = lv_date;
oJson.vpgroup = lv_pgroup;
oJson.vplant = lv_plant;

this.myLocalModel.setData(oJson);
// If we want this Model is another View/Page, we need to setModel
// sap.ui.getCore().setModel(this.myLocalModel);

},

ShowPReq: function(oEvt) {
debugger;

Var lv_date = this.myLocalModel.oData.vdate;
var lv_pgroup = this.myLocalModel.oData.vpgroup;
var lv_plant = this.myLocalModel.oData.vplant;

// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);

oRouter.navTo(“Route_PReqH”, {
pDate: lv_date,
pPgrp: lv_pgroup,
pPlant: lv_plant

});
},
/**
*@memberOf ZPReq.controller.V_Count
*/
GoToInputView: function(oEvt) {
debugger;
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo(“Route_Input”, {});
}
});
});