Skip to Content
Author's profile photo Dilip Kumar Krishnadev Pandey

SAP Fiori – Consume OData Service, CSS, i18n properties in UI5 Application

Overview:

In this blog, we will see,

  • How to apply custom CSS Styles in SAP UI5 application?
  • How to work with multiple language scripts (i18n properties) ?
  • How to consume an OData service in SAP UI5 Application?

Detailed steps to create a SAP UI5 application can be found in following link:

 

SAP UI5 Application project Structure:

  • Our SAP UI5 application’s project structure is as follows:
  • Note: here exampleProject is same as of above blog reference “Create a Fiori app using Eclipse

 

Apply custom CSS Styles in SAP UI5 application:

  • We can apply custom CSS styles in SAP-UI5 application
  • For this we need to maintain “Styles.css” under ‘WebContent’ folder as shown below:
  • Styles.css: for example lets create a custom style for button.
    • /* Button Style */
      .customCss_ForButton{
          background-color: red;
          font-style: italic;
          height: 2.850rem;
          border-style: solid;
          border-color: greenyellow;
      }
      
  • To apply this style to control view, we need to following things:
    • Give reference of ‘Styles.css’ file in ‘Component.js’
    • Use following to apply it to view controls
      • Syntax:    class=”customCss_ForButton
      • for e.g.:    <Button text=”{i18n>PgMst_BtnTxt1}” press=”pressGetMaterial” type=”Accept” class=”customCss_ForButton”/>
  • Testing:
    • Before custom style
    • After Custom style

 

 

