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

Develop your SAPUI5 applications in Ubuntu

$
0
0

Prerequisites

You should have already installed and be running Ubuntu. You might be surprised to know you can run Ubuntu from a USB drive. It would be easier to relate to all the topics if you already made a "Hello World" using SAPUI5 on Eclipse on Windows already.


Environment

I tested it out with Ubuntu 12.04. It should work with further versions too.

Problem

We are all usually more familiar with running SAP UI5 applications on Windows and wish if we could run it all on Linux/Ubuntu but may not be familiar with how to go about it as Linux scares off most of us.

 

Solution

By the end of this document, you will be running your SAPUI5 apps in Eclipse in Ubuntu.


STEP 1 : Eclipse needs JDK

Goto Terminal (Ctrl + Alt + T) and run the following command:

sudo apt-getinstall openjdk-7-jdk 

STEP 2: Download latest "Eclipse IDE for Java Developers" from the below link

Eclipse Downloads

You may check out your OS Type 32-bit or 64-bit by going to System Settings -> Details -> OverviewScreenshot from 2015-05-15 13:02:30.png

STEP 3: Extract Eclipse to /opt/ for global use

Goto Terminal (Ctrl + Alt + T) and run the following command

cd /opt/ && sudo tar -zxvf ~/Downloads/eclipse-*.tar.gz

STEP 4: Create a launcher shortcut for Eclipse

Goto Terminal (Ctrl + Alt + T) and run the following command:

gksudo gedit /usr/share/applications/eclipse.desktop

Above command will create and open the launcher file for eclipse with gedit text editor.

Paste below content into the opened file and save it.

[Desktop Entry]
Name=Eclipse 4
Type=Application
Exec=/opt/eclipse/eclipse
Terminal=false
Icon=/opt/eclipse/icon.xpm
Comment=Integrated Development Environment
NoDisplay=false
Categories=Development;IDE;
Name[en]=Eclipse

Finally open Eclipse from Unity Dash search results and launch it.
launch eclipse in ubuntu 14.04

STEP 5: Install the SAP UI5 plugin and start developing your apps
(Follow the usual drill for the Eclipse UI5 plugin elaborated at: How to install a basic development environment for SAPUI5.)

Go to your eclipse under "Help - Install New Software...". Paste one of the following URLs in the "Work with" input field, to get a list of available downloads options. You can find a list of all update-site URLs on the following site.

Screenshot from 2015-05-15 14:54:38.png

Select the entry "UI development toolkit for HTML5" and finish the wizard. Restart eclipse after you complete the installation. Then go to "File - New - Others" and type in the Wizard "UI5" and so on.

 

Screenshot from 2015-05-15 14:42:54.png

STEP 7: Enjoy your apps running !

Screenshot from 2015-05-15 14:41:23.png

Screenshot from 2015-05-15 14:48:09.png

 

A note for the readers
Please do rate the document and let me know your thoughts about the content. I would love to accommodate your suggestions. Your comments let me track my work and reflect upon my future output.

 

Links

Download Ubuntu

Eclipse Downloads

How to install a basic development environment for SAPUI5


Download file from SAP System to Mobile/Tablet - Part II

$
0
0

Hi All,

 

Part I:  Upload Images from Tablet/Mobile to SAP - Part I

 

INTRO:

A document management system (DMS) is a system (based on computer programs in the case of the management of digital documents) used to track and store documents. It is usually also capable of keeping track of the different versions modified by different users (history tracking).


Step1:

          -Use Cordova to create your apk/ipa project. Because of cordova have more than 200 plugins to enhance android/ios applications.           File opener could be among one of them.

          API link: markeeftb/FileOpener · GitHub

          -Add this plugin into your cordova project

          - Command: plugin add "plugin link"


Step2: Code snippet

 

function commonDownloadAndDisplayDoc(mime, filename){

 

    var downloadUrl = "http://MY-SYSTEM-eu.com:8100/sap/opu/odata/sap/ZGW_HELP_FILES_SRV/FileSet(filename)/$value";

    var relativeFilePath; // using an absolute path also does not work

    switch(mime){

    case "PDF":

    relativeFilePath = "HERE_Document_Dir/Viewer.pdf";

    break;

    case "PPT":

    relativeFilePath = "HERE_Document_Dir/Viewer.ppt";

    break;

    case "WRD":

    relativeFilePath = "HERE_Document_Dir/Viewer.doc";

    break;

    case "XLS":

    relativeFilePath = "HERE_Document_Dir/Viewer.xls";

    break;

    case "JPG":

    relativeFilePath = "HERE_Document_Dir/Viewer.jpg";

    break;

    case "PNG":

    relativeFilePath = "HERE_Document_Dir/Viewer.png";

    break;

    case "GIF":

    relativeFilePath = "HERE_Document_Dir/Viewer.gif";

    break;

    case "MP4":

    relativeFilePath = "HERE_Document_Dir/Viewer.mp3";

    break;

    case "TXT":

    relativeFilePath = "HERE_Document_Dir/Viewer.mp4";

    break;

    case "MP3":

    relativeFilePath = "HERE_Document_Dir/Viewer.mp3";

    break;

    default:

    relativeFilePath = "HERE_Document_Dir/Viewer";

    }

 

    window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {

      var fileTransfer = new FileTransfer();

      fileTransfer.download(

         downloadUrl,

         fileSystem.root.toURL() + '/' + relativeFilePath,

         function (entry) {

    var finalRes = fileSystem.root.toURL() + '/' + relativeFilePath;

    window.plugins.fileOpener.open(finalRes);//Working

    closeSplashScreen();//splash screen closed

         },

         function (error) {

           alert("Error during download. Code = " + error.code);

    closeSplashScreen();//splash screen closed

         },true//Trust all host

      );

    });

 

    }

This code will automatically open your requested file.


Step 3:

Run your application in Android/Ios mobile---> open ES folder -->under that folder "HERE_Document_Dir" search this name-->yup, I got my file



Thanks,

Karthik A

Using roundedTiles as "menus" in UI5

$
0
0

Hi again

 

Some of you might have read my previous post about the Rounded Tiles in UI5 and wonder what more can be done with those...

 

If you are not familiar with OpenUI5, go and check the great work they are doing on OpenUI5

 

I worked a bit on the main idea that drove me creating those round tiles and I'm happy to share the next step with you...

When I started the customisation of the tiles to be able to show as round tiles, I had an idea of what I wanted to accomplish next. I wanted to have tiles that acts as "menus" having some actions attached to them... As it can't be explained better than with a screenshot of the final result, here it is:

 

screen1.jpegscreen2.jpeg

(Of course the different tiles colours are just for the purpose of this blog to show the display customising I implemented)

 

So basically, a tile can have what I will further in this blog call "actions" that are some kind of "baby tiles" on which the user press to navigate to a specific view...

It allows the grouping of actions about the same subject under the same tile and, at the same time, reduce the number of tiles necessary in the launch page of your UI5 app. The control can handle up to seven actions without any overlap.

 

I'll not cover here the entire source code but only the most important parts of it. Please refer to the GitHub link at the end of the post for the entire source code, and the JSFiddle for a live demo.

 

What follows is very technical and if you don't really care and just want to know how to use the control, scroll down till point 2.

 

 

1) The control

 

The code of the control can be found under WebContent / controls / roundedActionTile. This folder contains 2 files: the javascript code for the roundedActionTiles and the CSS attached to the control.

 

1.1) The JS code

 

As usual, at the beginning of the file some lines declares the control, attach the control specific css file (see 1.2 bellow) and requires the necessary standard libraries.

 

jQuery.sap.declare("controls.roundedActionTile");
jQuery.sap.includeStyleSheet("controls/roundedActionTile/roundedActionTile.css");
jQuery.sap.require("sap.m.StandardTile");
jQuery.sap.require("sap.ui.core.IconPool")

The control inherits from the sap.m.StandardTile object in order to keep the functionalities available for that object.

It extends the StandardTile by adding some properties (iconColor, cssClass) and the control has an attribute aTileOptions that is an array that will contain the actions attached to the tile.

 

metadata :{    properties : {    // Icon color property with default value to standard UI5 blue        iconColor : {            type : "string",            defaultValue : "#007cc0"        },        cssClass:{            type : "string",            defaultValue: "defaultActionClass"        }    },    events:{        actionPress : {}    }
 },
aTileOptions: null,

The biggest part of the work is, as you can guess the rendering of the control to be able to display the actions around the tile. In the render function, you will find the code computing the positions and creating these actions. The computations are dynamic in order to handle the different number of actions. After the computation, it uses the CSS3 transform in order to rotate and translate the div created for the actions.

 

if(oControl.aTileOptions){// Start actions management    var startPoint, nbrLeft, firstPosition = 0; // initialize the variable     var rotationFactor = 51; // Fixed rotation factor (based on the action div size)    startPoint = -135; // Starting point of the rotations    if(oControl.aTileOptions.length%2 == 1){ // compute the number of elements to be placed on the left        nbrLeft = (parseInt(oControl.aTileOptions.length/2));    }else{        nbrLeft = (parseInt(oControl.aTileOptions.length/2) - 0.5);    }    // Compute the first position to be taken by the created action div.    firstPosition = startPoint - (nbrLeft*rotationFactor);     for(var i in oControl.aTileOptions){        var rotation = firstPosition + (rotationFactor*i); // Compute the rotation needed for the current action        var invertedRotation = rotation>0?-rotation:Math.abs(rotation); // compute the inverse rotation (used for the content)        rm.write("<div");// Start action container        rm.writeAttribute("id", oControl.getId() + "-action_"+i);        rm.writeAttribute("style", "transform: rotate("+ rotation +"deg) translate(80px,80px);"); // apply transformation        rm.addClass("actionItem");        rm.addClass("actionHidden");        if(oControl.aTileOptions[i].cssClass) // apply the custom or standard CSS class            rm.addClass(oControl.aTileOptions[i].cssClass);        else            rm.addClass("defaultActionClass");        rm.writeClasses();        if (oControl.aTileOptions[i].title) { // Write the action title as tooltip            rm.write(" title=\"");            rm.writeEscaped(oControl.aTileOptions[i].title);            rm.write("\"");        }        rm.write(">");        // Start Icon        rm.write("<div");        rm.addClass("innerActionItem"); // create the content of the action        // apply the inverted rotation to the content of the action div        rm.write(" style=\"color:" + oControl.aTileOptions[i].iconColor + "; transform: rotate("+ invertedRotation +"deg);\"");         rm.writeClasses();        rm.write(">");        var action_icon = oControl.getActionImage(oControl.aTileOptions[i].icon);// get the icon        action_icon.addStyleClass('roundedActionTileActionIcon');        rm.renderControl(action_icon);        rm.write("</div>");        // End Icon        rm.write("</div>");// End action container        oControl.aTileOptions[i].sId = oControl.getId() + "-action_"+i;// add the id of the created div in the aTileOption attribute for future reference
}

As you might have notice, I save the DOM id of the div created for the actions in the aTileOptions array. This is necessary to easily lookup the elements in order to hide and show them. This will be performed by the following function:

 

showActions:function(bVisible){    for(var i in this.aTileOptions){        var elem = this.$().find("#"+this.aTileOptions[i].sId);// lookup the element by id saved during the rendering        if(elem){            bVisible?elem.removeClass("actionHidden"):elem.addClass("actionHidden");// hide or show the DOM element        }    }
}

This function is not called by the control itself but by your controller to give a maximum of flexibility to your solution.

Having done all this, we just need to attach the events on the actions, and of course, a blur event to the control to hide the actions when the tile looses the focus... This is done after the rendering by the following function:

 

onAfterRendering:function(){    // Call the parent method as it's the one placing the tiles in the container    sap.m.Tile.prototype.onAfterRendering.call(this);    for(var i in this.aTileOptions){        // lookup the elements in order to add the listener on the click        var elem = this.$().find("#"+this.aTileOptions[i].sId);        if(elem){            elem.click(function(oEvent){                this.actionClicked({tile: this, actionId:oEvent.currentTarget.id});            }.bind(this));        }    }    // attach the blur event on the tile to hide the actions when it looses the focus    this.$().blur(function(){        for(var i in this.aTileOptions){            var elem = this.$().find("#"+this.aTileOptions[i].sId);            if(elem){                elem.addClass("actionHidden");            }        }    }.bind(this));
}

Now we just need to trigger the actionPress event declared in the control metadata and we will have a control ready to use. The actionPress event declared in the control metadata will be fired by the function actionClicked used by the onClick of the action. The JSON object used as parameter will contain the actionTag that you will have associated to the action definition... See point 2 bellow.

 

actionClicked:function(oParams){    for(var i in oParams.tile.aTileOptions){        if(oParams.tile.aTileOptions[i].sId === oParams.actionId){            oParams.action = { actionTag : oParams.tile.aTileOptions[i].actionTag};            break;        }    }    this.fireActionPress(oParams);
}

1.2) The CSS file

 

The CSS file used here is pretty straightforward as it's all CSS3 classes used for the control rendering.

Please note the "defaultActionClass" which is the class used by default if you don't specify any for the tiles or for the tile actions.

 

.defaultActionClass{
 color: #007cc0;
 border: 1px solid #007cc0; 
 background-color: rgb(255, 255, 255);
}

 

2) Using the control

 

