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

SAPUI5 and Neptune Designer

$
0
0

All,

 

I have seen two good videos from the people at Neptune, which may be worth a look.

 

This has kind of changed my mind on Neptune Software, and is on my list to look at further.

 

http://neptune-software.com/products/recorded-webinar-create-an-ui5-app-with-neptune-application-designer/

 

http://neptune-software.com/news/recorded-webinar-create-an-offline-application-based-on-sapui5-with-neptune-application-designer/

 

The other nice cool thing is that they have an client application you can now try as well.

 

Neptune Client available on the App Store and on Google play | Neptune Software

 

The one question that I still have for Neptune and would like to see some more information on is the integration with the back end and how to create an Application Class.

 

Martin



Model as Interface to Dialog

$
0
0

We often use Dialog Box to collect user's inputs. Dialog's content can be simple or complex. The former is easy to deal with. However the latter needs a lot of effort. In this blog, we want to share an interface between dialog on caller to solve some fundamental things such as

  1. How do I initialize the values of controls in the dialog? Do I have to know get the controls in the dialog and set their values accordingly?
  2. How do I get the values of controls when user click on the Submit/OK buttons?
  3. How do I reset the values of the dialog when it is opened again.

 

We propose that we use a JSON model as the interface between the caller and the dialog. Let looks at some codes.

    var dialog = new sap.m.Dialog({

         title: 'TItle of Dialog',

         content: [

             new sap.m.Input({value: '{/value1}'}),

             new sap.m.Input({value: '{/value2}'})

],

         beginButton: new sap.m.Button({

             text: 'OK',

             press: function () {

                 if (dialog.success) {

                     if (dialog.success()) {

                        dialog.close();

                    }

                 } else {

                    dialog.close();

                }

             }

         }),

         endButton: new sap.m.Button({

             text: 'Cancel',

             press: function () {

                 dialog.close();

             }

        })

     });

For illustration purpose, we keep the controls in the dialog simple. We have just two controls. And they are bind to /value1 and /value2 respectively. And when OK button is clicked, success function is called. Let's look at the caller's code.       

var model = new sap.ui.model.json.JSONModel();

model.setData({

value1: "",

value2: "Default value for 2"

});

dialog.setModel(model);

dialog.success = function () {

var model = dialog.getModel();

var data = model.getData();

alert(data.value1);

alert(data.value2);

return true;

}

dialog.open();

 

The caller set the values for the two inputs in the dialog via a model and expects the dialog to call the success function if OK button is pressed. In this manner, the controls in the dialog can be changed to TextArea or other controls later; and the caller's code remains unchanged.

 

Summary: We have a way to set the default values for these inputs and their values are always re-initialize when dialog is open; and caller does not need to know the kinds of controls used in the dialog as it just fetch the values from the model.

 

Working code is at JSBin.

 

Dennis

The power of OData - Part 4 - Creating an OData service

$
0
0

Content of this series:

 

The power of OData - Part 1 - Introduction

The power of OData - Part 2 - Setting up the Environment

The power of OData - Part 3 - Creating a data Model

      The power of OData - Part 4 - Creating an OData service (this part)

      The power of OData - Part 5 - Consuming the service with SAPUI5

 

 

Hey everyone and welcome to the next part of my series. Today, we are going to create the needed source code to create an OData feed from our database. It took me a little longer to write this part because I had to make some changes to one of the tools we will use in this part and pushed them into the repository. Until my pull-request is accepted, we have to use my repository link; I will update this post if the code is integrated into the official branch.

 

So far, we should have a working Apache Webserver running with PHP 5.5 and a MySQL server with our “customer” database and some sample data in it. In our website’s root directory, we should have a “customer_api” directory with the standard OData PHP Producer library inside. If you need more information about setting up the environment, begin reading the other posts of this series as mentioned above.

 

First of all, we won’t code much. There exist some libraries and scripts that will create the needed source code for us based on our database design. Furthermore, the documentation on the classes, interfaces and methods is very good. As the created filed will suit our need here, I won’t go much into detail but explain what kind of file is needed for.

 

Let’s start by getting the required packages. Download the following libraries:

 

 

The first download will create the scripts for us based on our database design. Doctrine here is needed in order to access and analyse the database. In general, it is a nice framework for creating abstract versions of a database in PHP. With the help of doctrine, we can have PHP classes that refer to our database. The benefit is that we work with objects here instead of database queries. (So far about Doctrine, it’s only a very very rough description).

 

Now extract both archives. Within your Doctrine-extract, you should find a Doctrine folder:

 

1.png

Copy this folder inside your connectors' folder, so that its structure looks like this:

2.png

  1. That was the configuration needed so far. Now let’s have fun

Open up your XAMPP control panel and start your MySQL server.

 

Fire up a console and navigate to your Connector’s folder and execute the following command:

 

php MySQLConnector.php /db=customer /u=root /pw= /srvc=Customer /h=127.0.0.1

 

Here are the options:

  • /db= name of the database you want to use
  • /u= username of the database user. I take root in this clean XAMPP installation
  • /pw= password of the database user. For root in a XAMPP installation the password is not set
  • /srvc= the name of the service we want to create, we can change this later again
  • /h= the host of the database system. Localhost would also be possible but I read that there might be some issues with this.

3.png

The system will ask you of you want to modify the EDMX file. Type “n” here and hit return. It should now create the needed script files.

 

We don’t have to care much about this EDMX file. It is generated by Doctrine and describes our database and all included tables in a xml format.

 

Within your Connector’s folder navigate now to the OutputFiles folder lying under ODataConnectorForMySQL:

4.png

Within that, there is a folder called Customers

 

5.png

As I said the script to create the service with a capital C. Now copy this folder and go to your services folder under C:\xampp\htdocs\customer_api\:

6.png

Delete anything in this folder and insert your service folder:

 

Finally copy the service.config.xml file from your Customer folder to the services folder. The final folder structure should look like this:

 

7.png

 

Now let’s see if it works. Start Apache from your XAMPP control panel (MySQL should be started because of the above configuration), start a browser and open this URL: http://localhost/customer_api/Customer.svc

 

If you get some XML listing showing your tables, everything went well.

 

Now open http://localhost/customer_api/Customer.svc/$metadata

 

You will get a description of your tables and columns.

 

To access, let’s say all customers, go here: http://localhost/customer_api/Customer.svc/customers

 

As I said, we can change the service name now, if we want. Open the xml file you just copied to the services folder:

8.png

The content here says how the service is called (here “Customer.svc”), where it is located and what URL should be called.

 

If you look into the Customer folder, there are 5 files that were previously created. The EDMX file is not relevant here and could also be deleted. Important of those 5 files are the following 3:

 

  • CustomerDataService.php
  • CustomerMetadata.php
  • CustomerQueryProvider.php

 

In the first file, a reference to the others is done and objects are instantiated. So if any of those classes change or you create everything manually, here is the mapping part. Within the metadata file, a class representation of our database structure is created. This includes key fields as well as all relations between the tables. Within the QueryProvider file, the queries itself are created. This is the place where we also could define custom queries or add some Join statements for example.

 

More about those files can be found in the documentation of the OData PHP producer. I think that the MySQLConnector here is a good tool for starting with custom services.

 

In the next and last part, I will consume the services from an UI5 application.

Colorful Fiori - Part 1 - Red

$
0
0

Introduction

 

This blog is about creating themes for SAP FIORI and for SAPUI5 custom applications.

In these series of blogs i will share different colors of fiori . I will try to create fiori themes using different colors. You all are most appreciated to mark your likes or dislikes . All suggestions are most welcome.

 

I always love to play around with CSS. I have worked as Web designer at my previous employer where i learnt web designing. Today i am happy that in SAP again i got something which i love to do .

Page.JPG

 

 

Content

 

In this blog i will share the images, color codes, css classes and how can we use those classes in application.

 

References

 

  1. Create and Apply Custom Theme to SAPUI5 Application
  2. SAPUI5 SDK - Demo Kit
  3. Ultimate CSS Gradient Generator - ColorZilla.com

 

Here We Go

 

We will talk in the context of the "sap_bluecrystal"

 

Let us start with RED color for theme.

 

Page - Copy.JPG

Figure 1. Full application preview


caaada.JPG

                                             Figure 2. Tiles


sdaa.JPG

Figure 3. List

3.JPG

Figure 4. Tab 1


6.JPG


Figure 5. Tab 2


77.JPG


          Figure 6. Mix


Lets Discuss


Hmmmm... did you see something new?

Everything RED you may not like RED but yes we have something new.


What i did for this ?

  • Custom theme created
  • Few color code changed
  • Added new css class

 

How i achieved this?


I used standard blue_crystal theme for my application.

To create custom theme you can refer the document which i have referred at the beginning of this blog.

Apply that theme to your application and Bingo !!! You will Rock


Color Code


Replace the left hand side color codes with right hand side colors in your theme.


#009de0 = #CF0404

 

#006ca7 = #ff3019

 

#007cc0 = #CF0404

 

#00679e = #ff3019

 

#e6f2f9 = #eaefb5

 

#dddddd = #666666


Source Code


below are the classes which i have overridden.
You can put these classes in your custom .css file and give reference of that .css file in your index page or you can put it in  your theme designer's CSS panel.

 

