Technical Articles
End to end XS Application development in hana studio
Hello All,
Hope everyone are doing good and safe!
In this blog we are going to implement an end to end sap hana xs application by using hana studio.
Introduction
Hana Studio is the best development environment to implement end to end application development i.e. Front-end(UI) + Back-end(Server-side Logic + Database stuffs). In this blog we are going to create two employee details custom tables and use those tables in calculation view to join and get the output results. After that we are going to use xsodata and xsjs service to expose view data into front-end application. XSJS is free flow process, we can write our own server-side java-script code to implement business logic.
Step 1:- First we need a server connection to implement back-end stuff. Add a system in Systems perspective.
Step 2:- Click on NEW -> XS Project
Step 3:- Provide the Project name and click on Next.
Step 4:- Select Project Workspace and check Add Project Folder as Subpackage and click on Next.
Step 5:- Select .xsaccess and .xsapp check boxes and click on Finish.
Step 6:- Project is created with below Folder structure in Project Explorer.
.xsapp file is created empty. there is no default code is generated during file creation, .xsaccess file is created with following code.
{
"exposed" : true,
"authentication" :
{
"method": "Form"
},
"cache_control" : "must-revalidate",
"cors" :
{
"enabled" : false
},
"enable_etags" : false,
"force_ssl" : false,
"prevent_xsrf" : true
}
Follow the Step 12. create MyEmp.xsjs file with below code. In MyEmp.xsjs file i am going to expose department wise employee count. It return the single Object.
/*----------------------------------------------------------------------------------------------------------------
Purpose: Service Side Java Script
----------------------------------------------------------------------------------------------------------------*/
function Employee_Count(){
var sqlstmt;
var sqlstmt2;
var conn;
conn = $.db.getConnection();
var oUser = $.session.getUsername();
sqlstmt = "SELECT COUNT (DISTINCT \"EMPID\") FROM \"Schema Name\".\"Sample_App/MyFirstView\" WHERE
DEPARTMENT IN ('ERP Technical(AD)')";
sqlstmt2 = "SELECT COUNT (DISTINCT \"EMPID\") FROM \"Schema Name\".\"Sample_App/MyFirstView\" WHERE
DEPARTMENT IN ('ERP Technical(UX)')";
var num = 0;
var num2 = 0;
var outputCount = 0;
var outputCount2 = 0;
var pstmt = null;
var pstmt2 = null;
var rs = null;
var rs2 = null;
try {
pstmt = conn.prepareStatement( sqlstmt );
$.trace.fatal( sqlstmt );
rs = pstmt.executeQuery();
while ( rs.next()) {
num = Number(rs.getString(1));
}
rs.close();
pstmt.close();
} catch ( e ) {
if ( rs !== null ) {
rs.close();
}
if ( pstmt !== null ) {
pstmt.close();
}
$.trace.fatal( e );
}
try {
pstmt2 = conn.prepareStatement( sqlstmt2 );
$.trace.fatal( sqlstmt2 );
rs2 = pstmt2.executeQuery();
while ( rs2.next()) {
num2 = Number(rs2.getString(1));
}
rs2.close();
pstmt2.close();
} catch ( e ) {
if ( rs2 !== null ) {
rs2.close();
}
if ( pstmt2 !== null ) {
pstmt2.close();
}
$.trace.fatal( e );
}
var body = {};
if (num > 0) {
outputCount = num;
outputCount2 = num2;
}
else{
outputCount = 0;
outputCount2 = 0;
}
body = //JSON.stringify(
{"d":
{
UserExp: outputCount2,
ApplDev: outputCount,
UserName:oUser
}};
return body;
}
$.trace.fatal( "========== BEGIN ==========" );
var result = [];
try {
var conn = $.db.getConnection();
result = Employee_Count();
conn.close();
} catch ( e ) {
$.trace.fatal( e );
}
var output = {};
output = result;
$.response.contentType = 'application/json';
$.response.setBody( JSON.stringify( output ) );
$.trace.fatal( "=========== END ===========" );
Follow the Step 12 create MyService.xsodata to fetch data from database objects and expose to UI. In MyService.xsodata i am going to expose employee details Emp_Details2 is EntitySet.
service {
"Schema Name"."Sample_App/MyFirstView" as "Emp_Details2" keys("EMPID");
}
annotations {
enable OData4SAP;
}
<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m" xmlns:table="sap.ui.table" xmlns:comn="sap.ui.commons"
xmlns:smartFilterBar="sap.ui.comp.smartfilterbar" xmlns:smartTable="sap.ui.comp.smarttable"
xmlns:f="sap.f" displayBlock="true"
controllerName="Sample_App.Table_GUI.view.Table_Grouping"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns:customData="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1">
<f:DynamicPage id="oDynamicPageId">
<f:title>
<f:DynamicPageTitle>
<f:heading>
<Title text="ERP Technical Employee Info" />
</f:heading>
<f:actions>
<ToolbarSpacer />
<core:Icon src="sap-icon://refresh" tooltip="Logout"
noTabStop="true" press="onLogOutPress" />
<core:Icon id="oExeId" src="sap-icon://donut-chart"
tooltip="Visualization" noTabStop="true" />
</f:actions>
</f:DynamicPageTitle>
</f:title>
<f:content>
<smartTable:SmartTable id="pricequoteTable"
smartFilterId="smartFilterBar"
beforeRebindTable="beforeRebindTable"
enableAutoBinding="true"
entitySet="Emp_Details2" initialise="onSmartTableInit"
tableType="ResponsiveTable" editTogglable="true" customData:useSmartField="true" showTablePersonalisation="true"
fieldChange="onFieldChange" useExportToExcel="true" editable="false"
useVariantManagement="true" useTablePersonalisation="true"
header="Employees" width="100%" height="100%"
class="sapUiSizeCompact">
</smartTable:SmartTable>
</f:content>
<f:footer>
<OverflowToolbar>
<ToolbarSpacer />
<Button type="Accept" icon="sap-icon://save" text="Save"
press="oSubmitChanges" />
<Button type="Reject" text="Reject" press="onReject"/>
</OverflowToolbar>
</f:footer>
</f:DynamicPage>
</core:View>
controller code:
jQuery.sap.require("sap.m.MessageBox");
sap.ui.controller("Sample_App.Table_GUI.view.Table_Grouping",{
onInit: function() {
var sURL, oModel, oView;
sURL = "/Sample_App/MyService.xsodata";
var oModel = new sap.ui.model.odata.v2.ODataModel(sURL);
oModel.setDefaultBindingMode("TwoWay");
var oView = this.getView();
oView.setModel(oModel);
var oTable = this.getView().byId("pricequoteTable");
oTable.setInitiallyVisibleFields("EMPID,EMP_NAME,DESIGNATION,MOBILE,ADDRESS,DEPARTMENT");
this.oRouter = sap.ui.core.routing.Router.getRouter("appRouter");
var oPage = this.getView().byId("oDynamicPageId");
oPage.setShowFooter(!oPage.getShowFooter());
},
onSmartTableInit : function(oEvent){
var oTable = oEvent.getSource().setShowRowCount(true);
},
onAfterRendering : function(){
var oTable = this.getView().byId("pricequoteTable");
if(!oTable){
var oPersButton = oTable._oTablePersonalisationButton.attachPress(function(){
var oPersController = oTable._oPersController;
var oPersDialog = oPersController._oDialog.fireReset();
});
}
this.getView().byId("oExeId").attachPress(function(){
sURL = "/Sample_App/MyEmp.xsjs";
var oModel = new sap.ui.model.odata.v2.ODataModel(sURL);
var uxArr = 0;
var adArr = 0;
$.get(sURL, function(data, status){
adArr = data.d.ApplDev;
uxArr = data.d.UserExp;
var oPanel = new sap.m.Panel({ height:"500px", width:"100%"});
var oId = oPanel.sId;
var chart = AmCharts.makeChart(oId,{
"type": "pie",
"theme": "light",
"innerRadius": "40%",
"gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5],
"dataProvider": [{
"Department": "ERP Technical(UX)",
"Count": uxArr
},
{
"Department": "ERP Technical(AD)",
"Count": adArr
}],
"balloonText": "[[value]]",
"valueField": "Count",
"titleField": "Department",
"balloon": {
"drop": true,
"adjustBorderColor": false,
"color": "#FFFFFF",
"fontSize": 16
},
"export": {
"enabled": true
}
});
this.resizableDialog = new sap.m.Dialog({
title: 'Employee Details Visualization',
contentWidth: "100%",
contentHeight: "100%",
resizable: true,
draggable : true,
content: oPanel,
beginButton: new sap.m.Button({
text: 'Close',
press: function () {
oPanel.destroyContent();
this.resizableDialog.destroy();
}.bind(this)
})
});
this.resizableDialog.open();
chart.write(oId);
// }});
});
});
},
oSubmitChanges : function(){
var oTable = this.getView().byId("pricequoteTable");
var changesFlag = this.getView().getModel().hasPendingChanges();
if(changesFlag){
oTable.setEditable(false);
this.getView().getModel().submitChanges({success:function(){
sap.m.MessageToast.show("Successfully submitted");
}});
}else{
sap.m.MessageToast.show("No pending changes to submit");
}
},
onReject:function(){
var oTable = this.getView().byId("pricequoteTable");
oTable.setEditable(false);
this.getView().getModel().resetChanges();
}
});
Here is the output: Once we click on top right corner icon(donut). Visual chart will be appear on dialog with department wise employee count.
Hope this blog was helpful to implement end to end XS Application. take this as reference and implement your first application.
Just a note:
You say in the introduction that you describe "XS Advanced Application development". But what you are describing in that blog post is the development of an XS Classic application. XS Advanced is not available for HANA Studio at all.
And: XS Classic is already deprecated for quite some time now. So I think you have to update knowledge about the current status of application development options on HANA.
Hi Lakshmi,
Thanks for the effort but I have to agree with Florian: this would have been a great blog about 6 to 7 years ago, before the introduction of XS advanced.
Current development focus is on the Business Application Studio (vscode), Cloud Application Programming Model (CAP). RestFul ABAP (RAP), and Kyma (serverless / Kubernetes).
Maybe this post might get you up to speed.
To provide a timeline for XS:
Hi Experts,
Really thanks a lot both of you! Basically i am a Front-End developer, Almost 3 years back i used to work on hana xs, later i switched my job and switched to new development environment, i didn’t much focused on hana. Your suggestions makes me dive towards advanced options in hana.
Hi Lakshmi,
Quite new thing very helpful blog for beginners.