i18n Perperties in SAP UI5 application:

  • We can maintain multiple language scripts for Labels, Titles, Header texts, Messages etc in  SAP-UI5 application using i18n property concept.
  • Based on default browser language, respective script can get automatically selected in SAP-UI5 application.
  • Suppose, we want to have two language script in my SAP-UI5 application
    1. Hindi
    2. English
  • Then i18n property path will look like as below [WebContent -> i18n -> scriptFiles]:
    • Where:
    • Hindi Script
      • i18n_hi.properties
      • #Title for 'Master' page | Hindi script
        PgMst_Title   =\u092B\u093F\u092F\u094B\u0930\u0940 \u092A\u0930\u0940\u0915\u094D\u0937\u0923 \u0938\u0902\u0916\u094D\u092F\u093E \u090F\u0915
        PgMst_BtnTxt1 =\u0938\u0948\u092E\u094D\u092A\u0932 \u0906\u0939\u094D\u0935\u093E\u0928
        PgMst_BtnTxt2 =\u0938\u0930\u094D\u0935\u093F\u0938 \u0906\u0939\u094D\u0935\u093E\u0928
        PgMst_BtnTxt3 =\u0905\u0917\u0932\u093E \u092A\u0947\u091C
        
        #Title for 'Details' page | Hindi script
        PgDtl_Title   =\u0935\u093F\u0938\u094D\u0924\u0943\u0924 \u092A\u0943\u0937\u094D\u0920
        PgDtl_Lbl1	  =\u0935\u093F\u0938\u094D\u0924\u093E\u0930 \u092A\u0943\u0937\u094D\u0920 \u092E\u0947\u0902 \u0906\u092A\u0915\u093E \u0938\u094D\u0935\u093E\u0917\u0924 \u0939\u0948
        
    • English Script
      • i18n.properties              : default script if no lang found
      • i18n_en.properties        : when app is been accessed in browser
      • i18n_en-US.properties  : when app is been accessed within Eclipse-PlatForm
      • same details is present in all three files
      • #Title for 'Master' page | English script
        PgMst_Title   =Fiori Example-1
        PgMst_BtnTxt1 =ModelJson
        PgMst_BtnTxt2 =ODataSrv
        PgMst_BtnTxt3 =NextPage
        
        #Title for 'Details' page | English script
        PgDtl_Title   =Detail Page
        PgDtl_Lbl1	  =Welcome to Detail Page
        
  • In i18n property scripts we define variable and assign languages specific values to them
  • To access i18n properties, we need to load them in SAP-UI5 application
    • Load i18n properties references in ‘Component.js’ file
    • Look at ‘get_i18nProperties: function()‘ which gets i18n file references
    • And in ‘createContent : function()‘, its been accessed.
    • ‘Component.js’
    • var gv_i18nBundle;
      jQuery.sap.declare("ZTEST_APP.Component");
      sap.ui.core.UIComponent.extend("ZTEST_APP.Component", {
      
      	
      	metadata : {
              stereotype 	: "component", 
              "abstract"	: true,  
              version 	: "1.0",   
              library 	: "ZTEST_APP", 	          //required for CSS reference
              includes	: [ "css/Styles.css" ],	  //CSS style reference     
              dependencies: { 			  //external dependencies
                  libs 	: ["sap.m", 
                       	   "sap.ui.commons", 
                       	   "sap.ui.ux3", 
                       	   "sap.ui.table", 
                       	   "sap.ui.layout" ], 	 //the libraries that component will be using            
                  library	: "sap.ui.core",	 //what library belongs your component to              
              },        
      	},	
      	
      	createContent : function() {
      	
      		
      		// get i18n.properties
      		var lv_oBundle = this.get_i18nProperties();
      		
      		/*		
      		Note: i18nModel needs to be called before root view 'sap.ui.view' 
                            i.e. before view creation
      		      so that bundle can be accessed at onInit() of Master Page
      		*/
      		gv_i18nBundle = jQuery.sap.resources({url : lv_oBundle.oData.bundleUrl});				
      						
      		// create root view
      		var oView = sap.ui.view({
      			id 			: "app",
      			viewName 	: "ZTEST_APP.view.App",
      			type 		: "JS",
      			viewData 	: { component : this }
      		});
      			
      		// set i18n.properties
      		oView.setModel(lv_oBundle, "i18n");	
      				
      		// set device model
      		var deviceModel = new sap.ui.model.json.JSONModel({
      			isPhone 	: jQuery.device.is.phone,
      			listMode 	: (jQuery.device.is.phone) ? "None" 	: "SingleSelectMaster",
      			listItemType: (jQuery.device.is.phone) ? "Active" 	: "Inactive"
      		});
      		deviceModel.setDefaultBindingMode("OneWay");
      		oView.setModel(deviceModel, "device");
      			
      		// done
      		return oView;
      	},
      	
      	get_i18nProperties: function(){				
      		
                 /*
      	    Set i18n model | for Use of Localized Texts in Applications
      	    Language:
      	    On Eclipse PlateForm: 			lv_Locale = en-US
      	    If BrowserDefaultLang English:	lv_Locale = en
      	    If BrowserDefaultLang Hindi:	lv_Locale = hi	
      	    */	
      		
      		// Get browser's language
      		var lv_Locale 	 = window.navigator.language;
      		
      		var lv_i18nPath;
      		if(lv_Locale){		
      			lv_i18nPath = "/i18n/i18n_" + lv_Locale + ".properties";	
      		}
      		
      		//set default English script "i18n.properties"
      		if(lv_Locale != "hi" || lv_Locale != "en" || lv_Locale != "en-US"){				
      			lv_i18nPath = "/i18n/i18n.properties";	
      		}
      			    	    
      	    var lv_bundleUrl = $.sap.getModulePath("ZTEST_APP", lv_i18nPath);   
      	    var lv_oBundle 	 = new sap.ui.model.resource.ResourceModel({
      		      bundleUrl	: lv_bundleUrl,		//"./i18n/i18n_en.properties"		       
      		  });	  
      	    return lv_oBundle;
          
      	},
      	
      });
  • The i18n defined variables will be accessed in views
    • To refer variable of i18n properties, following syntax is been used:
      • Syntax:            “{i18n>varName}
      • For Example:  “{i18n>PgMst_Title}
    • View ‘Master.view.xml
      • <core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"
        	xmlns="sap.m" controllerName="ZTEST_APP.view.Master" xmlns:html="http://www.w3.org/1999/xhtml">
        	<Page title="{i18n>PgMst_Title}">
        		<content>
        			<Bar>
        				<contentLeft>
        					<Button text="{i18n>PgMst_BtnTxt1}" press="pressGetMaterial" type="Accept" class="customCss_ForButton"/>
        				</contentLeft>
        				<contentMiddle>
        					<Button text="{i18n>PgMst_BtnTxt2}" press="pressODataSrv" type="Emphasized" />
        				</contentMiddle>
        				<contentRight>
        					<Button text="{i18n>PgMst_BtnTxt3}" press="pressNextPage" type="Emphasized" />
        				</contentRight>
        			</Bar>
        			<List id="idList1" mode="{device>/listMode}" items="{/listItems}">
        				<StandardListItem title="{MATNR}" />
        			</List>
        		</content>
        		<footer>
        			<Bar>
        			</Bar>
        		</footer>
        	</Page>
        </core:View>
        
        
    • View ‘Details.view.xml
      • <core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"
        	xmlns="sap.m" controllerName="ZTEST_APP.view.Details" xmlns:html="http://www.w3.org/1999/xhtml">
        	<Page title="{i18n>PgDtl_Title}" showNavButton="true" navButtonPress="backPress">
        		<content>
        			<Label text="{i18n>PgDtl_Lbl1}" design="Bold" />
        		</content>
        		<footer>
        			<Bar>
        			</Bar>
        		</footer>
        	</Page>
        </core:View>
  • Testing:
    • English-Script: When browser’s default language is English ‘en’, then script ‘i18n_en.properties’ is been referred in application
    • Hindi-Script: When browser’s default language is Hindi ‘en’, then script ‘i18n_hi.properties’ is been referred in application

 