.sapMGlobalBackgroundColor{background-image:linear-gradient(to bottom,#fcefec 0,#ffb9ab 100%);}
.sap-desktop .sapMBar.sapMPageHeader{background-color:#CF0404 !important; }
.sapMBar-CTX .sapMLabel{color:#ffffff;}
.sapMTile{-moz-border-radius: 10px;  -webkit-border-radius: 10px; -khtml-border-radius: 10px; border-radius: 10px;  background: #ffffff; /* Old browsers */
background: -moz-linear-gradient(top,  #ffffff 0%, #f3f3f3 50%, #ededed 51%, #ffffff 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(50%,#f3f3f3), color-stop(51%,#ededed), color-stop(100%,#ffffff)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* IE10+ */
background: linear-gradient(to bottom,  #ffffff 0%,#f3f3f3 50%,#ededed 51%,#ffffff 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ffffff',GradientType=0 ); /* IE6-9 */
}
.sapMPullDown{background-color:#ffffff;}
.sapMList .sapMLIB.sapMGHLI{background-color:#e9d4b3;}
.sapMSFB{background:#d6dbbf}
.sapMBar-CTX .sapMBtnContent>.sapUiIcon,.sapMBar-CTX .sapMBtn{color:#ffffff;}
.sapMPageHeader.sapMBar-CTX .sapMBtn, .sapMPageHeader.sapMBar-CTX .sapMSlt{border-image:linear-gradient(#000000 8.33%,#666666 8.33%) 0 100%;}
.sapMSplitContainerMaster:not(.sapMSplitContainerMasterVisible):before{border-right:1px solid #000000;}
.sapMShellBrandingBar{background-color:#000000;}
.sapMBar.sapMPageHeader:before{border-top:0.25rem solid #000000;}
.sapMFooter-CTX .sapMSegBBtn{border-color:#000000;}
.sap-desktop footer.sapMBar, .sap-desktop footer.sapMBar.sapMBarTranslucent{background-color:#000000; !important}

Suggestions


Make sure that your change will affect only to those controls, of which, you want to change the style

for example : giving border-radius to .sapMBtn will give rounded border to all buttons irrespective of their location and types.

                   

Next


Colorful Fiori - Part 2 -Yellow Green


Hope you liked it

Happy Learning

Working with JSON model dates in UI5

$
0
0

Let's say you've designed an OData Service that returns an Entity with a Date-/Time-value (Edm.DateTime).

Let's also say that you're consuming the service with SAP UI5, particularly with the JSON Model (sap.ui.model.json.JSONModel).

And to top things off, you're binding that to a DateTime UI control (sap.m.DateTimeInput) to display a nice mobile datepicker.

 

Then you might have gone through a hell of a time already

 

No, seriously - making those three things play together nicely isn't difficult, but provides some obstacles. John Patterson has written an excellent article explaining the handling of OData DateTime with Gateway and UI5.

What didn't make it into the article was handling Edm.DateTime in the UI5 JSON model explicitly.

 

So off we go:

 

First, Gateway's Edm.DateTime are represented in the UI5 JSON Model as Strings à la

 

    /Date(1402166783294)/

 

This seems to represent a JavaScript timestamp object.

Strange?

Me thinks too.

But that's the way it is (with UI5 version 1.20.4 as of this writing at least).

 

Next, if you're trying to bind this to the DateTimeInput, this will fail - the UI control expects a JavaScript Date object: "Type Error: Expected JavaScript Date Object".

 

So the JSON model Date strings needs to be converted to a Date object at runtime in order to be usable in UI5 controls.

 

I've found two ways to do that.

 

The first extracts the numbers from the string, using them to construct a new Date object.


// this comes from SAP NW Gateway
// and is in the JSON model
var sJsonDate = "/Date(1402166783294)/";
var sNumber = sJsonDate.replace(/[^0-9]+/g,'');
var iNumber = sNumber * 1; //trick seventeen
var oDate = new Date(iNumber);

Attention: JS String.replace method returns a string that can't be used directly to construct a Date object. Multiplying it with 1 causes an implicit type cast to Integer - the latter goes directly into new Date() then.

 

The second way uses the RegExp object. With its exec Method, all content between the two "/" of the Date string are extracted - the resulting Date(1402166783294) is auto-assigned to RegExp.$1 and subsequently used for a new call.


// this comes from SAP NW Gateway 
// and is in the JSON Model
var sJsonDate = "/Date(1402166783294)/";/\/(.+)\//.exec(sJsonDate);
var oDate = eval("new " + RegExp.$1);

Clue here is, that exec returns an Object - Date(1402166783294) resides in RegExp.$1 as an object representation. So with the help of eval(), it can directly be used with "new" for instantiating a Date object.


Both methods work: they result in converting the Gateway-JSON-Model "/Date(1402166783294)/" into its Date object representation that can then be used for the sap.m.DateInput control.

var oDateTimeInput1 = new sap.m.DateTimeInput({  dateValue: oDate,  displayFormat: "MMM yyyy",  valueFormat: "yyyy-MM-dd"
});

 

Let's combine this with the proper DateInput "type" property and UI5's binding and formatting API.

The dateValue property of the UI control is bound to the path "/date" of the JSON model. The value the JSON model injects then gets formatted with one of the above two snippets.

 

        var oData = {                date: sJsonDate        };        var oJsonModel = new sap.ui.model.json.JSONModel();        oJsonModel.setData(oData);        var oDateTimeInput3 = new sap.m.DateTimeInput({            type: sap.m.DateTimeInputType.Date,            displayFormat: "dd - M - yy",            dateValue: {                path: "/date",                formatter: function(sDate) {                    if(sDate) {                        /\/(.+)\//.exec(sDate);                        return eval("new " + RegExp.$1);
//                        var sNumber = sDate.replace(/[^0-9]+/g,'');
//                        var iNumber = sNumber * 1; //trick seventeen
//                        return new Date(iNumber);                    }                }            }        });        oDateTimeInput3.setModel(oJsonModel);

 

And that's it - a working DatePicker UI control, bound to a JSON model that holds values from a Gateway OData call.

Good karma all around.

 

Hint: both ways take < 1ms in execution time - so no performance gain possible here, use the possibility of your liking.

 

A working example can be found on GitHub.

World Cup 2014 and SAPUI5 - Goal!

$
0
0

Hi everybody!

 

This is my first time writing content for SCN after years of learning from the gurus of SAP Community. And how amazing it is, especially when you have the opportunity to do so combining it with a subject that (almost) all Brazilians love: Soccer! (or Football - I believe you got the idea ).

 

I remember the last 2010 World Cup not only because of Sjneider and that terrible game where Brazil lost to Netherlands in quarter finals , but at that time I managed to develop a Web Dynpro ABAP where my friends and I could enter our bets for the World Cup's Group phase and the better with more number of hits would earn some money.My prove that I didn't play any trick on them is that I was the worst ranked at the end!

 

Four years have passed and with all these World Cup talk going on I remembered how cool doing that Bet Manager was, so I decided to develop an App related to World Cup before the grand 2014 World Cup opening on June 12th, 2014 in São Paulo. I knew I wouldn't be able to develop a complete Bet Manager, but I knew I could do something almost similar. SAP's UI strategy has really changed after four years, so I really needed to try a different UI approach. That's where SAPUI5 comes in!

 

In the very beginning I didn't like SAPUI5, and more specifically the idea that I previously had that Views could be only created using JavaScript - don't ask me why, maybe because the API Documentation always refers to the JavaScript entities of SAPUI5. This idea completely changed after reading - and doing - the wonderful tutorial that DJ Adams et all have put together in Building SAP Fiori-like UIs with SAPUI5. I really liked the separation of concerns that XML Views provides, although I personally believe that HTML would be the ideal place for presentation as we see in JQuery Mobile (HTML Views in SAPUI5 is in my To-Do list). But this blog was inspiration enough to get me into SAPUI5.


Here are some screenshots of what the App looks like:


Desktop viewport:

Capturar0.PNGCapturar2.PNG

Mobile viewport:

Capturar11a.PNGCapturar1a.PNGCapturar2a.PNGCapturar3a.PNG


My boilerplate was basically the resulting App from the tutorial mentioned above, including the awesome technique of propagating the sap.m.SplitApp container throughout the Views of the App. But first off, I needed some resources to get this App started:


  • Flags: The circle-like flags from here are elegant and are available to use for non-commercial purposes. An special mention to the blog SAPUI5 and Responsive Web Design (RWD) from Morgan Apelqvist that helped me adjust the flag sizes according to the viewport;
  • Fonts(optional): I have set Samba as the App default font for a while. I thought it wasn't as readable as I wanted, so I've put it aside;
  • 2014 World Cup logo: The first Google hit for "2014 World Cup logo" ;
  • Data Models: Despite all possible on-line resources, I ended up using this JSON model as a base for development, which I could easily change locally. It is made of 5 JSON files: group.json, match.json, team.json, team_bracket.json (not used in this App) and venue.json. That's a sample of each of them:


group.json:

{  "group_collection":  [  {  "id": 1,  "name": "A"  },  ...//  7 more groups  ]
}


team.json:

{  "team_collection":  [  {  "id": 1,  "group_id": 1,  "code": "BRA",  "name": "Brazil", "wins":5  },  ... // 31 more teams  ]
}


match.json:

{  "match_collection":  [  {  "id": 1,  "stage": 0,  "venue_id": 12,  "team1_id": 1,  "team2_id": 2,  "kickoff": "2014-06-12 17:00:00"  },  ... // 63 Matches, but only 48 happens in the Groups' phase  // "stage": 0 - indicates that it is a classification match  ]
}


venue.json:

{  "venue_collection":  [  {  "id": 1,  "name": "Estadio Mineirao",  "city": "Belo Horizonte"  },  ... //11 more venues  ]
}


It was quite tricky to work with the JSON model above. The examples I had seen so far (including the tutorial above) relied on a single flattened Model, where you can navigate top-down using the facilities that Contexts provide. In my case I had 4 different JSON models and I wasn't willing to flatten them. I couldn't find a way to link them using Binding properties inside the View, so I've come up with a solution where the models which provide descriptions (venue.json and team.json) were loaded when the Component is created and assigned to the Formatter class sap.ui.demo.worldCup2014.util.TeamFormatter as JavaScript objects:


Component.js:

jQuery.sap.require("sap.ui.demo.worldCup2014.util.TeamFormatter");
jQuery.sap.declare("sap.ui.demo.worldCup2014.Component");
sap.ui.core.UIComponent.extend("sap.ui.demo.worldCup2014.Component", {  createContent : function() {  // create root view  var oView = sap.ui.view({  id : "app",  viewName : "sap.ui.demo.worldCup2014.view.App",  type : "JS",  viewData : {  component : this  }  });  // set i18n model  var i18nModel = new sap.ui.model.resource.ResourceModel({  bundleUrl : "i18n/messageBundle.properties"  });  oView.setModel(i18nModel, "i18n");  // Loading TeamFormatter with JSON Models:  jQuery.ajax({  url : "./model/team.json",  dataType : "json"  }).done(function(data) {  sap.ui.demo.worldCup2014.util.TeamFormatter.teams = data;  });  jQuery.ajax({  url : "./model/venue.json",  dataType : "json"  }).done(function(data) {  sap.ui.demo.worldCup2014.util.TeamFormatter.venues = data;  });  ...  // Using a local model for offline development  var oMatch = new sap.ui.model.json.JSONModel("model/match.json");  oView.setModel(oMatch, "matches");  var oGroup = new sap.ui.model.json.JSONModel("model/group.json");  oView.setModel(oGroup, "groups");  var oTeam = new sap.ui.model.json.JSONModel("model/team.json");  oTeam.setDefaultBindingMode("OneWay");  oView.setModel(oTeam, "teams");  ...  return oView;  }
});


TeamFormatter.js:

jQuery.sap.declare("sap.ui.demo.worldCup2014.util.TeamFormatter");
sap.ui.demo.worldCup2014.util.TeamFormatter = {  teamName : function(value) {  return sap.ui.demo.worldCup2014.util.TeamFormatter.teams.team_collection  .filter(function(item) {  return item.id === value;  })[0].name;  },  venueName : function(value) {  return sap.ui.demo.worldCup2014.util.TeamFormatter.venues.venue_collection  .filter(function(item) {  return item.id === value;  })[0].name;  },  venueCity : function(value) {  return sap.ui.demo.worldCup2014.util.TeamFormatter.venues.venue_collection  .filter(function(item) {  return item.id === value;  })[0].city;  },
};


This way I could use the TeamFormatter class above in order to get the name of a team, as detailed below in the XML View Matches:


Matches.view.xml:

<core:View  xmlns:core="sap.ui.core"  xmlns:mvc="sap.ui.core.mvc"  xmlns="sap.m"  controllerName="sap.ui.demo.worldCup2014.view.Matches"  xmlns:html="http://www.w3.org/1999/xhtml">  <Page  title="{i18n>MatchTableTitle} {path: 'navigation>/team',   formatter: 'sap.ui.demo.worldCup2014.util.TeamFormatter.teamName'}"  showNavButton="true"  navButtonPress="handleNavButtonPress">  <Table  items="{path: 'matches>/match_collection',  sorter: [{path: 'kickoff', descending: false}]}"  id="matches">  <columns>  <Column>  <header>  <Label  class="wc2014"  text="{i18n>MatchTableColumnHT}" />  </header>  </Column>  <Column>  <header>  <Label  class="wc2014"  text="{i18n>MatchTableColumnVT}" />  </header>  </Column>  <Column  minScreenWidth="Tablet"  demandPopin="true"  hAlign="Center">  <header>  <Label  class="wc2014"  text="{i18n>MatchTableColumnDT}" />  </header>  </Column>  <Column  minScreenWidth="Tablet"  demandPopin="true"  hAlign="Center">  <header>  <Label  class="wc2014"  text="{i18n>MatchTableColumnVN}" />  </header>  </Column>  <Column  minScreenWidth="Tablet"  demandPopin="true"  hAlign="Center">  <header>  <Label  class="wc2014"  text="{i18n>MatchTableColumnVC}" />  </header>  </Column>  </columns>  <ColumnListItem type="{sap.m.ListType.Detail}">  <cells>  <ObjectIdentifier  title="{path: 'matches>team1_id',   formatter: 'sap.ui.demo.worldCup2014.util.TeamFormatter.teamName'}"  class="wc2014" />  <ObjectIdentifier  title="{path: 'matches>team2_id',   formatter: 'sap.ui.demo.worldCup2014.util.TeamFormatter.teamName'}"  class="wc2014" />  <Text  text="{matches>kickoff}"  class="wc2014" />  <Text  text="{  path:'matches>venue_id',  formatter:'sap.ui.demo.worldCup2014.util.TeamFormatter.venueName'   }"  class="wc2014" />  <Text  text="{  path:'matches>venue_id',  formatter:'sap.ui.demo.worldCup2014.util.TeamFormatter.venueCity'   }"  class="wc2014" />  </cells>  </ColumnListItem>  </Table>  </Page></core:View>

In order to navigate between models I created CustomDatas inside of sap.m.List / sap.m.Table items so I could store navigation id's and retrieve them inside their respective press events. Notice that sap.ui.model.Filter objects are created so the items binding of the sap.m.Table object could be properly filtered according to the Group id:

 

Groups.view.xml:

<core:View  xmlns:core="sap.ui.core"  xmlns="sap.m"  controllerName="sap.ui.demo.worldCup2014.view.Groups"  xmlns:app="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"  xmlns:html="http://www.w3.org/1999/xhtml">  <Page title="{i18n>GroupsPageTitle}">  <List items="{groups>/group_collection}">  <StandardListItem  class="wc2014"  type="Active"  app:groupId="{groups>id}"  title="{i18n>GroupsListTitle} {groups>name}"  press="handleListItemPress"/>  </List>  </Page></core:View>


Groups.controller.js:

sap.ui.controller("sap.ui.demo.worldCup2014.view.Groups", {  handleListItemPress : function(evt) {  // Retrieve Custom Data:  var itemPressed = evt.getSource();  var groupId = itemPressed.data("groupId");  // Pass Group description to Navigation model:  var oNavigation = this.getView().getModel("navigation");  oNavigation.setProperty("/group", itemPressed.getTitle());  // Filter Team model using the Group id:  var filtersTeam = [];  filtersTeam.push(new sap.ui.model.Filter("group_id",  sap.ui.model.FilterOperator.EQ, groupId));  var filterObj = {  id : "teams",  binding : "items",  filter : filtersTeam  };  this.nav.to("Teams", undefined, filterObj);  },  ...
});


I have just pointed out here the details that I found important, but the complete version of the App can be found in https://github.com/edersouza38/WorldCup2014-SAPUI5. Please check it out and leave your comments!

Multi-Level Menu Control for UI5

$
0
0

 

Enhance your Control-Lib!

Intro

 

Today i want to show you a new custom control for UI5-applications. I let myself inspired by codrops once again (see Multi-Level Push Menu).

 

The idea is to create a responsive and multi-level menu, which is useful for visualize complex nested menu structures with many navigation items. This requirement will hit you, if you have to implement e.g an online store. And because place in UIs is very valuable, especially in mobile applications, this menu works with layered menu levels to provide a clear and smart user interface.

 

To get a better impression, please check out the following links.

 

View Demo

 

Get Source Code

 

Now i will explain you the details of my implementation. Your best be would be to have a look at the sources at github at the same time.

 

Implementation

 

Styles

 

After creating a new project in eclipse, i usually do similar steps to implement a custom control. If i want to port an existing control to UI5(like in this case), i transfer all CSS to a new file at first. In the case at hand, this file is menu.css. All other styles, which are not related to the control, are broken down in other files.

css.png


  1. menu.css: Styles for the menu control
  2. app.css: Common styles for the application
  3. icon.css: Styles for CSS-icons, which can be used to beautify menu items

 

UI5 Controller and View

 

The basic structure of the UI5 application is very simple. As you can see in the following screenshot, we have just a controller and the corresponding (JS-)view.

 

ui5_entities.png

  1. app.controller.js: This file contains central navigation handling. When you click on a menu item, a custom event is fired by the control which can be processed in any part of your project, preferably in your application controller like in this case.
  2. app.view.js: The menu structure, menu control and all other parts of the view are created here.

 

Multi-Level Menu Control

 

Now comes the really interesting part! All parts of the new control are placed in special directories (Screenshot). These directories are nothing more than an implementation of a namespace, so i can work with the UI5-statements jQuery.sap.require and jQuery.sap.declare.

 

control.png

  1. resources/neko/control/MultiLevelMenu.js: This file contains the core logic. A big part of this JavaScript from the original codrops project was transferred in this file. Although, i had to change a few things, so we can use it easier in our UI5 environment.

 

    1. I removed the framework classie.js and implement all class-based JavaScript manipulations via jQuery.
    2. I removed modernizr.js, because no fallback for older browsers is implemented. That means, you can use this control only in current Chrome, Firefox, Safari and IE11. The usage of 3D Transforms (CSS) to create the transitions prevents a support in older browsers like IE9 (see browser support).
    3. The original coding is working with many native JavaScript statements. That's of course not bad, but because we are using jQuery in UI5-projects anyway, i changed some coding parts into more compact jQuery statements.

 

  1. resources/neko/renderer/MultiLevelMenu.js: This file contains logic for rendering the a bit complex and nested markup. I'm using here a so called render-class, which is an UI5 functionality for transferring all render-related code in a separate instance. This is very great to get a better overview in your actual control implementation.
  2. resources/neko/element/MultiLevelMenuItem.js: Here we have a template for our menu-items. It is an extension of the standard UI5-Menu-Item and allows to create nested structures via submenues.

 

Usage

 

The Multi-Level Menu Item is at first a container control. That means, that all content, which you are going to display has to placed in this control (like sap.ui.ux3.Shell). Besides, you have to provide a valid (nested) menu structure, which is built out of the mentioned custom element above.

 

Besides, you can choose our of two display types. The first one (overlap) shows always the hierarchy of the menu level in the form of a scale, so it's very easy to go from a very deep level to one of the top levels. The second one (cover) show only the current menu level. If you want to give the user the possibility to navigate back to superior levels, you can activate back-links when creating the control. (This is also possible for the menu-type overlap).

 

I hope, this post and the corresponding source code will be useful for you. Thanks for reading!

CDN for UI5 library

$
0
0

Quoting the article in Wikipedia: Content delivery network - Wikipedia, the free encyclopedia

 

A content delivery network or content distribution network (CDN) is a large distributed system of servers deployed in multiple data centers across the Internet. The goal of a CDN is to serve content to end-users with high availability and high performance. CDNs serve a large fraction of the Internet content today, including web objects (text, graphics and scripts), downloadable objects (media files, software, documents), applications (e-commerce, portals), live streaming media, on-demand streaming media, andsocial networks.

 

Resuming, CDN is a place where some files are hosted to improve the user experience.

If lots of websites use jQuery, instead each one of them host their own jQuery files in their server, they use jQuery files hosted in a CDN server.

This is a good idea because they'll save space and traffic in their own server at the same time they'll share the cache in the user's browser.

 

Google has a specific website to share the most popular javascript libraries: https://developers.google.com/speed/libraries/devguide

Microsoft has one as well: http://www.asp.net/ajaxlibrary/cdn.ashx

 

To make us happy, SAP has a CDN which provides UI5 libraries for our apps.

 

If your app runs on SAP ECC environment, you should use:

SAPUI5 - https://sapui5.hana.ondemand.com/resources/sap-ui-core.js

 

 

If your app has nothing to do with SAP, so you should use:

OpenUI5 - https://openui5.hana.ondemand.com/resources/sap-ui-core.js


Compose SAP HANA Cloud Platform Fiori application accessing on premise OData service leveraging SAP River Rapid Development Environment in 30 minutes

$
0
0

Prerequisites

  1. SAP HANA Cloud Connector setup and connected to SAP HANA Cloud Platform, e.g. as described in my respective blog:
    HCC.jpg
  2. SAP River Rapid Development Environment setup, e.g. as described in help.sap.com including the OData destination:
    destination.jpg

Step-by-step Guide

  1. Launch SAP River RDE and create new project:
    project.jpg
  2. Chose SAP Fiori (Starter) Application:
    fiori.jpg
  3. Choose your OData connection as defined in the prerequisites step 2. and search for “catalog”:
    catalog.jpg
  4. Confirm with OK and continue to the Master Selection Template Customizing:
    master.jpg
  5. Followed by the Detail Selection Template Customizing:
    detail.jpg
  6. Confirm to create your Fiori application and run it:
    run.jpg
  7. To see a preview of your OData services in this Fiori style application:
    rde.jpg
  8. After deployment to the SAP HANA Cloud Platform, activation:
    hcp.jpg
  9. And committing to Git:
    git.jpg
  10. The application is available on the SAP HANA Could Platform for easy consumption outside the corporate network:
    deployed.jpg

The power of OData - Part 5 - Consuming the service with SAPUI5

$
0
0

Content of this series:

 

The power of OData - Part 1 - Introduction

The power of OData - Part 2 - Setting up the Environment

The power of OData - Part 3 - Creating a data Model

The power of OData - Part 4 - Creating an OData service

      The power of OData - Part 5 - Consuming the service with SAPUI5(this part)

 

 

So, welcome to the last part of the series, the one where we put everything together and really experience what we’ve build so far. Sorry for the delay of this post, I had to setup new hardware and to eliminate a few more “errors” within the PHP producer library. At least I think it’s an error, but we will see and correct it in this post. Furthermore, we will create a simple UI5 based web application to show the data, will enhance the look&feel and also create a mobile app for listing the data.

 

Let’s begin. Where are we? We should have an Apache webserver running in combination with a MySQL server. Inside the MySQL server, a table called “customer” should exist and we should have setup a webservice running at http://localhost/customer_api/Customer.svc. The query /cities should list all cities inside our database.

 

Now let’s look at the “error” I found. If we consume the service and don’t set any limit in our UI5 table for display, the request will be http://localhost/customer_api/Customer.svc/cities?$skip=0. If we set the property firstVisibleRow to 3, the query parameter $skip will be set to 3. With the last option, we will get results, but if we use $skip=0, an error will be returned. It took me some time to identify the coding line where this validation happens and after I added a little dirty fix, everything went well.

 

So start by modifying DataSerivceHost.php. The file is located in your customer_api folder. Go to library\ODataProducer\OperationContext.

 

1.png

The function validateQueryParameters has to be modified here so that our requests will work. To do so, go to line 370 and add the following after “$optionValue = current($queryOption)” and before “if (empty($optionName))”:

 

if($optionName == '$skip' && $optionValue == 0)                                                            //Added for skip OData Requests
{                $optionValue = 1;
}

2.png

 

Save and close the file.

 

The next issue I faced when testing and developing the sample applications for this part was about cross-origin resource sharing (cors in short). This is mainly an issue because of our development environment. Request across different domains aren’t allowed in general and we might not receive any data if we try to do so. Looking at the service, we are using port 80 (Apache’s standard). When we test in Eclipse, we get a port like 54874 where our UI5 app is running. If we use Tomcat with Eclipse for testing, we have 8080. Although we use localhost, everything is seen as a different domain because of the different ports. SAP provides a simple Proxy solution here (https://help.sap.com/saphelp_nw74/helpdata/de/2d/3f5fb63a2f4090942375df80abc39f/content.htm) but this didn’t work for me. So for the demo environment, I adjusted my .htaccess like this:

 

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "MaxDataServiceVersion, DataServiceVersion"

This allows access from other domains and also header values like the ones used for OData.  After those adjustments, we can now start with the development. Start up your eclipse instance, I assume you all have the UI5 development tools installed.

 

 

Simple Project

 

Create a new project via File -> New -> Project

3.png

 

Choose SAP UI5 Application Development and continue:

4.png

 

Let’s use customer_simple as project name here. As library, we choose “sap.ui.commons” as we will create a simple desktop application.

 

5.png

 

Name your view (I choose mainView) and simply click finish:

6.png

 

At this simple step, we don’t have to touch index.html much. Just add a new library. In the script section of the generated index.html, we have to tell the lib that we want to use a table. So add sap.ui.table here:

 

js.png

 

That’s it. Let’s start consuming the service. Close index.html and open up your controller file. If you took my naming, this should be mainView.controller.js. I like to follow the MVC approach and try to store much logic inside my controllers and use the views really for building the UI. So uncomment the onInit function at the top and add the following code:

 

var sServiceUrl = "http://localhost:80/customer_api/Customer.svc";
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, false);            

sap.ui.getCore().setModel(oModel);

It should look like this now:

 

js2.png

Here, we declare a serviceUrl pointing to our OData service. Additionally, we create an OData model and set this model for our application.

 

Let’s go to the main view. Here is where the binding and UI happens. Delete anything within the createContent function. We will add our own content here. We will create two tables. The first will display all countries from our database; the second will display the cities that belong to a chosen country.

 

Here is the code, I will explain it afterwards:

 

var oCountryTable = new sap.ui.table.Table({
title: "Countries",      width : "100%",       selectionMode : sap.ui.table.SelectionMode.Single 
});

oCountryTable.addColumn(new
      label: new sap.ui.commons.Label({text: "Country ID"}),      template: new sap.ui.commons.TextView().bindProperty("text", "countryID"),      sortProperty: "countryID",      filterProperty: "countryID",      width: "50px"
}));

oCountryTable.addColumn(new
      label: new sap.ui.commons.Label({text: "Country Name"}),      template: new sap.ui.commons.TextView().bindProperty("text", "country"),      sortProperty: "country",      filterProperty: "country",      width: "200px"
}));

oCountryTable.bindRows("/countries");
oCountryTable.placeAt("content");

First we create a new table here, give it a title and width and say that we can select single lines. After that we add three columns and assign a label, a template and some other properties. Most important here is the bind option in the template. We bind to the fieldname we have assigned in our service. Remember that the producer build the PHP files depending on the metadata of the database? Here we refer to the fields or our metadata description. After defining the columns we bind the rows of the table to your collection. In out controller, we specified only the service URL ending with Customer.svc. Here we finally bind to the collection, in this case “countries”. And this will result in the above mentioned link like Cusomer.svc/countries?$skip=0. Finally, we place the table in the content div of our index.html.

 

Let’s create another table, but this time, we don’t bind and place it yet:

 

var oCityTable = new sap.ui.table.Table({      title: "Cities",      width : "100%",       selectionMode : sap.ui.table.SelectionMode.None 
});

oCityTable.addColumn(new
      label: new sap.ui.commons.Label({text: "City ID"}),      template: new sap.ui.commons.TextView().bindProperty("text", "cityID"),      sortProperty: "cityID",      filterProperty: "cityID",      width: "50px"
}));

oCityTable.addColumn(new
      label: new sap.ui.commons.Label({text: "City Name"}),      template: new sap.ui.commons.TextView().bindProperty("text", "city"),      sortProperty: "city",      filterProperty: "city",      width: "200px"
}));

This should be straight forward as it is the same as above. We will now add a rowSelection event that is fired whenever we select a new row. In this event, we build a new query that will run against our service and fetch all the cities depending to a country.

 


oCountryTable.attachRowSelectionChange(function
      selectedRowContext = event.getParameter("rowContext"),      selectedCityLineItems = selectedRowContext + "/cities";      oCityTable.bindRows(selectedCityLineItems);
});

The selected row context will get the current row and the ID of the country. We add /cities as we navigate to a city from the country. The query will look like this: Customer.svc/countries(countryID=1)/cities

 

So UI5 here creates well-formed correct OData queries and the best, our custom service can understand those queries and return the results.

 

We bound the newly selected rows above, let’s place it on the screen. To do this, I’ve copied the content div in index.html and named the new one detail:

 

js 3.png

 

So that I can use oCityTable.placeAt(“detail”); to show it.

 

If you run in Eclipse, the following should be seen:

 

8.png

 

Mobile Demo

 

The mobile version is almost the same as the simple one. Create a new project and choose sap.m as library this time. After the project is created, we don’t have to add anything to our index.html this time, as we are completely using the mobile libraries. The controller looks completely the same as in the simple example; therefore, I will only present the view here:

 

My createContent function looks like this:

 

var oTable = new sap.m.Table({      mode: sap.m.ListMode.None,
columns: [      new sap.m.Column({              header : new sap.m.Label({                    text : "City ID"              })      }),      new sap.m.Column({              header : new sap.m.Label({                    text : "City"              })      })]
});    

oTable.bindItems("/cities"new
cells : [ 
              new sap.m.Text({                    text : "{cityID}"              }),               new sap.m.Text({                    text : "{city}"      })]
}));
var oPage = new sap.m.Page("Title");

oPage.addContent(oTable);
return oPage;

Mobile is a bit different here. The table has a columns collection, which will only store the description of the columns, like their header. After creating a mobile table, we have to bind the items. In this function, we specify the path, here /cities, and then define a ColumnListItem that represents the cells that are shown. In each cell, we bind an item like in the columns for sap.ui.table.

 

After binding, we add the table to a page object and return this for display.

 

9.png

 

I’ve included a more complex example as zipped Eclipse project as an attachment here, if anyone might be interested, just replace txt by zip. This example uses a shell for a better UI and displays all tables in different panes as shown here:

 

10.png

 

I hope you enjoyed this blog series and have many good ideas on how to combine different technologies and enrich your data with SAP data or vice versa. I’d be glad if you leave me some comments, queries, suggestions or similar things about the series.

Difference Between SAPUI5 Views, Controls, Fragments and Components

$
0
0

Hello Everyone,

 

As I saw so many doubts regarding Views, Controls, Fragments and Components confusion I am writing this blog to clear those confusions. Suggestions and Corrections are welcomed.

 

Fragments, Views and Controls are not related to each others.

 

SAPUI5 Views : Views are nothing but the application pages. We define our user interface by creating Views. Views is formed or created by using one or more Controls in it say Page,SimpleForm,Dialog,Label,Input etc. . Every view has its own controller.

 

SAPUI5 Controls : Controls the UI elements provided by the SAPUI5 framework. for example  Page,SimpleForm,Dialog,Input,

 

SAPUI5 Fragments:Fragments are the pieces of UI just like SAPUI5 Views. Whenever we need to use some similar UI parts many times in our application/views we create Fragments of those UI parts because Fragments are reusable and are light weight compared to VIews and Controls. Fragments are stored with in the application itself and can be used by that application only. Fragments are defined as View only and calling Views controller is shared with Fragment as Fragments are not having their own controllers.

 

I have written another blog for reusing UI elements with fragments for more details:

Click Here

 

SAPUI5 Components:  SAPui5 Components and Fragments are similar but components are reusable and INDEPENDANT parts used in SAPUI5 Applications. An SAPUI5 applications can use components stored on some other locations from where applications is running
Note : Components concept is under development so its advisable not to use it because it may change completely in future(see below image).

Component.JPG

I hope above information cleares all doubts 

 

Regards,

Rauf

Setting up River RDE with On-Premise System

$
0
0

Hi Friends,

 

I set up my River RDE with my on premise Gateway Server and wanted to share this experience. I see several videos on working with RDE, but did not find an end to end guide on setting up RDE to communicate with my On Premise system; so thought of creating a video around it.

 

Part 1: Gives an Overview of what we are going to do. A little about Cloud Connector and the landscape in question is explained here.

 

 

 

Part 2: Here we will set up Hana Cloud Connector and expose Gateway Server with paths for oData service and UI5 repository.

 

 

 

Part 3: In this part we set up our Cloud account with Subscription to RDE and destinations to connect to exposed resources in Gateway server.

 

 

Hope it is useful.

 

Thanks for reading and watching!

Krishna

Creating a reusable UI5 tile control – SAPUI5 control design on the fly

$
0
0

Introduction


It is always very difficult to follow only the standard controls given by SAP when we are developing a UI5 page. Sometimes we may need to have our own controls which are not available in UI5 library . One of such controls is a tile container which looks like a KPI tile. Here, in this blog, i am trying to explain how we can create a custom tile container which can be used in desktop UI5 dashboards as well as custom FIORI applications .


What we are trying to achieve ?


Nothing to speak about what we are going to create . sometimes, screenshots speak more than words

TileOverview.png

Just a box with little shadow in its borders, a title bar and a content pane where we can place our tile content.

 

What are required for the control

 

     To create such a control all we need is some HTML coding and CSS entries . Below is the CSS code which I used to create this box

 

 

 

.box {      text-align: left;
background: white;
width: 97%;
border: 1px solid #D4D4D4;
-moz-box-shadow: rgba(0,0,0,0.55) 0px 0px 10px;
-webkit-box-shadow: rgba(0,0,0,0.55) 0px 0px 10px;
box-shadow: rgba(0,0,0,0.55) 0px 0px 10px;
border-radius: 20px;
margin-top : 8px;
margin-left : 5px;    }

(thanks to w3schools for the css)

 

How to create the control on the fly

 

     SAPUI5 provides us the provision to extend any of the existing controls or create one your own. All the controls which we are seeing in the UI are extended(or inherited) from the base component called Control (sap.ui.core.Control) . So , when we are creating a control , we are supposed to extend the Control base component.

 

     Next step is to understand what are the properties and aggregations (and events also, if any) of the control. Here in our case, it is having one property, which is the title text(id property will be inherited from Control by default, no worries).Here , in our case, I am making the tile background colour dynamic.

 

sap.ui.core.Control.extend("CustomBox",{  metadata : {  properties : {  title : {type : "string"},  backgroundColor : {type : "string"}  },  aggregations: {             content: {singularName: "content"}          },

     The third and very important part is the renderer . A renderer function is supposed to render the UI5 metadata we define in our control to generate corresponding HTML tags in the run time . Keeping the fact in mind that neither JavaScript nor XML can visualize control in your screen, but just HTML can.

     No more stories, we will directly go to the coding part

renderer : {            render : function(oRm, oControl) {                oRm.write('<div');                oRm.writeControlData(oControl);                             oRm.addClass("box");                oRm.writeClasses();                oRm.addStyle("background", oControl.getBackgroundColor()+'")');                oRm.writeStyles();                oRm.write('>');                              if(oControl.getTitle() != null)                {                    oRm.write('<div class="title">');                    oRm.write(oControl.getTitle());                    oRm.write('</div>');                }                              var aChildren = oControl.getContent();                for (var i = 0; i < aChildren.length; i++) { // loop over all child Controls,                                                             // render the colored box around them                    oRm.write("<div>");                    oRm.renderControl(aChildren[i]);   // render the child Control                    oRm.write("</div>"); // end of the box around the respective child                }                                            oRm.write("</div>");            }

     It is mandatory to writeControlData method as it provides the id information to the div. This id caneither be passed manually or it will automatically be generated by the renderer itself. With out this statement, you can not dynamically update the tile content or title bar once it is set .

 

WriteClasses method would write the css class information if any into the associated div content.

 

WriteStyles method is capable of assigning or chainging css properties of the associated css class. In our case, box is the class which is having the property background . On the fly , we can change the background by assigning the background propery.

 

What you will get after the rendering

     Once the rendering is completed when we pass the control title and content , it will create the corresponding DOM objects in the HTML DOM tree.

 

Using the control in the view  :

 

var box = new CustomBox({  id : "osimple",  title : "On the fly Control"  }); 
box.addContent(chart());
return box;
}

where chart() function returns a bar chart with some data in it. You can implement the width property and additional css attributes as required .

Now , our UI5 tile would look like ,

 

usage.JPG

 

You can get more effects for the tile from : How to make a SAPUI5 Panel looks like a tile

 

Regards

 

Sreehari

SAPUI5 MasterDetail Screen App with Detail Screen as Splash Screen

$
0
0

Hello Everyone,

 

As we all know We can create Full Screen(Detail) And Split Screen(Master-Detail) application in SAPUI5. But there may be some scenarios where may require both App types in one single application.


For example we may require to show a full screen(Detail view) splash page before showing Split screen.

 

Before starting take a look at the followings:

 

  • Shell (sap.m.Shell) : The Shell control can be used as root element of applications, it can contain an App or SplitApp control. The Shell provides some overarching functionality for the overall application and takes care of visual adaptation, like a frame around the App, on desktop browser platforms.To be more specific it maintains one NavContainer.
  • App (sap.m.App) :App is the root element of a UI5 mobile application. It maintains only one screen at a time.
  • SpliApp (sap.m.SplitApp) : SplitApp is another root element of a UI5 mobile application besides App control. It maintains two screens based upond the device(table or phone).To be more specific it maintains two NavContainers.

 

Now lets return to the example application :

 

1. Create Splash Screen View

2. Create Master View

3. Create Detail View

4. In Splash Screen View controller onInit() set a timer function for the splash screen.

 

oController = this;      this.myVar = setInterval(function(){oController.myTimer();},5000);

 

5. Add myTimer() function in Splash Screen View:

 

myTimer : function(){           //Remove sap.m.App(Splash Screen) from Shell first           sap.ui.getCore().byId("Shell").destroyApp();           //Stop Timer           clearInterval(this.myVar);           // Create Split App now           this.app = new sap.m.SplitApp();           // load the master page           var master = sap.ui.xmlview("firstView", "view.firstView");           this.app.addPage(master, true);           // load the empty page           var detail = sap.ui.xmlview("secondView", "view.secondView");           this.app.addPage(detail, false);           //Add sap.m.SplitApp to Shell now           sap.ui.getCore().byId("Shell").setApp(this.app);     },

Its Done !

 

As 'myTimer' Function executes Splash Screen is Removed from Application and SplitApp is loaded on the screen

 

I hope this help

 

Regards,

Rauf

Creating A Fiori Like Application With Custom Style Sheets

$
0
0

Hi All,

        In this blog i am trying to share my attempt in creating a Custom UI5 Application following a Fiori application design guidelines.As shown in a previous article of mine(Creating A Fiori UI5 Application Using Fragments ).I will explain how i created a Flight booking application template application.On my next blog i will integrate the same application with Odata to make it a fully working UI5 Fiori application.I am using fragment concept in my below application which is already explained in the provided link above.

 

1)Creating a new UI5 mobile application in eclipse.

Capture1.PNG

Here i am going to make a sap mobile UI5 application.So i will be selecting the sap.m library for my project

Capture2.PNG

Give the name of the main view of your application and select the Development Paradigm(I have selected XML view because all the apps in Fiori Wave 2 has been developed on XML views,even the wave 1 application codes are ported to XML coding)Capture3.PNG

2)Create the necessary views for the fiori application.Here i am making a Split App design which makes use of the "sap.m.SplitApp" control in UI5.This app basically has a Master View and a Detail view.

 

  In addition to the two views mentioned above,There will be two more additional files which needs to be created

 

  i)Component.js - In a fiori based application instead of "index.html" fiori application always invokes the Component.js by default,this is a design standard for       every fiori applications.

 

  ii)App.view.js - this js file will create the required Split App control on load of the application

 

Capture4.PNG

Entire Hierarchy of my project can be seen in the below screenshot

Capture30.PNG

i) Component.js


    In component.js we will write the code to detect the device type whether its a desktop or a mobile device.This is essential to hide the Split App's Master view by default if the screen size is small.This component.js will be extending the control sap.ui.core.UIComponent as shown in the below screenshot

 

Capture5.PNG

 

In the below screenshot you can see the code to detect the device Model. Based on whether its a phone or desktop browser,I am hiding the Master Page.

 

Similarly i am declaring the language support files for maintaining multiple language support for my application.More details on language support in Fiori applications can be found in this discussion (SAPUI5 and the arabic language)

 

I am also setting the mock.json file which will be used to bind to the Tile container to define the Types of the tiles and the text to be shown in each tile.Capture6.PNG

jQuery.sap.declare("sap.ui.demo.myFiori.Component");
jQuery.sap.require("sap.m.routing.RouteMatchedHandler");
sap.ui.core.UIComponent.extend("sap.ui.demo.myFiori.Component", {  createContent : function() {
//alert("component");  // create root view  var oView = sap.ui.view({  id : "app",  viewName : "sap.ui.demo.myFiori.view.App",  type : "JS",  viewData : { component : this }  });  // set device model  var deviceModel = new sap.ui.model.json.JSONModel({  isPhone : sap.ui.Device.system.phone,  isNoPhone : !sap.ui.Device.system.phone,  listMode : (sap.ui.Device.system.phone) ? "None" : "SingleSelectMaster",  listItemType : (sap.ui.Device.system.phone) ? "Active" : "Inactive"  });  deviceModel.setDefaultBindingMode("OneWay");  oView.setModel(deviceModel, "device");  //debugger
//alert("oView created");  var langModel = new sap.ui.model.resource.ResourceModel({  bundleUrl : "i18n/messageBundle.properties"  });  oView.setModel(langModel,"i18n");  // Set the model
// var url = "proxy/http/zmetdc00.wdf.sap.corp:55080/sap/opu/odata/IWBEP/GWDEMO/";
// var oModel = new sap.ui.model.odata.ODataModel(url, true);
// oView.setModel(oModel);  oModel = new sap.ui.model.json.JSONModel("model/mock.json");  oView.setModel(oModel);  //alert("oView returned");  return oView;  }
});


ii) App.view.js

 

In this Javascript file i am basically creating an app and inserting a SplitApp control into that app using the following code.

this.app = new sap.m.SplitApp().setMode(sap.m.SplitAppMode.HideMode);

 

Also i am specifying the property of the split app to hide the Master View by default (sap.m.SplitAppMode.HideMode).You can remove that property if you wish to keep the Master page expanded in desktop browser by default.

 

Then i am declaring my Master and Detail view page and adding it the app as shown in the below screenshot

Capture7.PNG

sap.ui.jsview("sap.ui.demo.myFiori.view.App", {  getControllerName: function () {  return "sap.ui.demo.myFiori.view.App";  },  createContent: function (oController) {  //alert("app started");  // to avoid scroll bars on desktop the root view must be set to block display  this.setDisplayBlock(true);  // create app  //this.app = new sap.m.App();  this.app = new sap.m.SplitApp().setMode(sap.m.SplitAppMode.HideMode);  // load the master page  var master = sap.ui.xmlview("Master", "sap.ui.demo.myFiori.view.Master");  master.getController().nav = this.getController();  this.app.addPage(master, true); // true means this is the master page  // load the detail page  var detail = sap.ui.xmlview("Detail", "sap.ui.demo.myFiori.view.Detail");  detail.getController().nav = this.getController();  this.app.addPage(detail, false);  // done  return this.app;  }
});


App.controller.js



sap.ui.controller("sap.ui.demo.myFiori.view.App", {  /**  * Navigates to another page  * @param {string} pageId The id of the next page  * @param {sap.ui.model.Context} context The data context to be applied to the next page (optional)  */  to : function (pageId, context) {  var app = this.getView().app;  // load page on demand  var master = ("Master" === pageId);  //alert(master);  if (app.getPage(pageId, master) === null) {  var page = sap.ui.view({  id : pageId,  viewName : "sap.ui.demo.myFiori.view." + pageId,  type : "XML"  });  //  page.getController().nav = this;  app.addPage(page, master);  jQuery.sap.log.info("app controller > loaded page: " + pageId);  }  // show the page  app.to(pageId);  // set data context on the page  if (context) {  var page = app.getPage(pageId);  page.setBindingContext(context);  }  },  /**  * Navigates back to a previous page  * @param {string} pageId The id of the next page  */  back : function (pageId) {  this.getView().app.backToPage(pageId);  }
});

Now we will look into the codes of MasterView and DetailView


MasterView.xml (The  details about the line 14 in the below code is being explained in my previous article about fragments,then link to that is mentioned at the begining of this blog)

 

 

<core:View controllerName="sap.ui.demo.myFiori.view.Master"  xmlns="sap.m" xmlns:core="sap.ui.core">  <Page title="{i18n>MasterTitle}">  <subHeader><Bar><contentLeft><SearchField
search="handleSearch"
width="100%" ></SearchField></contentLeft></Bar></subHeader>  <core:Fragment fragmentName="sap.ui.demo.myFiori.Fragments.Sidepanel" type="XML" />  </Page></core:View>

 

 

Detail.View.xml

 

 

 

<core:View  controllerName="sap.ui.demo.myFiori.view.Detail"  xmlns="sap.m"  xmlns:layout="sap.ui.layout"  xmlns:core="sap.ui.core" ><Page title="{i18n>DetailTitle}"      showNavButton="{device>/isPhone}"   navButtonPress="handleNavButtonPress">  <subHeader>  <Bar>  <contentRight>  <Button id="user" icon="sap-icon://account" press="handlePopoverPress" ></Button>  </contentRight></Bar>  </subHeader><layout:Grid defaultSpan="L12 M6 S12" hSpacing="1">  <layout:content><VBox><core:Fragment fragmentName="sap.ui.demo.myFiori.Fragments.MainContent" type="XML" /><HBox><Image src="Images/line.png"></Image></HBox>  <NavContainer id="navCon2" width="60em" height="43em">  <core:Fragment fragmentName="sap.ui.demo.myFiori.Fragments.Tiles" type="XML" />  </NavContainer></VBox>    </layout:content></layout:Grid><footer>  <core:Fragment fragmentName="sap.ui.demo.myFiori.Fragments.Footer"  type="XML" />  </footer></Page></core:View>

 

Detail.controller.js (This controller file for the Detail.View page handles the Popup controls,Tile interactions etc as shown in the final output of this UI5 applications towards the end of this blog)

 

jQuery.sap.require("sap.ui.demo.myFiori.util.Formatter");
sap.ui.controller("sap.ui.demo.myFiori.view.Detail", {  handleNavButtonPress : function (evt) {  this.nav.back("Master");  },  onAlert : function (){  alert("Alert Box");  },  closeButton:function(oEvent) {  oEvent.getSource().getParent().close();  },  openDialog: function (Msg) {  if (!this[Msg]) {  this[Msg] = sap.ui.xmlfragment("sap.ui.demo.myFiori.Fragments.Popup",this );// associate controller with the fragment  }  //this[Msg].bindElement("/ProductCollection/0");  this[Msg].open();  },  openDialog1: function (Msg) {  if (!this[Msg]) {  this[Msg] = sap.ui.xmlfragment(  "sap.ui.demo.myFiori.Fragments.MsgDialog",this // associate controller with the fragment  );  }
// this[Msg].bindElement("/ProductCollection/0");  this[Msg].open();  },  onMsgDialogPress: function (oEvent) {  this.openDialog('Std');  },  onDialogCloseButton: function (oEvent) {  oEvent.getSource().getParent().close();  },  onDialogokButton: function (oEvent) {  var msg = 'Pop Up Closed';  sap.m.MessageToast.show(msg);  oEvent.getSource().getParent().close();  },  onInit : function (evt) {     // set explored app's demo model on this sample
//    var oModel = new sap.ui.model.json.JSONModel("resource/products.json");
//    this.getView().setModel(oModel);   },   onExit : function () {     if (this._oPopover) {       this._oPopover.destroy();     }   },   handlePopoverPress: function (oEvent) {     if (! this._oPopover) {       this._oPopover = sap.ui.xmlfragment("sap.ui.demo.myFiori.Fragments.Popover", this);     }     this._oPopover.setModel(this.getView().getModel());
//    this._oPopover.bindElement("/ProductCollection/0");     this._oPopover.openBy(oEvent.getSource());   },   handleEmailPress: function (oEvent) {     this._oPopover.close();     jQuery.sap.require("sap.m.MessageToast");     sap.m.MessageToast.show("E-Mail has been sent to bince");   },   handleLogOff: function (oEvent) {     this._oPopover.close();     jQuery.sap.require("sap.m.MessageToast");     sap.m.MessageToast.show("Logged Off Succefully");   },   handleEditPress : function (evt) {     var oTileContainer = this.getView().byId("container");     var newValue = ! oTileContainer.getEditable();     oTileContainer.setEditable(newValue);     evt.getSource().setText(newValue ? "Done" : "Edit");   },   handleTileDelete : function (evt) {     var tile = evt.getParameter("tile");     evt.getSource().removeTile(tile);   },
});


Now a custom style sheet is being declared for some hovering effects in my application.

 

 

Custom.css (I have added an animate custom code inorder to animate a jpg file in a popup.The screenshots can be found at the bottom of the blog)

.table_hover and .list_hover is used to give a custom hovering effect on mouseover of rows of the table and list.

 

Capture32.png

 

 

.animate_icon {    border: 3px solid #999;    -webkit-border-radius: 30px;    height: 18px;    width: 18px;    position: absolute;    left:90px;    top:80px;    -webkit-animation: pulsate 1s ease-out;    -webkit-animation-iteration-count: infinite;    opacity: 0.0
}
@-webkit-keyframes pulsate {    0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}    50% {opacity: 1.0;}    100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
}

 

To assign the hovering effect to the Table or List use the following format as shown in the screenshot


Capture33.PNG


The custom css file which i have created now has to be called during runtime of the UI5 application.So we need to make the index.html file to call the custom css file.Which can be achieved by using the code


<link type="text/css" rel="stylesheet" href="Css/custom.css" />



<!DOCTYPE html><html>  <head>  <meta http-equiv="X-UA-Compatible" content="IE=edge" />  <meta charset="UTF-8">        <link type="text/ccss" rel="stylesheet" href="Css/style.css" />        <link type="text/css" rel="stylesheet" href="Css/custom.css" />  <title>My Fiori 0</title>  <script  id="sap-ui-bootstrap"  src="resources/sap-ui-core.js"  data-sap-ui-theme="sap_bluecrystal"  data-sap-ui-libs="sap.m"  data-sap-ui-xx-bindingSyntax="complex"  data-sap-ui-resourceroots='{  "sap.ui.demo.myFiori": "./"  }' >  </script>  <script>  new sap.m.Shell({  app : new sap.ui.core.ComponentContainer({  name : "sap.ui.demo.myFiori"  })  }).placeAt("content");  </script>  </head>  <body class="sapUiBody" id="content">  </body></html>

 

Mock Json files is being used for dummy datas

 

mock.json (This mock.json file is used to define the Tile types and load the contents of the tiles shown in the screenshots,the mock json file is binded to the view in the Component.js file)


Capture34.PNG

 

 

{  "My_Tile_Data": [  {  "Name":"Bince Mathew",  "CreatedByBp": "Bince",  "ChangedByName": "Bince",  "Email": "bincemathew@gmail.com",  "TileCollection" : [    {      "icon" : "sap-icon://flight",      "title" : "Flights Available ",      "info" : "Saudi Airlines",      "infoState" : "Best Rates"    },    {      "icon" : "sap-icon://employee",      "title" : "My Bookings ",      "info" : "Booking Status",      "infoState" : "Check Your Ticket Status"    },    {      "icon" : "sap-icon://employee",      "title" : "My Bookings ",      "info" : "Booking Status",      "infoState" : "Check Your Ticket Status"    },    {      "icon" : "sap-icon://employee",      "title" : "My Bookings ",      "info" : "Booking Status",      "infoState" : "Check Your Ticket Status"    },    {      "icon" : "sap-icon://employee",      "title" : "My Bookings ",      "info" : "Booking Status",      "infoState" : "Check Your Ticket Status"    }      ] ,  "TileCollection_Standard" : [  {  "icon" : "flight",  "number" : "1",  "numberUnit" : "Flights",  "title" : "Flights Available",  "info" : "Departing in next 12 Hours"  },  {  "icon" : "inbox",  "number" : "3",  "title" : "Ticket Status",  "info" : "Waiting List",  "infoState" : "Error"  },  {  "type" : "Create",  "icon" : "calendar",  "title" : "Book Tickets",  "info" : "Seats Available",  "infoState" : "Success"  },  {  "icon" : "loan",  "number" : "180",  "numberUnit" : "euro",  "title" : "Refund Tickets",  "info" : "1 day ago"  },  {  "icon" : "loan",  "number" : "2500",  "numberUnit" : "euro",  "title" : "My Wallet",  "info" : "6 Transactions"  },  {  "icon" : "inbox",  "type" : "Monitor",  "title" : "Saved Tickets"  },  {  "icon" : "meal",  "type" : "Monitor",  "title" : "Food"  },  {  "icon" : "stethoscope",  "number" : "",  "title" : "Travel Insurance",  "info" : "Expired",  "infoState" : "Error"  },  {  "icon" : "pie-chart",  "number" : "8",  "title" : "My Travels Overview",  "info" : "8 This month",  "infoState" : "Warning"  },  {  "icon" : "cart",  "number" : "",  "numberUnit" : "",  "title" : "Shop With Us",  "info" : "Over 2000 items",  "infoState" : "Success"  },  {  "icon" : "factory",  "number" : "8",  "numberUnit" : "Services",  "title" : "Other Services",  "info" : "",  "infoState" : ""  },  {  "icon" : "calendar",  "title" : "Travel Planner"  }  ]  }  ]
}


Fragment Codes ( All the codes used in each fragments is listed below)


Footer.fragment.xml

 

<core:FragmentDefinition xmlns="sap.m"  xmlns:core="sap.ui.core"  controllerName="sap.ui.demo.myFiori.view.Detail">  <Bar>  <contentRight>  <Button text="Edit" press="handleEditPress" />  <Button text="Alert Box" press="onAlert" />  <Button text="Open Popup" icon="sap-icon://notes" press="onMsgDialogPress" />  <Button text="Dynamic Icons" icon="sap-icon://create"  press="openDialog1" />  </contentRight>  </Bar></core:FragmentDefinition>

 

MainContent.fragment.xml


<core:FragmentDefinition xmlns="sap.m"  xmlns:core="sap.ui.core"  controllerName="sap.ui.demo.myFiori.view.Detail"><List id="Menu" headerText="" ><items><ActionListItem title="Flights" text="Book Flights" class="list_hover"/><ActionListItem title="My Bookings" text="My Bookings" class="list_hover"/><ActionListItem title="Status" text="Flight Status" class="list_hover"/><ActionListItem title="Refund" text="Refund Tickets" class="list_hover"/></items></List></core:FragmentDefinition>

MsgDialog.fragment.xml

 

<core:FragmentDefinition xmlns="sap.m"  xmlns:core="sap.ui.core">  <Dialog title="Dynamic Icons" class="sapUiPopupWithPadding" contentWidth="0em"  contentHeight="10em">  <Page showHeader="false">  <content>  <Image src="Images/Fiori.jpg" width="25em" height="9em"  densityAware="false" align="right" />  <Image class="animate_icon" src="Images/heart.png" width="2em"  height="2em" densityAware="false" />  </content>  </Page>  <beginButton>  <Button type="Accept" text="Accept" press="closeButton">  <layoutData>  <FlexItemData growFactor="1" />  </layoutData>  </Button>  </beginButton>  </Dialog></core:FragmentDefinition>

 

Popover.fragment.xml

 

<core:FragmentDefinition  xmlns="sap.m"  xmlns:core="sap.ui.core"><Popover    title="Bince"    class="sapUiPopupWithPadding"    placement="Left" ><Image src="Images/bince.jpg" width="10em" height="10em" densityAware="false" />    <footer>      <Bar>      <contentLeft><Button            text="Profile"/>        </contentLeft>        <contentMiddle>          <Button            text=""            icon="sap-icon://email"            press="handleEmailPress" />        </contentMiddle>        <contentRight>        <Button text="Logout" press="handleLogOff" type="Reject"></Button>        </contentRight>      </Bar>    </footer>  </Popover></core:FragmentDefinition>

 

Popup.fragment.xml

 

<core:FragmentDefinition xmlns="sap.m"  xmlns:core="sap.ui.core"  controllerName="sap.ui.demo.myFiori.view.Notes">  <Dialog title="My Popup" type="Message">  <VBox >  <items>  <Label text="Comments" />            <TextArea width="100%" height="100%"></TextArea>  </items>  </VBox>  <beginButton>  <Button text="Ok" press="onDialogokButton" />  </beginButton>  <endButton>  <Button text="Cancel" press="onDialogCloseButton" />  </endButton>  </Dialog></core:FragmentDefinition>

 

Sidepanel.fragment.xml

 

<core:FragmentDefinition xmlns="sap.m"  xmlns:core="sap.ui.core"  controllerName="sap.ui.demo.myFiori.view.Detail"><List id="User_Settings" headerText=""><items><ActionListItem title="Settings" text="My Account Details" class="list_hover"/><ActionListItem title="Profile"  text="View Profile" class="list_hover"/><ActionListItem title="Payment"  text="Add A Payment Method" class="list_hover"/><ActionListItem title="History"  text="My Booking History" class="list_hover"/><ActionListItem title="Cancel"   text="Ticket Cancellation" class="list_hover"/><ActionListItem title="Stay"     text="Book Accomodation" class="list_hover"/><ActionListItem title="Services" text="Platinum User Services"  class="list_hover"/><ActionListItem title="Reports"  text="My Travel Analytics"     class="list_hover"/></items></List></core:FragmentDefinition>

 

Tiles.fragment.xml

 

<core:FragmentDefinition xmlns:core="sap.ui.core"  xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="view.search"  xmlns:html="http://www.w3.org/1999/xhtml">  <Page  id="r1" showHeader="false" enableScrolling="false"><!-- <Label text="My Flight" class ="content7"/> -->  <TileContainer id="container"  class ="content8"  tiles="{/My_Tile_Data/0/TileCollection_Standard}"><StandardTile        icon="sap-icon://{icon}"        type="{type}"        number="{number}"        numberUnit="{numberUnit}"        title="{title}"        info="{info}"        infoState="{infoState}" />  </TileContainer>  </Page></core:FragmentDefinition>

 

In addition to these we can also create custom controls like a button or panel from scratch and use it a new UI control in our applications.

It basically involves two main parts.

  1. Extending the sap.ui.core.Control to define the metadata of the new control you are trying to build with its own custom properties,aggregations  and events.
  2. Using a renderer to render your final custom control using the metadata you have defined.

 

Capture35.PNG

More detailed article about creating a custom control can be found in the following link Creating a reusable UI5 tile control – SAPUI5 control design on the fly



Final UI5 Application Outputs

Capture23.PNG

Capture24.PNG

Capture25.PNG

Capture26.PNG

Capture27.png

Capture28.PNG

Capture29.PNG

Regards,

Bince Mathew C


Login page for custom sapui5 applications

$
0
0

Hello friends, In this blog I am sharing my experience with Login page requirements in SAP Fiori custom development. we have created a SAPUI5 application and added it in Launchpage ( Yes it is Launchpage not Launchpad ). Things were running great. Everything was fine as per the Fiori flow.

 

Login >> Tile Catalog >> Application

 

One day our client asked us to remove the middle interface of Tile Catalog from the flow. They wanted us to bring the user directly on application view instead of Tile Catalog after successful Login.

 

They also wanted to change the Login page background and company logo.

 

For first requirement we thought of creating a custom login page and manage everything by calling methods of standard login class or create a Z solution to mange login if possible. Now if we are doing so, we have to provide a solution for Logoff also. I read many blogs related to login issues on SCN, so first decided to search on SCN then take a call for the best suited solution. For me SCN is always the first choice to solve any problem related to any kind of issue in SAP.

 

For second requirement we searched on SCN and found that ”/UI2/SRA_LOGIN” class will handle everything we just need to enhance the respective methods.

 

Meanwhile one of my colleague was reading the Extend SAP Fiori Applications (https://help.sap.com/saphelp_fiori/fiori10_extend_en.pdf) guide and he found something by which we can mange login page changes just by creating only a single properties file in our application. This was something new for me. I have never found any blog on SCN regarding this and didn’t go through configuration guide till the end . If you have any links related to Login screen enhancements using properties file, please share it in comments.

 

Now moving to the solution we decided for our custom SAPUI5 Application,One of our team member who is champ of sap portal , used his experience and gave a solution to use standard SAP Fiori login page for our application without writing a single line of code or any custom login page. We manged the login page changes as per the solution given in the extened guide. For Logoff, we created a button in our application to call the logoff method of shell.

 

Steps followed:

 

Requirement #1: SAP Fiori Login page for custom application

 

  • Go to transaction SICF
  • Search for your service name (BSP Directory Name )

 

1.png

 

 

  • Under the UI5_UI5/Sap node double click on application

 

2.png

 

  • Click on the edit button
  • Go to Logon Data tab

 

3.png

 

  • Select “Alternative Logon Procedure” in Logon procedure dropdown (as per the SAP documentation by choosing this option we can change the sequence of the procedures or remove individual one).
  • Now click on Error Pages tab and select the Logoff page Tab

 

4.png

  • Here you can change the redirect URL on logoff ( When user press the logoff button in your application)
  • Now select the Logon Errors tab under same Errors Pages tab


5.png

 

  • Select the System Logon radio button at the bottom to let the system handle/generate the error pages
  • Click on the Configuration Button

 

7.png

 

  • Here you can make changes as per your need
  • Click on save button in main window and save your service changes
  • Run your application in browser (use application url not launchpage/launchpad url)
  • You can see the Fiori Login page



Requirement #2:Change Login page Background and Logo


Create a login.properties file as shown in below image and add it to your BSP directory or in your application WebContent Folder. Please read more about Customizing Login Page at https://help.sap.com/saphelp_fiori/fiori10_extend_en.pdf ( 4.1 )


8.png


Requirement #3:Logoff button


We provided a logoff button in our application which triggers the logoff event of shell. Please see the code below.


new sap.m.Button("btnLogoff",                  {icon:"sap-icon://log",                    press:function()                    {                                     var shell = sap.ui.getCore().byId("mainShell");                     shell.attachLogout(function()                      {                           jQuery.ajax({url:"http://server:8000/sap/public/bc/icf/logoff",                                       async:false}).complete(function (){location.reload();                                      });                                });                    shell.fireLogout();                   }                })

If you have any suggestions or if you find something wrong in above blog, please share your comments.

 

Happy Learning

 

 

Regards,

Krishnakant Joshi

Hands-on video tutorials for SAP River Rapid Development Environment

$
0
0

Hi,

 

You likely already heard about SAP River Rapid Development Environment (RDE) and how it helps you accelerate development of HTML5/UI5 applications and facilitate extension & customization of SAP Fiori apps?

 

The SAP HANA Academy produce hands-on video tutorials - and we’ve got SAP River RDE fully covered with over 2 hours of content!

 

Here's the main playlist: SAP River Rapid Development Environment

 

Tutorials range from getting started & connecting to back-end systems - to creating UI5 mobile apps - to extending SAP Fiori apps like HCM Timesheet Approvals & Sales Order Tracking. Also covered are different ways to run apps from SAP River RDE including offline access via the "mock data" capability, and how to build and deploy apps in conjunction with SAP HANA Cloud Platform.

 

Here are direct links to all of the videos published so far:

 

Each tutorial is accompanied by code snippets where relevant and you'll find the github link in the main playlist description - or you can get there directly via: saphanaacademy/RDE


Your feedback is most welcome – in the YouTube comments section, below, tweet me @pmugglestone or mailto:HanaAcademy@sap.com.


Philip

Understanding SAP Fiori Webinar - The Director's Cut

$
0
0

Yesterday Brenton OCallaghan and I hosted a public webinar "Understanding SAP Fiori", which was well attended and also a lot of fun to do. There was never going to be enough time to cover all the stuff we wanted to, so today we sat down together and followed up on what we covered in the webinar.

 

We recorded it as a Google+ Hangout and published it on YouTube.

 

Here are some of the things that we covered:

 

  • SAP Fiori transactional app design
  • master detail patterns with responsive containers
  • the structure of a transactional app
  • components, with routing and the visible control
  • the responsive container and its aggregations
  • semantic colours for Buttons and other controls
  • responsive design and the demandPopin property
  • the SplitApp modes
  • examining the S2 and S3 views
  • extension points

 

plus

 

  • a small update* to the SAP Fiori App Analysis app to link to the official SAP docu for each app

 

*this update is currently still in a git branch local to my laptop :-)

 

It was a fun 30+ minutes, we hope you enjoy it too!

 

 

Bluefin Solutions - Understanding SAP Fiori Webinar Followup

Build SAPUI5 Cordova Barcode Scanner with OData Service

$
0
0

I would like to share how easily to integrate the Cordova barcode-scanner plugin with the SAPUI5 app and connect to the OData back-end service to retrieve the material number and description.

 

We will deploy the SAPUI5 app on the Android and use it to scan the barcode label. Once the barcode label is recognized, we pass it to the OData request to get the description of the material number.

 

The app screenshots will look like as below:

1403304389495.jpg1403304401680.jpg1403304411030.jpg

 

Required Components

 

OData Service


I am using the customized OData service ZGW_MATERIAL_SRV that is calling the BAPI_MATERIAL_GET_DETAIL with material number as an input. You may refer to other blog how to setup the OData service.

3.jpg

 

Execute http://sapgatewayserver.com/sap/opu/odata/sap/ZGW_MATERIAL_SRV/Materials('<material_number>) in the Chrome browser to get the input.

The sapgatewayserver.com is your SAP Netweaver Gateway server and the material number, for my case is 0009620-081.

 

The OData output format will look like as per below screenshot:

1.jpg

Barcode Scanner Function


The doScan method performs the barcode scanning. It is calling the cordova plugin barcodeScanner to get the barcode number in result.text. Then pass this parameter to the OData query string to perform the OData query. The response  (i.e., response.data.Material& response.data.MatlDesc) will be captured and printed in the scanresult page.

 

doScan: function() {  cordova.plugins.barcodeScanner.scan(  function (result) {  jQuery.sap.require("sap.ui.model.odata.datajs");  var sUrl = "http://sapgatewayserver.com/sap/opu/odata/sap/ZGW_MATERIAL_SRV";  var oModel = new sap.ui.model.odata.ODataModel(sUrl, true, "username", "password");  oModel.read(  "/Materials('" + result.text + "')",  null,  null,  true,  function(oData, response) {  console.log(response.data.Material);  var oMatID = []; var oMatDescr=[];  oMatID.push(response.data.Material);  oMatDescr.push(response.data.MatlDesc);  var data = [];  for(var i = 0; i < oMatID.length; i++) {  data.push({"MatID": oMatID[i], "MatDescr": oMatDescr[i]});  }  var oModel1 = new sap.ui.model.json.JSONModel({ "zgwmat": data });  sap.ui.getCore().setModel(oModel1, "zgwmatmodel");  var bus = sap.ui.getCore().getEventBus();  bus.publish("nav", "to", {  id : "scanresult",  });  },  function (err) {              alert("Error in Get -- Request " + err.response.body);                  console.log(err.response.body);             }  );       },     function (error) {        alert("Scanning failed: " + error);    }  );  },

The complete source code is available in the Github: https://github.com/ferrygun/SAPUI5CordovaBarcodeScanner


Create Cordova Project

 

Make a folder programs in your C:\ drive and create the cordova project by executing the following command:

 

  • cordova create C:\programs\barcodeScanner com.enterprisemobility.barcodeScanner barcodeScanner
  • cd barcodeScanner
  • cordova platform add android

 

Then copy all your files (except META-INF and WEB-INF) in Eclipse barcode-scanner WebContent folder to C:\programs\barcodeScanner\www

6.jpg

The final structure in C:\programs\barcodeScanner\www will be like this:

7.jpg


Build the Cordova Project

 

Execute the following command to build the cordova project under C:\programs\barcodeScanner

  • cordova build

 

If it's successful, you will get the debug APK file (barcodeScanner-debug.apk) in C:\programs\barcodeScanner\platforms\android\ant-build.

 

Copy this APK to your Android device to test the app.

 

Generate Barcode


Please visit the http://www.barcode-generator.org/ to generate the online barcode to test the app.


Select a barcode: Code 128, enter the barcode number 0009620-081 and click on Create Barcode.

5.jpg

 

You will get the following barcode image. Print it, we will use it to scan the barcode label using our app.

2.jpg

Demo Video

 

 

I hope you enjoy and successful implementing the barcode plugin with your SAPUI5 app. Please feel free to drop any comment/feedback.

 

Thanks for reading my blog.

How to configure an external GW system with SAP River RDE

$
0
0

Do you need to connect your SAP River RDE to an external GW system? Check hereafter how you can achieve this.

 

Let's suppose your want to use the OData services provided by the system sapes1.sapdevcenter.com. This is a public GW server: you can get more information and register to it by going to the page Getting started with the SAP Netweaver Gateway Service Consumption System

Since this is public, you can connect to it without using the HANA Cloud connector:

all you have to do is to create a new destination in the account.hanatrial.ondemand.com environment as follows:


 

ParameterValue
Name<your_destination_name>
TypeHTTP
Description<your_destination_description>
URLhttps://sapes1.sapdevcenter.com:443/sap/opu/odata
Proxy TypeInternet
Cloud Connector version2
AuthenticationNoAuthentication

 

Add also the following additional properties:



ParameterValue
RDEEnabledtrue
RDESystemES1
RDEUsageodata_abap
TrustAlltrue

 

You should get something like this:

ss.jpg

 

There are two things which you need to pay special attention to:

1) do not forget to put the port number 443 in the URL string for this server, because, currently, it's not automatically inherited by the system from the protocol type.

2) do not forget to specify the additional property TrustAll = true. This will allow you to avoid using the certificate keystore for this destination, even though it will reduce the overall security.

 

 

That's all!

Viewing all 789 articles
Browse latest View live




Latest Images