2.1) The view

 

The roundedActionTiles are meant to be placed in a standard TileContainer (sap.m.TileContainer) that you need to declare in the view.

 

this.oTilesContainer =new sap.m.TileContainer();
this.oTilesContainer.setHeight("100%");
this.oTilesContainer.setVisible(true);
return new sap.m.Page({  title : "Rounded Actions Tiles",  enableScrolling : false,  content : [    this.oTilesContainer  ]
});

2.2) The controller

 

In the controller, load the control using the "require"

 

jQuery.sap.require("controls.roundedActionTile.RoundedActionTile");

Assuming that you have declared (or loaded from your backend) a structure as follow:

 

tiles : [  {    title : "Tile 1",    icon : "Chart-Tree-Map",    options : [      {        title : "Add",        icon : "add",        cssClass: "exampleClass1",        actionTag: "Tile 1 - Action 1"      }, {        title : "Browse",        icon : "search",        actionTag: "Tile 1 - Action 2"      }    ]  },  ...

You just need to create the controls as:

 

for ( var c in this.tiles) {  var tileItem = new controls.RoundedActionTile();  tileItem.setTitle(this.tiles[c]["title"]);  tileItem.setIcon("sap-icon://" + this.tiles[c]["icon"]);  if (this.tiles[c]["cssClass"])    tileItem.setCssClass(this.tiles[c]["cssClass"]);  if (this.tiles[c]["iconColor"])    tileItem.setIconColor(this.tiles[c]["iconColor"]);  if (this.tiles[c]["options"]) {    tileItem.setTileOptions(this.tiles[c]["options"]);  }  this.tiles[c].object = tileItem;  tileItem.attachPress({    index : c  }, this.showOptions, this);  tileItem.attachActionPress(this.handleAction, this);  this.getView().oTilesContainer.addTile(tileItem);
}

and the rounded tiles with actions will be created.

 

Of course in your controller you need a method to handle the click on tiles to show the actions or, if no action has been defined on the tile, do what you need to do upon clicking on a tile... This function will use the "showActions" function defined on the control (as described in 1.1)

 

showOptions : function(oEvent, oParams) {  //Hide the visible actions (if any)  for ( var c in this.tiles) {    this.tiles[c].object.showActions(false);  }  // if the tile has actions, show them, else handle the "normal tile click"  if(this.tiles[oParams.index]["options"])    this.tiles[oParams.index].object.showActions(true);  else    this.handleAction(oEvent, oParams);
 }

And then, last part of the code is to do the actual processing (navigate to a view, ...) upon clicking an action or a tile without action

 

handleAction : function(oEvent, oParams) {  if(oEvent.getParameter('action'))    alert(oEvent.getParameter('action').actionTag);  else    alert(oEvent.getParameter('id'));
}

I hope you will enjoy this control, let me know your thoughts and comments

 

Happy coding

 

 

Link to the GitHub repository: dafooz/roundedActionTilesUI5 · GitHub

Link to the JSFiddle for a live demo: Rounded Actions Tile in UI5 - JSFiddle(Note that the code has been slightly modified in the fiddle in order to have all the Javascript inline)

Using Tokenizer to make Pie Chart work as a filter for table

$
0
0

Hi folks!!!

 

I was working on the Pie Chart for some use case, I found and implemented interesting functionality by using Tokenizer along with the Pie Chart enabling to act as a filter for table to populate the data according to one or more clicked context in the table.

 

I got this idea by seeing several filter options on modern web applications. I have gone through many threads and discussion on populating data into table on click of chart which helped me a lot. so, taking reference of these implementation, thought to implement filter on pie chart as well. so, sharing my experience with you. It may look like below image.

 

Functionality is on clicking on the slices of pie chart, the token will be generated accordingly in table toolbar and correspondingly data will be populated/filtered inclusively in table with option of multi-select. And as will go on cancelling/deleting the token then also it will filter the data in table depending on the action.

 

Img3.png

 

 

 

Project Hierarchy :-

 

Below image represents the list of files which have been used.

 

projectHierarchy.png

Step By Step Process :-


  1. Created a SAPUI5 Applicate Project using Eclipse IDE.

Image1.png

 

2. Selected sap.m library & Created an Initial View check box. And then Finish.

 

Image1.png

 

 

 

 

 

3. Created a Dummy JSON Model

 

{
"paymentDetail":  [  {  "paymentID":"R1000",  "invoiceNumber":"IN2345",   "amount":"25 Lakhs",   "dueDate":" 14 April,2015",   "duePeriod":"30"  },  {  "paymentID":"R1001",  "invoiceNumber":"IN4523",   "amount":"15 Lakhs",   "dueDate":" 24 April,2015",   "duePeriod":"20"  },  {  "paymentID":"R1002",  "invoiceNumber":"IN7564",   "amount":"5 Lakhs",   "dueDate":" 1 May,2015",   "duePeriod":"14"  },   {  "paymentID":"R1003",  "invoiceNumber":"IN9856",   "amount":"3 Lakhs",   "dueDate":" 5 May,2015",   "duePeriod":"08"  }                   ],        "pieChartData":[  {  "days":">=15 Days",  "value":"35"  },  {  "days":"16-30 Days",  "value":"65"  },  {  "days":"31-45 Days",  "value":"95"  },  {  "days":"<45 Days",  "value":"15"  }  ],
}


Main.view.js

 

sap.ui.jsview("piewithtokenizer.main", {  /** Specifies the Controller belonging to this View.  * In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.  * @memberOf piewithtokenizer.main  */  getControllerName : function() {  return "piewithtokenizer.main";  },  /** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.  * Since the Controller is given to this method, its event handlers can be attached right away.  * @memberOf piewithtokenizer.main  */  createContent : function(oController) {  /*  * JSON Model*/  var oModel = new sap.ui.model.json.JSONModel("./Model/dummy.json");  this.setModel(oModel);  console.log("oModel",oModel);  // Dataset For PieChart  var pieChartDataSet = new sap.viz.ui5.data.FlattenedDataset("paymentAgingReport",{  dimensions:[{axis:1, name:'Days', value:'{days}'}],  measures:[{name:'Payments Due', value:'{value}'}],  data:{path:"/pieChartData"}  });  var oLabel = new sap.m.Label({text:"Loading Report..."});  //Defining Pie Chart  var pieChart = new sap.viz.ui5.Pie("agingReportChart",{   id : "pie",   width : "70%",   height : "250px",   dataset: pieChartDataSet,   noData:oLabel,   selectData:oController.onSelectPieChart,   deselectData:oController.onDeselectPieChart   });  pieChart.setInteraction(     new sap.viz.ui5.types.controller.Interaction({       selectability: new sap.viz.ui5.types.controller.Interaction_selectability({         mode: sap.viz.ui5.types.controller.Interaction_selectability_mode.inclusive       })     })   );  var reportTitle = new sap.m.Label({text:"Payment Aging Report", design:sap.m.LabelDesign.Bold});  var titleOverFlowBar = new sap.m.OverflowToolbar({  content:[new sap.m.ToolbarSpacer({width:"20%"}),reportTitle,new sap.m.ToolbarSpacer({})]  }).addStyleClass("titleToolBar");  var pieFlexBox = new sap.m.FlexBox("pieFlexBox",{   width: "100%",   height: "auto",   direction: sap.m.FlexDirection.Column,   justifyContent : sap.m.FlexJustifyContent.Center,   alignItems: sap.m.FlexAlignItems.Center,        items: [                titleOverFlowBar,                pieChart                         ]    }).addStyleClass("KPIFlexBox");  var hBox = new sap.m.HBox({  items:[pieFlexBox]  });  //Search ToolBar  var title = new sap.m.Label({text:"Payment List", design:sap.m.LabelDesign.Bold});  var oSearch = new sap.m.SearchField("searchTable",{  width:"20%",  liveChange:oController.onSearch,  search:oController.onSearch  });  var sortButton = new sap.m.Button({icon:"sap-icon://sort",type:sap.m.ButtonType.Transparent,tooltip:"Sort on Due Period",press:oController.onSort});  var resetButton = new sap.m.Button({text:"RESET", type:sap.m.ButtonType.Transparent,press:oController.onReset});  var tokens = new sap.m.Tokenizer("token");  var overFlowBar = new sap.m.OverflowToolbar({  content:[tokens,new sap.m.ToolbarSpacer({}),title,new sap.m.ToolbarSpacer({}),oSearch,resetButton,sortButton]  }).addStyleClass("tableToolBar");  // Defining Table  var otable = new sap.m.Table("table");  otable.addColumn(  new sap.m.Column({header: new sap.m.Text({text:"Payment ID"})})  );  otable.addColumn(  new sap.m.Column({header: new sap.m.Text({text:"Invoice Number"})})  );  otable.addColumn(  new sap.m.Column({header: new sap.m.Text({text:"Amount(INR)"})})  );  otable.addColumn(  new sap.m.Column({header: new sap.m.Text({text:"Due Date"})})  );  otable.addColumn(  new sap.m.Column({header: new sap.m.Text({text:"Due Period (In Days)"})})  );  var tableRow = new sap.m.ColumnListItem("tableRow");  var paymentID = new sap.m.Text({text:"{paymentID}"});  var invoiceNumber = new sap.m.Text({text:"{invoiceNumber}"});  var amount = new sap.m.Text({text:"{amount}"});  var dueDate = new sap.m.Text({text:"{dueDate}"});  var duePeriod = new sap.m.Text({text:"{duePeriod}"});  tableRow.addCell(paymentID).addCell(invoiceNumber).addCell(amount).addCell(dueDate).addCell(duePeriod);  otable.bindItems("/paymentDetail", tableRow);  return new sap.m.Page({  title: "Payment Report",  content: [hBox,            overFlowBar,            otable  ]  });  }
});


Main.controller.js

 

onSelectPieChart : function(oEvent) {  selectedData = this.selection();  if (onPieChartInitialize == false) {  tokVal = selectedData[0]["data"]["Days"];  switch (tokVal) {  case '>=15 Days':  chartTokenArray.push(tokVal);  addToken();  filterTableGrid();  break;  case '16-30 Days':  chartTokenArray.push(tokVal);  addToken();  filterTableGrid();  break;  case '31-45 Days':  chartTokenArray.push(tokVal);  addToken();  filterTableGrid();  break;  case '<45 Days':  chartTokenArray.push(tokVal);  addToken();  filterTableGrid();  break;  default:  break;  }  this.onPieTable;  }  },  onDeselectPieChart : function() {  sap.ui.getCore().byId("token").destroyTokens();  chartTokenArray = [];  sap.ui.getCore().byId("searchTable").setValue("");  var oTable = new sap.ui.getCore().byId("table");  var oRow = new sap.ui.getCore().byId("tableRow");  oTable.bindItems("/paymentDetail", oRow);
},  onSearch : function(oEvent) {  var searchString = oEvent.getParameters().newValue;  if (searchString == undefined) {  searchString = oEvent.getParameters().query;  }  console.log("searchString", searchString);  var filter = new sap.ui.model.Filter("dueDate",  sap.ui.model.FilterOperator.Contains, searchString);  var filter1 = new sap.ui.model.Filter("paymentID",  sap.ui.model.FilterOperator.Contains, searchString);  var filter2 = new sap.ui.model.Filter("invoiceNumber",  sap.ui.model.FilterOperator.Contains, searchString);  var filter3 = new sap.ui.model.Filter("duePeriod",  sap.ui.model.FilterOperator.Contains, searchString);  var combFilter = new sap.ui.model.Filter([ filter, filter1, filter2,  filter3 ]);  var oTable = new sap.ui.getCore().byId("table");  console.log("table", oTable);  oTable.getBinding("items").filter(combFilter,  sap.ui.model.FilterType.Application);  },  onReset : function() {  sap.ui.getCore().byId("searchTable").setValue("");  var oTable = new sap.ui.getCore().byId("table");  var oRow = new sap.ui.getCore().byId("tableRow");  oTable.bindItems("/paymentDetail", oRow);  },  onSort : function() {  if (order) {  order = false;  } else {  order = true;  }  var osort = new sap.ui.model.Sorter("duePeriod", order);  var oTable = new sap.ui.getCore().byId("table");  oTable.getBinding("items").sort(osort);  },

 

Util.js

 

/*
* @File : Utility Javascript file for common code used in the application
*/
var tokenText; // Global Variables
var arr, f1, f2;
var ofilter;
var counter = false;
/*
* Function to add Token on click of slice of Pie Chart
*/
function addToken() {  sap.ui.getCore().byId("token").addToken(  new sap.m.Token({  text : tokVal  }).attachDelete(function() { // Function for deleting Token  tokenText = this.getText();  var flag = chartTokenArray.indexOf(tokenText);  if (flag >= 0) {  chartTokenArray.splice(flag, 1);  sap.ui.getCore().byId("agingReportChart")  .attachInitialized(onInitialLoad); // For Initializing the Pie Chart on Token Delete Event  sap.ui.getCore().byId("agingReportChart").getModel()  .refresh(true); // Refreshing the Pie Chart so that Initialized event can Fire  counter = true;  sp(tokenText);  }  }));
}
/*
* Function to be called on initialization of Pie Chart after deleting tokens
*/
function onInitialLoad(oEvent) {  var pieDataArray = [];  var count = 0;  for (i in selectedData) {  var obj = selectedData[i];  for (j in obj) {  var subObj = obj[j];  for (key in subObj) {  if (key == "Days") {  if (subObj[key] != tokenText) {  var SD = selectedData.indexOf(subObj);  pieDataArray.push(obj);  }  }  }  }  }  selectedData = pieDataArray;  var selectionPoint = pieDataArray;  if (selectionPoint.length == 0) {  onPieChartInitialize = false;  } else {  onPieChartInitialize = true;  }  sap.ui.getCore().byId("agingReportChart").selection(selectionPoint);
}
/*
* Function to filter Table Grid according to Pie Chart Action
*/
function filterTableGrid() {  var length = chartTokenArray.length;  console.log("length", length);  if (length == 0) {  var oTable = sap.ui.getCore().byId("table");  var tableItem = sap.ui.getCore().byId("tableRow");  oTable.bindItems("/paymentDetail", tableItem);  } else {  var ofilter;  console.log(firstValue);  console.log(secondValue);  for (i = 0; i < length; i++) {  var text = chartTokenArray[i];  text = text.split(" ");  console.log("text", text[0]);  if (text[0].indexOf("-") >= 0) {  arr = text[0].split("-");  ofilter = sp();  } else if (text[0].indexOf("=") >= 0) {  text[0] = "0-15";  arr = text[0].split("-");  ofilter = sp();  } else if (text[0].indexOf("<") >= 0) {  arr = text[0].split("<");  f2 = arr[1];  ofilter = new sap.ui.model.Filter("duePeriod",  sap.ui.model.FilterOperator.GT, f2);  }  }  var oTable = sap.ui.getCore().byId("table");  oTable.getBinding("items").filter(ofilter);  }
}
/*
* Function to filter the table data on deleting the tokens*/
function sp(tokenText) {  if (!counter) {  if (firstValue.indexOf(arr[0]) < 0) {  firstValue.push(arr[0]);  }  if (secondValue.indexOf(arr[1]) < 0) {  secondValue.push(arr[1]);  }  f1 = Math.min.apply(Math, firstValue);  console.log("f1", f1);  console.log("firstValue", firstValue);  f2 = Math.max.apply(Math, secondValue);  console.log("f2", f2);  console.log("secondValue", secondValue);  ofilter = new sap.ui.model.Filter("duePeriod",  sap.ui.model.FilterOperator.BT, f1, f2);  return ofilter;  } else {  console.log("ttt", tokenText);  var tokVal;  var tokenTextArray = tokenText.split(" ");  if (tokenTextArray[0].indexOf("-") >= 0) {  tokVal = tokenTextArray[0].split("-");  var flag = firstValue.indexOf(tokVal[0]);  if (flag >= 0) {  firstValue.splice(flag, 1);  }  var flag2 = secondValue.indexOf(tokVal[1]);  if (flag2 >= 0) {  secondValue.splice(flag2, 1);  }  console.log("spliceFirst", firstValue);  console.log("splicesecond", secondValue);  } else if (tokenTextArray[0].indexOf("=") >= 0) {  tokenTextArray[0] = "0-15";  tokVal = tokenTextArray[0].split("-");  var flag = firstValue.indexOf(tokVal[0]);  if (flag >= 0) {  firstValue.splice(flag, 1);  }  var flag2 = secondValue.indexOf(tokVal[1]);  if (flag2 >= 0) {  secondValue.splice(flag2, 1);  }  console.log("spliceFirst", firstValue);  console.log("splicesecond", secondValue);  } else if (tokenTextArray[0].indexOf("<") >= 0) {  tokVal = tokenTextArray[0].split("<");  //firstValue.splice(tokVal[0],1);  secondValue.splice(tokVal[1], 1);  console.log("spliceFirst", firstValue);  console.log("splicesecond", secondValue);  }  console.log("spliceFirstl1", firstValue.length);  console.log("splicesecondl2", secondValue.length);  if (firstValue.length == 0 && secondValue.length == 0) {  var oTable = sap.ui.getCore().byId("table");  var tableItem = sap.ui.getCore().byId("tableRow");  oTable.bindItems("/paymentDetail", tableItem);  counter = false;  } else {  f1 = Math.min.apply(Math, firstValue);  console.log("f1", f1);  console.log("firstValue", firstValue);  f2 = Math.max.apply(Math, secondValue);  console.log("f2", f2);  console.log("secondValue", secondValue);  ofilter = new sap.ui.model.Filter("duePeriod",  sap.ui.model.FilterOperator.BT, f1, f2);  var oTable = sap.ui.getCore().byId("table");  oTable.getBinding("items").filter(ofilter);  }  }
}

Including util.js files on index.html page.

 

 

<!DOCTYPE HTML><html>  <head>  <meta http-equiv="X-UA-Compatible" content="IE=edge">  <meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>  <link rel="stylesheet" type="text/css" href="util/style.css">  <script src="util/util.js"></script>  <!-- Utility file -->  <script src="resources/sap-ui-core.js"  id="sap-ui-bootstrap"  data-sap-ui-libs="sap.m,sap.viz,sap.ui.commons"  data-sap-ui-theme="sap_bluecrystal">  </script>  <!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->  <script>  sap.ui.localResources("piewithtokenizer");  var app = new sap.m.App({initialPage:"idmain1"});  var page = sap.ui.view({id:"idmain1", viewName:"piewithtokenizer.main", type:sap.ui.core.mvc.ViewType.JS});  app.addPage(page);  app.placeAt("content");  </script>  </head>  <body class="sapUiBody" role="application">  <div id="content"></div>  </body></html>

 

Hope!! It may help someone!!!

 

Any improvements and suggestions are welcomed.

 

Cheers!!!

Use of Fragments in SAPUI5 (Reusability)

$
0
0

Many times we need to show a pop up screens (Dialogs, Message Boxes etc.) to userat runtime. So in this case creating a complete view and its controller is not desirable. Hence Fragment comes into the picture.

     

Fragments are light-weight UI parts (UI sub-trees) which can be re-used, defined similar to Views (in XML, HTML, JS), but do not have any controller or other behavior code involved. In case code is required and for event handler methods they should be able to connect to existing controllers of the "owning" View.

 

So In case where someone require a set of controls to be reused in each of the view, we can utilize the capacity of fragment. We can create a fragment & can reuse everywhere we want.

 

For example - if we want to reuse the Product information (Below screenshot) in each of the view so in that case we can create a fragment for product information.

 

First view –

Screen1.PNG


Second view –


Screen2.PNG


Below is the step by step process to create & reuse the fragment in any SAPUI5 Project.

 

  • Create a SAPUI5 Project.
  • Create a Folder named “xml_frag” under webcontent

    

     Screen3.PNG


 

Creating a fragment –

 

  • create a file under that folder with extension “fragment name”.fragment.xml
  • Write the code in fragment file according to the requirement in my case I created the controls for product information.


  1. Button.fragment.xml

Screen4.PNG

  • Create an xml view & write the below code in init method of Controller of the view to load the fragment created.

          Loading a fragment & registering the fragment with action.

          //import xml fragment for display

 

var frg = sap.ui.xmlfragment("xml_frag.button",sap.ui.controller("fragment.fragment"));

frg.placeAt("content");

 

   In the same way in other views you can load the fragment & can pass the controller of current view & can load the fragment.  

   Define the fragment action in corresponding view with which fragment has been registered.

   Fragments are like static controls & can be easily implemented & high reusability with actions.You can also find the detailed documentation of fragment at        below – 

   (https://sapui5.netweaver.ondemand.com/sdk/#docs/guide/Fragments.html).

Using Google spreadsheet as the data model - SheetAsModel, the reusable module

Barcode Scanner in SAPUI5 without Cordova

$
0
0

Hello ,

 

Recently, Many of our customers are asking about barcode scanning feature within SAPUI5, but the application should be a browser based. No Native feature or platform dependency. I came across one of the HTML5 based API's which serves similar purpose without any need of Cordova Integration. On Desktop , it gives you an option to choose an image which contains Barcode and on mobile device , you can either choose an image from gallery or Take a picture. Basically this API is dependent on HTML Media Tag. I have attached some screenshots with this blog. I hope this will help you to achieve this really IMP functionality in your UI5 App.

 

Sample Project is available on GITHUB : " MaheshZ87/BarCodeScanner · GitHub"

 

Apologies for Layout probs as its just a demo project I had created giving more importance to actual functionality

 

Please provide your suggestions to improve this API further.

 

Happy Coding

 

Thanks ,

Mahesh.

 

Note : This has been tested with following devices :

 

 

Mobile Handset

OS Version

Output

Red Mi 1S

Anrdoid  JellyBean

For Sample images from photo gallery of mobile, it worked fine.

Motorolla G2

Anrdoid Lollypop - 5.0.2

For Sample images from photo gallery of mobile, it worked fine. When I tried camera option, it stared camera however I was not able to take picture. Hence I tried it other way round. I took a picture of a barcode and used choose file option form gallery where the picture was stored. It gave me the correct barcode of the image.

Xiomi Note 4G

Anrdoid KitKat

For Sample images from photo gallery of mobile, it worked fine. When I tried camera option, it stared camera with video option. I tried my luck again with previous approach. I took a picture of a barcode and used choose file option form gallery where the picture was stored. It gave me error for the first time and then I again tried it by keeping the picture as stable and clear as possible. In my third attempt, It gave me the correct barcode of the image.

Samsung Galaxy S2

Android Platform 2.3 ( GingerBread )

App started running however when I click on choose file option, it directly opened camera by giving some error message for flash. I took the picture however it’s not giving me an option to choose file from gallery.

iPhone 6

iOs 8.1

Its working for all possible options. I can take a picture from app itself and it will be used for scanning. Most of the times, It gave me the correct barcode in the first attempt itself. For some sample images which are not clear or barcodes which were not that clear, it gave me the error but rarely.

Sony Xperia C3

Android 4.2.2 Jelly Bean

  1. For Sample images from photo gallery of mobile, it worked fine. With camera option, I took the picture and it gave me correct barcode(For a Fanta Bottle J).Then I took a picture of a barcode and used choose file option form gallery where the picture was stored. It gave me the correct barcode of the image again. So worked well with this as well.

 

 

My Observations :  This API works well with clear images and proper barcodes. With Latest Smartphones , it works well however compatibility with older devices is still an issue .

Is there still a future in development?

$
0
0

Disclaimer: I'm going on an uncontrolled rant here. Close this page while you still can.

I'll be talking about my geographical region: Western Europe, where taxes are triple of what ends up on our bank account.

Reading advice: imagine me on a stage, wildly gesticulating while reading this.

 

I'm a software engineer, always have been, always will be.

 

 

Actually, no. Scratch that last bit. I'm not sure if I'll be able to remain a software engineer.

I'm seriously debating my career path as a software engineer.

I'm even doubting the future of software engineering in general for my geographical region.

 

Why? What happened?

 

Let's first look a bit at the past.

Geographically, my region is supposed to be a knowledge economy. It used to be a manufacturing economy, but because our taxes are so high, the wages, and costs became too high. the result is that nearly all manufacturing was moved to low-cost countries. *bummer*

That means a lot of people became unemployed, and do not have the necessary education to move into other roles.

 

So our government decided to put an emphasis on the knowledge economy.

People were encouraged to choose fields of study that would become more important in the future: Research, Development, Management, analytics,...

So we started training kids to learn how to code (CoderDojo's), we've introduced re-education programs and we're promoting IT to everyone!

Sounds like a good plan, right?

Except that these area's don't actually require a physical presence, because the result is virtual.

 

It can be done at the other side of the world just as well. That movement started already over 15 years ago.

Large corporations began moving their software engineering to low cost countries. Back in the days, this didn't work particularly well, because the offshored workforce was too decoupled from the business. To put it bluntly: "They knew how to write code, not how to create software".

*Notice how I speak in the past tense here.

 

Many corporations came back from that venture and said: "Never again!".

 

Things changed

Knowledge levels in those "low-cost-countries" have risen dramatically. We used to be able to mock about a bit, but let's face it: those guys are now skilled, have a reasonable understanding of the business they are working with, and they are much cheaper!

The only advantage that us, locals, still have, is a better understanding of the culture and the customer's IT landscape as a whole.

 

Cost is the trigger

This is were we bump into the age old misery of IT. IT is considered a cost, not an investment. 30 years since thought-leaders have been saying that IT is not a cost, but a competitive advantage, the corporate world has still not seen the light.

IT investments are still decided upon by procurement departments and the contract still goes to the cheapest, not the best.

 

You know those quotes flooding the internet about software and quality?

I can guarantee that 9 out of 10 companies will pick cheap and fast.

 

or this one:

The bitterness of poor quality remains long after the sweetness of low price is forgotten

Sure, but the person deciding on the cheap offer got his bonus and is long gone by the time the project goes down the drain...

 

You know I'm right!

You might, naively, believe that eventually, quality will prevail and you'll be paid top notch for fixing the mess left behind due to bad decisions. But deep down, you know that won't happen.

 

Actually, I'd even debate whether quality coming from low-cost countries is bad. It might have been 15 years ago, but surely, not today anymore?

 

Killing off our own chances

As software engineers, we have to stay ahead of the game to remain relevant. That's how we can keep our competitive edge and still earn money. So let's introduce a "new" technology which fits closer to the knowledge and skills of today's youth.

*peut* issue! How can we improve adoption of this new technology? Customers perceive any new technology as expensive and difficult.

 

Here's an idea: Let's make it easier with the right tools, and explain to customers that graduates know this technology already, and can implement it at a much lower cost.

 

What were we thinking?! Now customers actually expect us to implement whatever new technology, at a third of the cost, because we should be using students.

 

So I threw this on twitter, and it made my feed explode.

tweet - future of dev.png

Great news for the graduates. Not so great news for software engineers with 10+ years experience, because they're all of the sudden too expensive.

And actually, while I'm at it, it's not great news for our graduates either, because it's great news for graduates in low cost countries.

 

That's the thing with software. It's virtual. You press a button and it's shipped around the world in an instant, at no cost. It's not like a prefab house that you have to move with a boat and put together on-site. (wonky comparison...)

 

So how do we go about?

I'm running the risk here of being a cynic, but I have actually put some serious thought into this.

As a pure developer, our chances are slim. we'll experience an increasing competition in our local market from all the youngsters graduating IT studies, with heaploads of talent. At the same time, our overall region will be facing a though competition from low-cost countries that are becoming increasingly good at what they do.

 

So how can we still make the difference?

 

Well, for starters, we still make great IT Architects. We have a broad knowledge of both technology, functionality, business and economics. so we can put two and two together and move into a much higher view, guiding the overall IT strategy of companies.

But ask yourself: how do you become a great IT architect?

By having tons of experience as a software engineer/analyst.

So in another 10 years, the low-cost countries will have great Architects as well.

 

In other words, I can squeeze in another 10 years as an architect, and then I'll need a plan C.

 

What else?

 

Well, in the current market, customers don't actually like having long running development projects. they prefer to have an off-the-shelf semi-finished product which they can adapt to their needs. So the smart entrepreneurial Software engineer may create his own products and resell those to customers. The cloud based model (HCP for example) makes this a lot easier.

That means, becoming an entrepreneur, rather than just a developer.

But again, competition is stiffling, because 6 months after you release something, someone else will come up with something similar, which is slightly better and slightly cheaper. (App economy) So you have to keep on releasing.

 

Future of development

So I'm not saying development has no future whatsoever, but it'll be very different from what we know today.

A freelance developer will have a hard time making a living, no matter how talented he is.

Succesfull developers will have to be more, than just developers. They'll have to be architects or entrepreneurs. And that is no easy task.


Creating Offline Mobile Apps using SAP Web IDE

$
0
0

Did you notice SAP UI5 Master Detail Kapsel Offline Application template while creating a new project in SAP Web IDE? It is a new feature added in HAT 1.4. This template allows you to quickly create a Kapsel based offline mobile app. In this blog you would find how to create an offline mobile app (CRUD) using this template.

Prerequisites

  1. SAP Web IDE
  2. Hybrid App Toolkit
  3. HCPms

Configure App in HCPms

  • From HCPms admin cockpit click on Applications, then click on + button, and provide below details.

appoffline17.png

apoffline18.png

apoffline19.png

Note: The backend URL is dynamic, you need to create a URL with a session ID associated with it, that allows you to do CRUD operations. Click on this link to get your URL:http://services.odata.org/V2/(S(readwrite))/OData/OData.svc/

 

Create App in Web IDE

  • Open SAP Web IDE. Click on File> New> Project from Template.
  • Choose SAP UI5 Master Detail Kapsel Offline Application template. Then click Next.

webide1.png

  • Enter project name and clickNext.

offine7.png

  • Choose source as Service URL, then enter the following details and click Next.Note: Follow this blog to configure backend with Northwind Odata service.

offline8.png

  • Choose Products from the list of Odata collections. Hence Products collection will be available offline in the device. Click Next.

northwind1.png

  • Provide the details as given below and click on Finish.

webide5.png

webide6.png

  • Check the box Key Properties, then click on Finish. A new project will be created.

appofflinw15.png

  • Right click on the project and click Project Settings. Click on Device Configuration.

Appofflinw16.png

  • Provide below details and Click on Save.

*Choose mobile OS and plugins to be supported by the application.

*Choose Offline and Logon plugins.

*Provide your HCPms trial account details

webide8.png

Appoffline.png

webide10.png

  • Right click on the project > Run> Run on> iOS simulator. You are free to choose your mobile platform here. It will run the app in the simulator.
  • Once you login to the app you could find the list of products.

Note 1: Backend doesn't need credentials, hence you could pass any value to login to the app.

Note 2: A local database was created in the device (offline store), the data populated is from the offline store. It is possible to do Create, Read, Update and Delete operations without internet connectivity in the device. When the device comes online click on Refresh button, it will send all the local changes to the backend.

appoffline1.png

Create

  • From Home screen click on the + button to create a new record. After entering the values click on Save.

appoffline1.pngappoffline12.png

  • Now you could see that the data was successfully added in the offline store. But it is yet reflected to the backend. To update this record to the backend click on Refresh button. (In the background it's calling the Flush API, which is part of Offline plugin)
  • To see the new record in the backend, execute the Odata service in a web browser.

appoffline13.png

Update

  • Choose any product from the list, then click on Edit button. After editing the record click on Save. Then click on Refresh. The record was updated. You could find it in the mobile app as well as in the Odata service reponse.

appoffline2.pngappoffline4.png

appoffline7.pngappoffline6.png

Delete

  • To delete a record choose any product from the list then click on Delete button. Finally, from the Home screen click on Refresh.

appoffline8.png

This app works with SMP 3 too without any code change.

 

Regards, Midhun

SAP Technology RIG


Other spaces to follow:

SMP Developer Center

SAP for Mobile

Read and Write TXT File from Android, IOS

$
0
0

Hi All,

 

Introduction:

                    One of my project requirement is to generate json format file by giving input as a  txt file.

     For ex:

 

          Input File.txt:

                    -Raman - ECE

                    -Sita - CSE

                    -Hanuman-IT

                    -Ravanan-Mech

 

          Year Should be input Field

 

          OurPut.txt should be:

 

               {"Name": "Raman", "Dept" : "ECE", "Year" : "Final Year"},

               {"Name": "Sita", "Dept" : "CSE", "Year" : "Final Year"},

               {"Name": "Hanuman", "Dept" : "IT", "Year" : "Final Year"},

               {"Name": "Ravanan", "Dept" : "Mech", "Year" : "Final Year"}

 

Environment: Android, IOS


Solution:

         

Capture.JPG

       5. Use this code to read and write your file:

 

               View JS:

                         Capture.JPG

 

               Controller.JS:

                              Capture.JPG

                                   Capture.JPG

                                           

 

                                                  Capture.JPG

 

OutPut:

                                           Capture.JPG

 

For IOS Users: add platform as ios

 

 

Thanks,

Karthik A

                                      

 

 

 

                              

 

 



Something about negative cache error

$
0
0


I am testing my Fiori extension project created based on SAP standard Fiori application "My Opportunity" and I meet with error message "Error: found in negative cache: 'cus/crm/opportunityExt/Component.js' from /sap/bc/ui5_ui5/sap/extcrm_opp/Component.js: Error: found in negative cache: 'cus/crm/opportunity/Component.js' from /sap/bc/ui5_ui5/ui2/ushell/resources/cus/crm/opportunity/Component.js: 404 - NOT FOUND" when I click tile of my Extension project in Fiori launchpad:


clipboard1.png

clipboard2.png

Issue analysis

 

put mouse onto the hyperlink part of the topmost callstack, "at a1...", the mouse becomes a hand shape:

 

clipboard3.png

click it, and Chrome will bring us to the exact code where this error occurs. Click the bracket icon to format the code:

clipboard4.png

Now the reason of this "negative cache" is clear: there is a global array M which stores all currently loaded modules with their url and state. Since the module to be loaded when I click the tile of my extension project, "cus.crm.opportunity.Component.js", has error state ( 5 ), the corresponding error is raised.

clipboard5.png

Why this Component.js file is needed when I click the tile

 

from the callstack we can find the answer:

 

1. ui controller has a method openApp, which will call render method.

clipboard6.png

2. render method will further delegate the call to load component via sap.ui.component.load:

clipboard7.png

What is negative cache

 

Let me copy the definition from wikipedia:

 

In computer programming, negative cache is a cache that also stores "negative" responses, i.e. failures. This means that a program remembers the result indicating a failure even after the cause has been corrected. Usually negative cache is a design choice, but it can also be a software bug.

 

 

I am glad today I know a new terminology

SAPUI5 Maintenance strategy update - still in process but a heads up

$
0
0

Hi all,

 

because of feedback from customer projects and via OSS tickets, I'd like to share the information that SAP is currently working on an update of the SAPUI5 maintenance strategy. The plan is still subject to be changed, but there is already a clear direction that it is important for you to plan the go live releases.

 

Basically the idea is that there will be dedicated UI5 versions that have a maintenance period from up to 2 years and thus are the recommended go-to releases for stable productive usage of the Fiori / UI5 applications. SAP will provide UI5 corrections via note or via SPs that contain only bug fixes which reduces the risk of regressions.

 

So why I'm writing a heads-up before the official roll-out:

 

The latest UI5 version 1.28 that is available via the NW UI add-on V1.0 SP12, HCP and soon via NW UI add-on V1.0 SP13 is already such a stable version. In case you have go-live date close by and are targeting a stable stack, please decide for SAPUI5 1.28 and directly avoid older releases that are no longer supported.

 

Usually, SP13 would have contained UI5 version 1.30 instead of a higher 1.28 patch level, so you already will see the difference in July. To avoid questions: there also will be a UI5 V1.30 with the latest innovations that is currently planned for 09/2015 (not yet a final date). 

 

More information and also final confirmation yet to come (e.g. how long the stable period will be, what is the next stable version etc.), but please use already the additional opportunity that SAPUI5 is offering with 1.28.

 

So short version from this blog post: 1.28 for sure is a much better choice compared to 1.24 or 1.26   

 

Best regards

Stefan

Integrating Google GeoChart in SAPUI5 App

$
0
0


Gooogle.com provides a lot of API's for integration to websites and there are also a lot of apps provided by it.

 

Among them one is GeoCharts.

 

A geochart is a map of a country, a continent, or a region with areas identified in one of three ways:


  • The region mode colors whole regions, such as countries, provinces, or states.

geo1.PNG

  • The markers mode uses circles to designate regions that are scaled according to a value that you specify.

geo2.PNG

  • The text mode labels the regions with identifiers (e.g., "Russia" or "Asia").

geo3.PNG

A geochart is rendered within the browser using SVG or VML.

Note that the geochart is not scrollable or draggable, and it's a line drawing rather than a terrain map; if you want any of that, consider a map visualization instead.

 

For more details you can follow this official link :- https://developers.google.com/chart/interactive/docs/gallery/geochart .

 

Many times we need to display our data in geographical location format and google provides the best API for it.

Here we are going to display Region GeoCharts.

 

First as usual we have to create an SAPUI5 Application.


              <metahttp-equiv="X-UA-Compatible"content="IE=edge">

              <metahttp-equiv='Content-Type'content='text/html;charset=UTF-8'/>

            

 

              <scriptsrc="resources/sap-ui-core.js"

                           id="sap-ui-bootstrap"

                           data-sap-ui-libs="sap.ui.commons"

                           data-sap-ui-theme="sap_bluecrystal">

              </script>

              <!-- add sap.ui.table,sap.ui.ux3 and/or other libraries to 'data-sap-ui-libs' if required -->


First as usual we have to create an SAPUI5 Application.After this we have to load the Google GeoChart library.

For doing so write this line in another script tag.


<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['geochart']}]}"></script>


After this we will write our code for displaying geochart.


              <script>

              function drawMap() {

                  var data = google.visualization.arrayToDataTable([

                      ['Country', 'Projects'],

                      ['Russia', 3],

                      ['France', 2],

                      ['Spain', 4]

                  ]);

                

                  var options = {

                      dataMode: 'regions',

                      width: 834,                                        // Set Width

                      height: 521                                        // Set Height

                  };

                

                  var container = document.getElementById('map_canvas');

                  var chart = new google.visualization.GeoChart(container);

                

                  function myClick(){                                                            // Click Handler event

                      var selection = chart.getSelection();

                      var message = '';

                      for (var i = 0; i < selection.length; i++) {

                          var item = selection[i];

                          if (item.row != null&& item.column != null) {

                              message += '{row:' + item.row + ',column:' + item.column + '}';

                          } elseif (item.row != null) {

                              message += '{row:' + item.row + '}';

                          } elseif (item.column != null) {

                              message += '{column:' + item.column + '}';

                          }

                      }

                      if (message == '') {

                          message = 'nothing';

                      }

                      alert('You selected ' + message);

                  }

                

google.visualization.events.addListener(chart, 'select', myClick);                         // Listener has been created for select event of any region.

                

                  chart.draw(data, options);

              }

              google.load('visualization', '1', {packages: ['geochart'], callback: drawMap});         

              </script>


Here we have a <div> in our body where our geochart has been placed.


       <bodyclass="sapUiBody"role="application">

              <divid="map_canvas"></div>

       </body>


I don't remember the link from where i got some help but i want to thanks the contributor.

These are some SDN Queries.

Issue while trying to display Google geochart in SAPUI5 app 

How to access and work with SAPUI5 controls from a google chart's event handler method.


I hope you all will like it.

I will keep updating this blog very frequently with different google API's.



Thanks.

 


When to not use sap.m.DatePicker: How to cleanly pick a month instead of a date

$
0
0

Hello fellow SAPUI5 learners and experts,

 

A quick tip regarding input fields and dates. I was trying to have an input field that allows a user to select a date as a month.

 

I used a sap.m.DatePicker with the displayFormat as below, to select a month period.

 

0001.png

 

This worked well enough; the DatePicker field showed the date as expected and is treated as I wanted.

0002.png

However I still had to click down to the day in the picker view:

 

0003.png

For example, I still had to click all the way through to 16th (or whatever) April 2015 to select April 2015. One extra click felt inelegant, how could I avoid it?

 

It turns out that using sap.m.DateTimeInput was the more correct choice in this instance!

0001b.PNG

leads to:

0004.png

 

The date picked will implicitly always be the 1st day of the  chosen month.

 

No doubt not much of an observation to our UI5 veterans, but a learning item for me!

A Complete beginner's guide for SAPUI5

$
0
0

I have seen in this forum that whenever a beginner's start his journey for SAPUI5, they face a lot of basic problems. Sometimes it's hard to search for the exact thing they want and they ask queries for simple issues. In this blog i am trying to give a dictionary to beginner's from where they may start properly. This is not full documentation but have tried to cover the basic things. You can suggest other blogs also and we will add it here. Here i have used different blogs of SCN only.

"Let's try to build best SAPUI5 forum"


A Complete beginner’s guide for SAPUI5

 

INSTALLATION

 

  1. http://scn.sap.com/community/developer-center/front-end/blog/2013/01/31/getting-started-with-sapui5-alternative-guide by http://scn.sap.com/people/dj.adams
  2. http://scn.sap.com/community/developer-center/front-end/blog/2013/05/22/what-sapui5-and-fiori-tells-us-about-the-future-of-ui-development-for-abapers by http://scn.sap.com/people/john.moy3
  3. http://scn.sap.com/community/developer-center/front-end/blog/2013/06/01/how-to-install-a-basic-development-environment-for-sapui5 by http://scn.sap.com/people/michaelherzog
  4. http://scn.sap.com/community/developer-center/front-end/blog/2013/07/23/installing-and-sap-ui5-toolkit-ver-1121-in-eclipse-43-kepler by http://scn.sap.com/people/tarun.telang2
  5. http://scn.sap.com/community/developer-center/front-end/blog/2015/04/22/step-by-step-video-tutorials-for-installing-sapui5-tools-in-eclipse by http://scn.sap.com/people/dhananjay.choubey

 

FIRST APPLICATION

 

  1. https://sapui5.hana.ondemand.com/sdk/#docs/guide/5b9a170d9f6a4d5784e8ab2ded3d8517.html
  2. https://sapui5.hana.ondemand.com/sdk/#docs/guide/592f36fd077b45349a67dcb3efb46ab1.html
  3. https://sapui5.hana.ondemand.com/sdk/#docs/guide/510d6eeed849447fbf497cfa5b640514.html
  4. https://sapui5.hana.ondemand.com/sdk/#docs/guide/5ca68e6e62e6464a8103297fbc19cd9c.html
  5. https://sapui5.hana.ondemand.com/sdk/#docs/guide/57da09a600a74315ba1e27687bacad17.html
  6. https://www.youtube.com/watch?v=bkWlMPLsGvw&list=PL2-hZl5UoWIiC97-mqtjxpT12ZTBMb6jd&index=2

 

Customizing your application

 

  1. http://scn.sap.com/docs/DOC-63732 by http://scn.sap.com/people/dhananjay.choubey

 

Data Binding

 

  1. http://scn.sap.com/community/developer-center/front-end/blog/2013/05/31/how-to-create-sapui5-application-consuming-gateway-service-with-the-help-of-sap-nw-gateway-plugin by http://scn.sap.com/people/chandrashekhar.mahajan
  2. http://scn.sap.com/community/developer-center/front-end/blog/2013/02/22/playing-with-the-model-on-sap-ui5 by http://scn.sap.com/people/joseph.berthe
  3. http://scn.sap.com/community/developer-center/front-end/blog/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service--part-1 by http://scn.sap.com/people/christian.jianelli
  4. http://scn.sap.com/community/developer-center/front-end/blog/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service--part-2 by http://scn.sap.com/people/christian.jianelli
  5. http://scn.sap.com/community/developer-center/front-end/blog/2012/12/07/building-a-crud-application-with-sapui5-and-icf-restjson-service--part-3 by http://scn.sap.com/people/christian.jianelli
  6. http://scn.sap.com/community/developer-center/front-end/blog/2013/04/18/are-you-getting-no-data-in-your-sapui5-table by http://scn.sap.com/people/skemp
  7. http://scn.sap.com/community/developer-center/front-end/blog/2012/10/15/consume-netweaver-gateway-services-via-sapui5 by http://scn.sap.com/people/ivan.femia
  8. http://scn.sap.com/community/developer-center/front-end/blog/2012/10/15/consume-netweaver-gateway-services-via-sapui5--part-2 by http://scn.sap.com/people/ivan.femia
  9. http://scn.sap.com/community/developer-center/front-end/blog/2012/10/15/consume-netweaver-gateway-services-via-sapui5--part-3 by http://scn.sap.com/people/ivan.femia
  10. http://scn.sap.com/community/developer-center/front-end/blog/2012/09/06/how-to-consume-sales-oder-gateway-using-odatamodel-and-displaying-using-sap-ui5-views by http://scn.sap.com/people/sunil.e.sharma

 

Miscellaneous

 

  1. http://scn.sap.com/community/developer-center/front-end/blog/2013/06/29/solving-same-origin-policy-issue-in-different-ways by http://scn.sap.com/people/michaelherzog
  2. http://scn.sap.com/community/developer-center/front-end/blog/2013/06/14/useful-jquery-functions-for-sapui5-development by http://scn.sap.com/people/michaelherzog
  3. http://scn.sap.com/community/developer-center/front-end/blog/2013/05/17/essential-tools-for-developers by http://scn.sap.com/people/brenton.ocallaghan
  4. http://scn.sap.com/community/developer-center/front-end/blog/2014/02/03/display-smartform-pdf-in-sapui5 by http://scn.sap.com/people/chandrashekhar.mahajan

 

Thanks.


App Update: Deploy a hybrid application to SAP HANA Cloud Platform mobile services (HCPms) for Updates

$
0
0

Introduction

SAP Web IDE is an Integrated Development Environment for SAPUI5 and Fiori applications.

In this blog we shall see how to use Kapsel plugin App Update for a SAP UI5 mobile app. (along with Kapsel plugin Logon Manager)

(Note: This feature is not available for Web IDE local installation. Users should log on to a Web IDE application at HANA Cloud Platform.)

Objective

In this blog we shall see how to deploy an app to SAP HCPms with latest updates of the App.

The below steps show how to deploy a SAP UI5 mobile app along with latest updates first to HCPms and then onto a device on which it is installed. For this we will use Kapsel Plugin AppUpdate in SAP Web IDE.

We will follow the below steps,

  • Create an app on HCPms
  • Create SAPUI5 App in SAP Web IDE
  • Setup Device Configuration
    • Enable Kapsel plugin App Update and enter HCPms details
  • Deploy and Run the app on an Android Device via local HAT (just for making it look like an existing app on device)
  • Now, Update the app with necessary changes in SAP Web IDE
    • Add a test button onto the search bar as an update to the existing app
  • Deploy app to HCPms
  • Check for updates of the app on the device


The updates for the app is seen as soon as we start the existing app and will look like this
26Relaunch.png

Prerequisites

  • SAP Web IDE 1.11 and later (you can register at SAP HANA Cloud Platform to get your development environment)
  • Hybrid Application Toolkit 1.4.2 downloadable from here
  • An HCPms account configurable as described here
  • Valid User for ES1. Procedure to get access information is described here
  • An Android device which is recognizable using your PC. To connect an Android device to the PC to test your applications you need to install the appropriate USB driver. Follow the link for steps.
  • Please also ensure: (For these preparation steps please check at the end of this blog. For further info, You can also refer to the help document here )
    • Destination is setup (to ES1),
    • HAT Connector is started,
    • HAT Plugin is enabled in SAP Web IDE,
    • Kapsel SDK cli is installed


Steps

1. Create an application on HCPms

 

Logon to https://hcpmsadmin-<your_user>trial.dispatcher.hanatrial.ondemand.com where you need to replace the string "<your_user>" with your user account

Click on Applications Tile

0LogonToMobileServicesCockpit.png

At the bottom press button Add (with plus symbol), to create a new Application

0_1LogonToMobileServicesCockpit.png

Enter the following values:

Application ID

com.test.prods

Version

1.0 (default)

Name

Products

Type

Hybrid

Description

Products

Vendor

SAP

 

0_2LogonToMobileServicesCockpit.png

Save the settings

 

Select tab Backend and enter the following:

Backend URL

http://sapes1.sapdevcenter.com:8080/sap/opu/odata/sap/ZGWSAMPLE_SRV/

Authentication Type

No Authentication

Proxy Type

Internet

 

Leave the rest of the default values as is.

 

0_3LogonToMobileServicesCockpit.png

Ping the Connection to verify a successful Ping Result

 

2.      Create SAPUI5 App


Create an SAPUI5 Master Detail App, for Products consuming services from ES1

In SAP Web IDE, go to File --> New --> Project from Template

3ProjectFromTemplate.png

Select SAPUI5 Master Detail Kapsel Application. Press Next3TemplateSelection.png

Enter a valid Project Name: Example ProductsAppUpdate,Press Next4BasicInfoTemplate.png

In the Data Connection, chose es1 from the dropdown of Service Catalog.

If asked for authentication provide UserID/Pwd for es1            5_0DataConnection.png

Search for service ZGWSAMPLE_SRV. Select it and Press Next

          

Enter the following into the fields:

Project Namespace: Products

Master Section

Title: Products

Odata Collection: ProductCollection

Search Field: ProductId

Main Data Fields

                Item Title: ProductId

                Numeric Attribute: Price

                Units Attribute: Currency Code

Detail Section

                Title: Products

                Additional Attribute1: Description

                Additional Attribute2: Category

Information Section

                OData Navigations: Supplier

                Navigation Attribute1: CompanyName

                Navigation Attribute2: PhoneNumber

                NavigationAttribute3: EmailAddress


6TemplateCustomizzation.png 

7TemplateCustomization.png

8TemplateCustomization.png

Press Next

 

Press Finish

 

Optionally, Test the app as Web app. In SAP Web IDE open the newly created project ProductsAppUpdate. Right click on the index.html. Run --> Run as --> Web Application

10RunAppInWeb.png

3.      Device Configuration

 

In SAP Web IDE, Right click on Project ProductsAppUpdate. Go to the Project Settings

11_1DeviceConfiguration.png

Go to Device Configuration and enter the following:

App Name

Products

App ID

com.test.prods (this should match the Id given in HCPms for Application)

Description

Products

Version

1.0.0

Platforms

Android

 

11DeviceConfiguration.png

From Plugins, selectKapsel Plugin Logon Manager and App Update

Enter the HCPms host : hcpms-<you_user>trial.hanatrial.ondemand.com

11DeviceConfiguration2.png

Save the Settings

 

4. Deploy and Run on Device

 

Right click on the Project ProductsAppUpdate. Deploy -->Deploy to Local HAT

12DeployToLocalHat.png

On a successful deployment a success message appears

13SuccessfulDeplo.png

Right click on the index.html. Run -->Run on Android Device. Ensure the device is connected

On the Android device, a screen appears to launch the app.

Enter the Logon info for ES1 and press Register

14_2Compressed.jpg

 

Disable Passcode and press Submit

 

14_03.png

 

The Main View with all the products should appear

 

14_4.png

 

5. Update the app with necessary changes in SAP WebIDE


Go back to SAP Web IDE. Go to folder ProductsAppUpdate. Open view Master.view.xml. Add the following code to add a button on the search bar. Immediately after the <contentMiddle> of the searchbar


<contentRight>

     <Button id="btnTest" icon="sap-icon://customer" tooltip="TestButton"></Button>

</contentRight>

 

Save the content

 

15ContentChange.png

Optionally, Run the index.html as a Web app to test the added button

16RunAsWebApp.png


6. Deploy app to HCPms


In order to get the updates to the device on which the app is already installed, follow the steps below


Open Web IDE Console View via Menu View --> Console,to check errors if any.

17_0OpenConsole.png

Right click the project ProductsAppUpdate and select Deploy -> Deploy to HCP Mobile Services menu

17DeployToHCPms.png


If authentication popup appears, enter the Hana Cloud Platform mobile services(HCPms) login info. Press LogIn

18AuthenticationRequired.png

Click the Next button on the pop-up.

19DeployToHCPms.png

The project will be sent to local HAT for packaging. You can see the progress in the Console View.

Once the packaging succeeds, on the popup that appears click the Browse... button, navigate to the suggested folder and select the packagedKapselApp.zip file

20PackagedKapselApp.png

Press button Deploy

21Deploy.png

The upload progress and result will be shown in the pop-up. In case of an error, follow the given hint to correct the error

22Deployed.png

Click the Close button

Logon to Hana Cloud Platform mobile services(HCPms). Go to the application com.test.prods and press button Configure

23Configure.png

Navigate to tab App Specific Settings. The most recent deployment should be seen. Select it and press the Deploy button

24SelectAndroidVersionDeploy.png


7. Check for updates for the app on the Device

Logon to the device on which the app is installed. Open the app.

25GoToAppOnDevicec.png

A New Update available message pops up. Press Relaunch Now to get the latest updates on the device.

 

26Relaunch.png

You should now be able to see the newly added button

27UpdateAvailable.png

 

That’s it for today!


====================================================================================

====================================================================================

====================================================================================


Preparation Steps:


1.      Setup Destination

Login to your hanatrial account and set up destination configuration for ES1 (to consume services).

 

In a browser login to https://account.hanatrial.ondemand.com/ --> Cockpit

Go to Destinations --> New Destination…

Enter the following Destination Configuration parameters:

Name        

es1

Description

es1

Type

HTTP

URL

http://sapes1.sapdevcenter.com:8080

ProxyType

Internet

CloudConnectorVersion

2

Authentication

NoAuthentication

 

And Additional Properties:

WebIDEUsage

odata_abap

WebIDEEnabled

true

WebIDESystem

es1

 

 

Save the configuration settings

 

2.      Start the HAT Connector

To allow Web IDE to interact with Hybrid App Toolkit add-on components on your local machine over HTTPS, start Hybrid App Toolkit Connector.

 

From the SAP_HAT_local-<version> folder: On Windows, double-click run.cmd, or type this command in a command window. On Macintosh, in a terminal window, first run chmod +x *.sh and then ./run.sh.

At the prompt, enter the keystore password. This password is the same one entered during the HAT setup procedure. The Hybrid App Toolkit Connector starts and listens for requests from Web IDE.

 

3.      Enable HAT Plugin in SAP Web IDE and Verify

Login to SAP Web IDE. Ensure that Hybrid App Toolkit is enabled. Test and verify that the connection is up. 

 

In a browser login to https://webide-<your_user>trial.dispatcher.hanatrial.ondemand.com/ where you need to replace the string "<your_user>" with your user account

  1. Go to Tools --> Preferences

 

 

  1. Select Plugins --> Optional Plugins. Select Hybrid App Toolkit.

 

 

Next select Hybrid Application Toolkit from the left Pane. Press button Test Connection. Ensure that Connection is up

 

4.      Install Kapsel SDK cli

Windows Installation
To install the CLI, open a terminal window and navigate to the Kapsel CLI folder. On Windows, the SDK installer installs the SDK by default in c:\SAP\MobileSDK3\, so the Kapsel CLI can be found in c:\SAP\MobileSDK3\KapselSDK\cli. With a terminal window open to the cli folder, issue the following command:

npm -g install

Macintosh OS X Installation
To install the CLI, open a terminal window and navigate to the Kapsel CLI folder. On OS X, the SDK installer installs the SDK by default in /users/user_name/SAP/MobileSDK3/ (replacing user_name with the login name for the user performing the installation), so the Kapsel CLI can usually be found in /users/user_name/SAP/MobileSDK3/KapselSDK\cli. With a terminal window open to the cli folder, issue the following command:

sudo npm -g install

"Designed with Love" - VNSG UEX meeting about SAPUI5

$
0
0

The Dutch user group focusing on User Experience had another really good meeting today, this time fully focused on UI5.

 

Robert Eijpe from NL4B started the event with his presentation. As an SAP Mentor, he worked few weeks in Walldorf on UI5 training material, so he could not only introduce the technology, but also give us insights into future developments directly from Walldorf. He started off with explaining the evolution of UI technologies at SAP and he focused on a huge paradigm shift: modern UI should be “designed for you, your needs, and how you work”. He covered the basics of OData, how it can provide uniform data access consuming JAVA, ABAP, XS(2) and even .NET applications.

 

robert.jpg

 

He explained the difference between Fiori and Fiori-like applications, where Fiori-like apps cannot run in the Fiori Launchpad in the same window using the FLP navigation.

 

His presentation was an overall journey in the “land of UI5”, he talked about Fiori Launchpad, S/4HANA, Fiori apps reference library, WebIDE and Fiori cloud edition. The 10 golden rules for Fiori development was a slide where many people took out their phone and started to take photos. I did too

 

golden.jpg

 

Thanks to Jan Penninkhof, another Dutch SAP Mentor, we had a very special guest speaker: Kai Richter, Vice President - Global Design Concepts at SAP. Jan met him at DKOM Walldorf, followed up and thanks to Jan, we got a very interesting presentation about Fiori 2.0.

 

kai.jpg

 

Kai talked about the Fiori guidelines and the central role of Design Thinking at SAP. I noticed that when he talked about a great example application, he mentioned that it was “designed with love”. I find this a very remarkable statement!

 

love.png

 

Kai explained how Design Thinking becomes a driver for software development and DT workshops are enjoyable and fun for the participants.

 

He gave us insights into what SAP is busy with regarding Fiori 2.0. Personalized home page, extendable notifications view (also for mobile devices), tabs for navigation, Me Area, improved tiles, hierarchical navigation, app finder, quite an impressive list of new features. Fiori will look even more awesome in the future.

 

After Kai I got the chance to present my UI5 implementation at Suiker Unie. This project was very interesting, because we used UI5 100%, but not for Fiori-like development. The application was designed by a design agency and we worked closely with an interaction designer. The result is visually very attractive. I shared my project experience from design, implementation, project management and testing aspects. I explained how a design created by people who have never seen SAP can be implemented pixel perfectly with SAPUI5. The implemented UI5 application is responsive. We have tested it for many browsers and all kinds of devices. The combination of Design Thinking approach and Agile project methodology helped us to reach great user experience and high customer satisfaction.

 

tamas.jpg

 

At this point in the agenda we had some “internal affairs”: Marcel Rabe resigned from his chairman position (I took over) and we welcomed Henny Claessens as the new secretary. Henny is a very well-known and respected member of the Dutch SAP community, so we can look forward to his activity.

 

Roelof Kuipers from SAP NL gave a very interesting presentation about using UI5 on HANA, actually on HCP. He introduced HCP and gave a live demo of using WebIDE, the HCP cockpit, etc. He presented a very interesting use case, where he, together with his colleagues developed an app on HCP for SAP employees driving electric cars. SAP NL has 20 charging stations, but 100+ e-Drivers. The app helps the drivers utilize the charging stations to the max by notifying when one is available, reserving places and showing usage statistics, etc. They are even thinking to extend it with predictive analysis. Roelof explained how such a useful app could be built in a few days on HCP.

 

roelof.jpg

 

Last but not least, this meeting was special becasue of its location too. Many thanks for our sponsor, Perfect for People (part of the SOA People group) to arrange this beautiful location for us!

 

fort-jutphaas-vooraanzicht.jpg

loc2.jpg

loc1.jpg

Openui5 + Heroku + Mailgun + Google Spreadsheet + Dropbox = the whole package = a simple yet robust e-commerce solution

$
0
0

Greetings,

 

Ever since I encountered Openui5, this awesome front-end framework, I’ve been thinking, how could I introduce it to more people, how about an end to end real-life application? Not only showcase the goodies of the framework, but show people how easy it is to work with a back-end database, to deploy, and to add common features like sending emails, make it the whole package.

 

So here it is, the Openui5 demo app – shopping cart on steroids

 

Key features:

 

  • Powered by Openui5 / Ruby Sinatra. It’s built on top of the demo app, the only non-Openui5 / JavaScript code is the email sending part, which is written in Ruby.
  • Hosted by Heroku, which connects with my Github repo (automatic deploy).
  • Outgoing emails service is provided by Mailgun. Their free plan allows us to send out 400 mails each day.
  • Images hosted using Dropbox.
  • And the best is that it uses Google spreadsheet as the database (I had a reusable Openui5 module written for this task), which makes it super easy to manage the back-end data, and robust as hell.

 

I’ll go out and say this is the perfect e-commerce solution for mamas and papas stores, give me five ^__^

 

Actually I’m fairly new to programming, you could for sure sniff some code smells here and there, but it does not keep me from solving problem programmatically and contributing, cheers.

 

Check out the live demo, and all of my code:

 

Live demo

 

j1wu/openui5-app-shopping-cart · GitHub

j1wu/openui5-module-sheet-as-model · GitHub

Meet Keggy – the IoT kegerator powered by OpenUI5 and SAP HANA

$
0
0

In this blog (being my first one) I’m going to explain to you a UI5 application that receives and displays data from an IoT device we named Keggy – an Arduino with WiFi shield connected to a kegerator. Keggy also likes to tweet a lot – but more on this later.

 

 

Introduction

Reaching out to people at GlueCon is an important step towards bringing new technologies to the market such as HCP, OpenUI5 or even first approaches of IoT.

This year, SAP went to GlueCon with a very exciting use-case: a beer kegerator that communicates with a HANA instance to transfer data every time beer is poured, the door is opened or the temperature changes. In order to showcase that we actually get real time data from the kegerator, we implemented a web app with OpenUI5. We wanted it to be a monitor, optimized for mobile devices, as the web app would be running on tablets. That being said, what would be a better fitting framework than OpenUI5?

Let’s start with the design of our XML-Views for the beginning, but first of all have a view on this wonderful kegerator and the application which can be seen on the devices in the back (just to get a first impression):


p1.jpgp2.jpg

 

 

Concept

First of all, we want to depict what we are going to build. The Ardunio connected to the kegerator gives us information about:

 

    1. How much beer is poured at which point of time?
    2. When is the door being closed or opened?
    3. How much beer is left in the barrel?
    4. What is the temperature of the beer inside at which point of time?

 

With this data, we started building an UI that refreshes itself every three seconds and gives the user the opportunity to see what’s going on inside the barrel – everything being responsive enough and especially designed to run on a mobile device. So, what we want to do is create an XMLView that shows us information about the beer brand, type of beer, barrel size etc. in a bar at the top of the screen. It shall then provide the IoT kegerators data in different charts on the main area of the screen. The data is refreshed every third second. To save space, we are going to add another bar to the bottom of the screen to show the percentage of the capacity of our barrel and the date and time when the door has been opened/closed recently. We are going to use a lightweight and easy-to-use JS library called “Chart.js” which allows us to generate charts on the screen. Obviously, that saves a lot of time. Now that our goal is set, let’s get started!

 

 

XML-Views

We’ll build the UI with the Web-Development-Workbench of SAP HANA, but for a first approach Plunker (an easy-to-use online web development environment, http://plnkr.co/) will serve us great. Its ability to directly show the results of your programming on the right side of the screen (refreshing automatically) is perfect for fast UI development.

For our app we’ll only want one MasterView which displays all of the information. An XMLView will work just fine for that, as it enforces the separation between model, view and controller. In case you didn’t know: An XMLView works descriptively which means that there is no functional logic in it. This helps us implement the MVC concept in a cleaner way. The MasterView is placed on a JSView which only sets up the initial processes and adds the MasterView as its first and only page.

It’ll need a lot of CSS customization afterwards because of several features and containers which cannot be added as simple and flawless as UI5 claims it to be. The following pictures show you the final UI of the app. The first one is displaying the temperature over time, while the second is displaying the beer flow for specific points of time.

 

p3.png

 

p4.png

 

Now that the view is defined we can start adding components. The view needs a sap.m.Page to display the content of course. Because we want a lot of information being displayed in the top, the page’s aggregation “customHeader” will provide a customizable sap.m.Bar that we can insert. It needs an ID to edit its design properties afterwards in the CSS file “style.css” that is going to be referenced in the “index.html”. The bar will have a lot of content so it makes sense to distribute the information to the bar’s aggregations contentLeft, contentMiddle and contentRight. On the left side there’s going to be a sap.ui.layout.VerticalLayout (or after the namespace identifier in the view’s properties <l:VerticalLayout>) which contains the barrel-size and unit, the beer type, brewery location and brewery type. The content in the middle will only be a sap.m.Image which is filled with the icon of our beer brand being currently used. Because the text of our picture is quite small, we want to do some CSS customization to give it more space on the screen. This will make our sap.m.Bar bigger, therefore the picture better readable and it will align our objects right. The right side contains a RatingIndicator for the beer type and an indicator for which chart is currently active. All information is retrieved by the “LocalModel.json” which is bound to the view and contains all relevant information displayed on the screen like size, unit, brand, rating and the measures provided by the ODATA service. The model is initially loaded from the controller and allows us to communicate with the view without having to use a lot of variables. It is also bound to the respective UI components. The following picture shows an excerpt:

 

p5.png

 

The main area of the view contains a sap.m.Carousel which includes three pages. Those pages represent the different charts that can be displayed. Because of the size of one chart and the requirement to make it readable for the user on a mobile device you can swipe easily between the three screens. The carousel, unlike tabs e.g., is optimized for mobile devices and adds value to the UX. The following picture shows the way the carousel is described in our XMLView. Pure HTML code is integrated into the screen of the carousel. This allows us to use Chart.js without writing a new component.

p6.png

The view’s footer is another customized sap.m.Bar which contains information about the door being opened or closed recently (just sap.m.Labels and sap.m.Texts bound to the model) on the left, a sap.m.ProgressIndicator in the middle which shows the current percentage of beer left in the barrel and the current temperature of the beer in the right content.

 

 

Controller-Implementation

The MasterView’s controller implements all the logic of receiving, formatting and passing data from the ODATA service to the view.

It initially sets the JSONModel for our view to have an appropriate binding from the beginning on. After the model is defined and we declared some global variables in the onInit() function, the onAfterRendering() function is invoked. This one is going to call an anonymous function after an interval of 3s which permanently loads the most recent temperature, pours and other activities via the following functions (which use Chart.js http://www.chartjs.org/docs/#getting-started ):

 

loadPour():

This function loads the most recent pours with an AJAX call which then will update the complete consumption in the model as well as the beer left in the current barrel. Those changes regard the model only in the first place, but as the model’s data is changed the UI elements will also change after refreshing the model. That leads to the progressIndicator in our footer being updated e.g.

After the updates on the model are done, it is time to change the charts. Those are recreated every time new data is provided and filled with it. It’s a very descriptive procedure which I won’t elaborate right now. Let’s just say that you need to read the documentation of Chart.js carefully and find the properties of Chart.Line and Chart.Bar that are necessary.

 

loadTemperature():

This function loads the most recent temperature values with an AJAX call, updates the model to make sure the TextFields are labeled correctly and fills an array with temperature values and dates to then display them on another chart which is filled just as mentioned before.

 

loadActivities():

This function loads the most recent changes of the kegerator’s door whether it’s been opened or closed and applies the changes to the model (which then applies the changes to the UI). If there has been a change in the doors state the controller will fire a tweet via Twilio API

(https://www.twilio.com/) complaining about the heat or thanking for closing. This works as follows: Twilio API sends an SMS from within JavaScript. This message then gets forwarded to IFTTT (https://ifttt.com/) where a tweet is posted every time a message from Twilios number arrives. The principle “if this then that” is applied.

 

tweetPour():

         p7.png

Another little easter egg in our application would be an API that allows us to send POST requests to Twitter. Twilio combined with IFTTT provide us with such a functionality so that we can easily send an AJAX POST request to Twilio, if the most recent pour date is higher than the last date. Twilio then forwards the message to IFTTT via SMS where a tweet is posted every time a message with specific information from Twilios number arrives.

 

 

Issues and Conclusion

Developing OpenUI5 can be fun once you’ve learned the way it’s used. You could even say that it’s fairly simple taking into consideration that JavaScript, XML, HTML and CSS are quite easy-to-learn languages. Nevertheless, in the beginning you have to be aware of struggles, such as using the right syntax in XML, JSON and JS, always keeping in mind the namespaces of your used libraries in views, finding and modifying the desired properties deep in the heart of container-trees and many more. Luckily, there’s a lot of information which can be found on SCN, Stackoverflow or other forums. Google is a pretty helpful companion on your way to being a professional UI5 developer

Another lesson learned is the variety of opportunities to customize OpenUI5. Being able to react to data model changes with Twitter posts (via Twilio and IFTTT) is a great thing. The flawless integration of an external library (Chart.js) was essential in creating dynamic charts with ease. Plunker as a web development environment is able to integrate the UI5 framework. It is a great way of testing your app or little functions as it usually runs a lot faster than the HANA Web-based Development workbench and a lot more stable than the current WebIDE.

For any questions on the blog, please reach out via mail

Metadata Binding in UI5

$
0
0

  Hi All,

                Here I’m going to explain how to do Metadata Binding in UI5. Actually, In UI5 Application, We are Hard Coded some Properties like Label’s and MaxLength, etc… from i18n.properties file or directly.

According to me it’s not a good approach because, if we develop the application in English Language and need to give same Application to German or any other Language, And for example MaxLength is increased or decreased by Abap on any fields like amount, phone number, etc..,  . Now changes have to do from Abap side as well as UI5 side (So many Changes!! Bad idea right?).

So Why should we hardcode these things, If we directly bind from metadata, No changes from UI5 side, No rework.

                For this binding purpose SAP provided 2 Ways,

1. Absolute Binding – means we should give Full Path to access a file.

Example,

     C:\Windows\calc.exe

2. Relative Binding- means don’t want to give Full Path to access a file, directly we can give file name.

Example,

                     calc.exe

Now, Enter Your metadata url to get metadata,

In Google Crome I entered my url/$metadata . below is my metadata.

<edmx:Edmx 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" Version="1.0">

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

<Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" Namespace="NameSpace" xml:lang="en" sap:schema-version="0000">

<EntityType Name="EntityTypeName" sap:content-version="1">

<Key>

<PropertyRef Name="PropertyRefName"/>

</Key>

<Property Name="PropertyName1" Type="Edm.String" Nullable="false" MaxLength="12" sap:label="Label Name1" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>

<Property Name="PropertyName2" Type="Edm.Edm.Decimal" Nullable="false" MaxLength="4" sap:label="Label Name2" sap:creatable="false" sap:updatable="false" sap:sortable="false"/>

<Property Name="PropertyName3" Type="Edm.DateTime" Nullable="false" MaxLength="30" sap:label="Label Name3" sap:creatable="false" sap:updatable="false" sap:sortable="false"/>

</EntityType>

<EntityContainer Name=" NameSpace _Entities" m:IsDefaultEntityContainer="true">

<EntitySet Name="EntitySetName" EntityType=" NameSpace.EntityTypeName" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:pageable="false" sap:content-version="1"/>

</EntityContainer>

<atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="self" href="http://URL/$metadata"/>

<atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="latest-version" href="http://URL/$metadata"/>

</Schema>

</edmx:DataServices>

</edmx:Edmx>

In mycomponent.js,

I initialize my model with ”oRefModel” because I used multimodel so I give reference name for that model.And for setting model I used this.setModel() and sap.ui.getCore().setModel() because sometimes, In .xml this.getModel() not working properly and .js sap.ui.getCore().getModel() not working properly.

              var sServiceUrl = "URL";

              var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, true);

              this.setModel(oModel, "oRefModel");

              sap.ui.getCore().setModel(oModel, " oRefModel ");

In my.xml view,

                Here, you can bind using any one of way.

Way1. Absolute Binding

1. For the Properties starts with “sap:” bindings like sap:label , sap:creatable etc,..

                Example,

                <Labeltext="{oRefModel>/#EntityTypeName/PropertyName1/@sap:label}"></Label>

 

2. For the Properties does’t starts with “sap:” bindings like MaxLength , Type, etc,..

Example,

<InputmaxLength="{oRefModel>/#EntityTypeName/PropertyName1/@maxLength}"/>.

 

type="{oRefModel>/#EntityTypeName/PropertyName1/@type"}"

 

In metadata MaxLength , Type are in capital letters but in that name you can’t get the metadata values.

If you get the metadata in debug mode, there you will see these properties with small letters like mexLength, type, etc..,

 

Here, #-referred address,

oRefModel>/#EntityTypeName – refered the direct path to the properties.

 

Way2. Relative Binding

1.  For the Properties starts with “sap:” bindings like sap:label , sap:creatable etc,..

                Example,

                <Labeltext="{oRefModel>/EntitySetName/PropertyName1/#@sap:label}"></Label>


2. For the Properties does’t starts with “sap:” bindings like MaxLength , Type, etc,..

Example,

<InputmaxLength="{oRefModel>/EntitySetName/PropertyName1/0/#@maxLength"}"/>.

 

type="{oRefModel>/EntitySetName/PropertyName1/0/#@type"}"

 

In metadata MaxLength , Type are in capital letters but in that name you can’t get the metadata values.

If you get the metadata in debug mode, there you will see these properties with small letters like mexLength, type, etc..,

 

Here, #-referred address,

oRefModel>/ EntitySetName– refered the in-direct path to the EntityType.

See in metadata file,

<EntitySet Name="EntitySetName" EntityType=" NameSpace.EntityTypeName" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:pageable="false" sap:content-version="1"/>

So, its indirect path, half path or relative path to access the metadata properties.

 

Note: 

In backend “PropertyName2”  is of Type="Edm.Edm.Decimal" so <InputmaxLength="{oRefModel>/#EntityTypeName/PropertyName2/@maxLength}"/> will work.

<Property Name="PropertyName2" Type="Edm.Edm.Decimal" Nullable="false" MaxLength="4" sap:label="Label Name2" sap:creatable="false" sap:updatable="false" sap:sortable="false"/>

 

In backend “PropertyName1”  is of Type="Edm.Edm.String " so <InputmaxLength="{oRefModel>/#EntityTypeName/PropertyName1/@maxLength}"/> will not work.

<Property Name="PropertyName1" Type="Edm.Edm.String " Nullable="false" MaxLength="4" sap:label="Label Name2" sap:creatable="false" sap:updatable="false" sap:sortable="false"/>

 

For that you need to convert string to integer bec now the MaxLength is comes in String Format but MaxLength Property will allow only integer. so it will give error.

For that convert you can use formatter or else any other methods.

<InputmaxLength="path :’{oRefModel>/#EntityTypeName/PropertyName1/@maxLength}’ formatter:”call your formatter method”"/>

 

Reference- Property Metadata Binding - UI Development Toolkit for HTML5 (SAPUI5) - SAP Library

 

Regards,

Santhosh Gowda

 

 

               

               

Viewing all 789 articles
Browse latest View live




Latest Images