Consume OData service in SAP UI5 Application:

  • In SAP-Fiori, one OData Service is been created which consumes RFC of SAP-R3 (back end) system
  • Detailed steps to create a OData service, can be referred from below links:
  • OData Service url is as below, which returns Material details from RFC of SAP-R3, which we will consume in SAP UI5 application
    • /sap/opu/odata/sap/ZTEST_ODATA_SRV/MaterialListSet
  • To consume this OData Service in SAP UI5 application, in ‘Master‘ Page, we create a button, and on click event of this button, we call OData-Service:
  • Button Name:            ODataSrv
  • Button Event Name:  pressODataSrv
  • View ‘Master.view.xml‘:
    • Here we define button control and its properties
    • see code screen from above in i18n section
  • ‘connectivity.js’
    • Here we define OData Service url
    • File path: ‘WebContent > view -> utils -> connectivity.js’
    • Code:
    • //OData Service URL: when testing APP in Eclipse local environment
      var serviceUrl = "proxy/http/fiori:8000/sap/opu/odata/sap/ZTEST_ODATA_SRV/";
      
      //OData Service URL: when testing app in SAP FIORI LAUNCHPAD
      //var serviceUrl = "/sap/opu/odata/sap/ZTEST_ODATA_SRV/";
    • When we plan to deploy UI5 application in SAP-Fiori server, we need to comment url ‘proxy/http/fiori:8000/sap/opu/odata/sap/ZTEST_ODATA_SRV/
    • and un-comment url “/sap/opu/odata/sap/ZTEST_ODATA_SRV/”
    • because application when accessed from Fiori-Launchpad, it takes host and port details from Launchpad itself.
  • View ‘Master.controller.js’:
    • Controller page, weher event is handled to call OData Service.
    • 1st when page load, we call OData-Service with url path “/sap/opu/odata/sap/ZTEST_ODATA_SRV/” and set its model to page view
    • 2nd one button click event “pressODataSrv”, consume OData-Service’s specifc EntitySet url path for fecthing RFC details:
    • Url path: “/sap/opu/odata/sap/ZTEST_ODATA_SRV/MaterialListSet”
    • See functions:
      1. onInit : function()
      2. pressODataSrv: function()
    • Code:
    • jQuery.sap.require("ZTEST_APP.view.utils.connectivity"); 
      jQuery.sap.require("sap.m.MessageBox");	
      sap.ui.controller("ZTEST_APP.view.Master", {
      
      	onInit : function() {	
      		
      		//Load OData Service
      		var oModel = new sap.ui.model.odata.ODataModel(serviceUrl, true);
      		sap.ui.getCore().setModel(oModel);
      		
      	},
      	
      	pressODataSrv: function(){		
      		
      		//Get list control reference
      		var list = this.getView().byId("idList1");
      		
      		//Frame Url with EntitySet
      		var url = serviceUrl + "MaterialListSet";
      				
      		//Call OdataService
      		OData.read(url, function(data) {
      
      			//Read output
      			var result = data.results;
      			
      			//set JSONoutput to a JSONModel
      			var oModel = new sap.ui.model.json.JSONModel();
      			oModel.setData({
      				listItems : result
      			});
      			
      			//Set output to ListControl			
      			list.setModel(oModel);
      						
      		}, function(err) {
      			var errTxt = err.message + "\n" + err.request.requestUri;
      			sap.m.MessageBox.show(errTxt, sap.m.MessageBox.Icon.ERROR, "Service Error");
      		});	
      	},
      		
      	pressNextPage: function(evt) {	
      		var context = evt.getSource().getBindingContext();
      		this.nav.to("Details", context);
      	},
      
      	pressGetMaterial : function(evt) {
      		var sample = $.sap.getModulePath("ZTEST_APP", "/model/sampleData.json");
      		var oModel = new sap.ui.model.json.JSONModel(sample);
      		
      		//Set JSONModeloutput to ListControl
      		var list = this.getView().byId("idList1");
      		list.setModel(oModel);	
      	},
      
      });
  • Testing:
    • Click on button “ODataSrv”
    • Debug Screen-1, here we can url input
    • Debug Screen-2, here we can see returned output
    • Post Call -> output items get filled up in List
  • Thus we have consumed OData Service in SAP UI5 Application.

Assigned Tags

      14 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Ransome Mathias
      Ransome Mathias

      Hi Dilip,

      Thanks for your post. It was very helpful. I have issue in my app. In your debug screen-2 screenshot, you demonstrated that the "result" variable has a array of output materials.
      I am using SAPwebide in my case. when I run the app and debug I am unable to see the debugger stop inside the Odata.read service call. It seems to perform a asynchronous call. I had my abap debugger placed in the entity set call method and I get the debugger stopped.

      Thats a confirmation that service call is going through well. However I am unable to catch the result and bind it. Can you please suggest me typical step done in order to see the output?

      I think the calls are going as batch calls and I don't know how to know when the calls are completed.

       

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Dear Ransome Mathias

      Please refer below inputs in your case:

      • If you expect response, then OData Service should be configured to perform synchronous call.
      • The method "OData.read(url, function(responseData)" supports synchronous (GET Method) call.
      • In case of Batch Request,
      • In case of non-Batch method, (i.e. dealing with single EnittySet "GET_ENTITYSET" methiod inside oData), then there may be issue in oDataService only,
        • however, you debugger should stop inside your app's code, either in success case (inside Odata.read )  or in error case (in side Odata.read(){},function(err) ), check the error text.
        • Go to fiori-abap-stack side, chck error t-code "/n/iwfnd/error_log/" for errors.
        • Check t-code ST22 for any dump errors.
        • And most important, check oData service code, at the point, when output is ready, and check whether output is properly mapped to response structure of OData Service, you can follow below my blogs:
      • Hope, above may help you.

       

      Thanks & Regards

      Dilip

      Author's profile photo Ransome Mathias
      Ransome Mathias

      Hi Dilip,

      Thank you so much for your inputs. Really really helpful inputs.

      Author's profile photo Ransome Mathias
      Ransome Mathias

      Hi Dilip,

      I have another issue which i logged about a month ago. I haven't been able to solve it on my own. If you could please respond with your suggestions on inputs that will be amazing. Here is the link for the question.

      https://answers.sap.com/questions/459192/unable-to-run-standard-app-from-local-webide-even.html

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      ​Dear Ransome Mathias,

       

      You can try following link suggestions and let us know, if that solved your issue

      https://archive.sap.com/discussions/thread/3937860

      Suggestions are like:

      • clear caches (Fiori server) and executed report /UI5/APP_INDEX_CALCULATE

       

      If problem is only in WebIDE, then respective library may not be available in your WebIDE.

       

      Thanks & Regards,

      Dilip

       

      Author's profile photo Ransome Mathias
      Ransome Mathias

      Hi Dilip, Thanks for the suggestion. Unfortunately that didn't work. Here is the strange observation.

      I downloaded the standard app using the projec extension method to my SAPwebid, then the app works well. Right after i download the app and then see the project folder i see the index file automatically created. I can run the app from that and I don't see any issue.

      But when i just do a normal download of the SAP app to web ide, I don't see the index file in the project. So I manually created it. I am sure about the index file is pretty fine. But somehow the app does not seem to start. I am not having any answers in the thead I created. 🙁

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Dear Ransome Mathias

      Have you tried all syntax of working index file with your erroneous project one ?

      MeanWhile I’ll check same, to download sap app in WebIDE.

      We are having practice to download/upload fiori-app to/from Eclipse, and there was no such issue with index file.

       

      Thanks & Regards,

      Dilip

       

      Author's profile photo Ransome Mathias
      Ransome Mathias

      The app is ui.ssuite.s2p.mm.pur.po.create.s1
      Please see the index file. I think the code in the file is looks good. But i doesnt seem to lauch the app when i download just the app. when I import as an extension, webide creates a index file on its own and i am able to run the same app from the webide as an extension app without done any changes.

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Dear Ransome Mathias

      In your index.html, try something like below: (specially check on src and ComponentContainer)

      	<head>
      		<meta http-equiv="X-UA-Compatible" content="IE=edge">
      		<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
      		<script
      			id="sap-ui-bootstrap"
      			src="resources/sap-ui-core.js"
      			data-sap-ui-theme="sap_bluecrystal"
      			data-sap-ui-libs="sap.m, sap.ui.layout"
      			data-sap-ui-xx-bindingSyntax="complex"
      			data-sap-ui-resourceroots='{
      				"ZAppProjectName": "./"
      			}' >
      		</script>
      	
      		<script>
      			new sap.m.Shell({
      				app : new sap.ui.core.ComponentContainer({
      					name : "ZAppProjectName"
      				})
      			}).placeAt("content");
      		</script>
      	</head>

       

      Author's profile photo Ransome Mathias
      Ransome Mathias

      I tried a couple of modification based on your index.html file

      It didnt seem to work. Please try to download the Pruchase order create app or other standard app on your webide and see i you are able to run it standalone from your system.

      I am using sapwebide personal edition.

      Author's profile photo Former Member
      Former Member

      Thanks for the detailed articles! They are really helpful.

      I've got the problem that the default project template in eclipse looks completly different:

       

      Do you have any suggestions?

      Best Regards and thx again!!

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Dear Former Member,

      • Yes, you are right, initially I was also struggling for same, default project template in eclipse looks completely different,
      • and if you try to upload this strcture (webContent ) in fiori server, you will get error.
      • The correct project structure should be like below:
      • While following above structure, we should correct references in each files of 'WebContent' folders, like:
        • In Component.js, viewName : "ZTEST_APP.view.App",
        • and in views -> ZTEST_APP.view.Master etc..
      • You can refer below blog of mine for more details:
      • This structure idea, I got from SAP's 10 UI5 App example zip file "Building SAP Fiori-like UIs with SAPUI5 - SAPUI5 Project Sources.zip"
      • You can also cross check by downloading any standard app's source project from sap fiori server.

      Thanks & Regards,

      Dilip.

       

       

      Author's profile photo SWATI KIRAN
      SWATI KIRAN

      I went through your posts many times and am successfully able to create a custom app. Thanks a lot for you detail post. it was very helpful.

      Author's profile photo Dilip Kumar Krishnadev Pandey
      Dilip Kumar Krishnadev Pandey
      Blog Post Author

      Swati...nice to know it....