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

SAPUI5 using Shell

$
0
0

Backround

SAPUI5 is a latest User Interface(UI) technology by SAP based on HTML5, which is used to build lightweight client applications. The important factor in the success of SAPUI5 is, it uses and supports open source such as CSS, jQuery, Javascript etc. Unlike WebdynPro's(Java/ABAP) which are server dependent, SAPUI5 runtime is a client side HTML5 rendering library, in which we can create applications for both Desktops and Mobiles. Going forward, SAP will recomend the use of SAPUI5 in all of its UI development.


Installation


We can develop and publish the SAPUI5 applications in Eclipse. Installation aand Configuration on SAPUI5 is very easy. Just follow the steps mentioned in this link.


Prerequisites


To be able to use this blog, you need to complete the installation steps and have a basic knowledge of Java, HTML, Javascript, and Eclipse.


Development


Step 1


Open Eclipse and create an SAPUI5 application project.




 

 

We will create a desktop application, so select ui.commons.


Select create initial view check box and give name to the the view.



When we create a view, along with it the controller file also gets created.


xxxx.controller.js is the controller file

xxx.view.js is the view file.


Also an index.html file is created with the first view. This file is used to initialize the application.


Step 2


Create a destination view (Right click the project folder -> New -> Others -> View)




 

 

Give name to the file. Select finish.




Step 3

Now we need to initialize the view inside index.htmland add the required libraries.




Step 4

To navigate, we will use Shell control. Shell is an application frame with an navigation capability. We will add shell to the index.html file.



Add the desired view to the shell.




Step 5


We will define a model which will hold values at run time in  index.html




This is all we have to do in order to get everything in place. Important point to note here in this example is, the source view needs to be instantiated in the target view. Always!


Next step is simple. Add UI elements in the view, bind the model to the UI elements and navigate.


For complete solution, please follow the link


index.html 


https://drive.google.com/file/d/0B_is7beaY2bIOV9JMUxiSmFOSnc/edit?usp=sharing

 

First View

 

https://drive.google.com/file/d/0B_is7beaY2bIcFQxb1FXdmZfMjA/edit?usp=sharing


Result View


https://drive.google.com/file/d/0B_is7beaY2bIdFhZb3JkNFlNWnc/edit?usp=sharing


Output


Right click index.html and run as web preview.


 



 

 



Offline development of UI5 applications using The Mockserver

$
0
0

Motivation

There would be an oData service modeled before the developement phase, at least in an ideal world. We can then let our frontend ui5 developers use the mockserver instead of running oData service on SAP GW. The mockserver responds to all oData requests with some sample data, so our backend developers can feel free to experiment with SAP GW as much as they want and not to be afraid of stopping ui5 developers from work.

 

Using Mockserver

The mockserver can be found in library sap.ui.core.util.MockServer. The settings are quite simple, even though some mistake can take you hour(s) of debugging (like me).

  1. You need to include Mockserver's library.
  2. You need to prepare you metadata in xml file. You can use existing service, grab its metadata with $metadata command in gateway client like this you_service/ZSA_USERS_SRV/$metadata
  3. You need to prepare JSON sample data of your entities, you can use your_service/ZSA_USERS_SRV/UserSet?$format=application/json and delete metadata.

 

Critical part of code

    jQuery.sap.require("sap.ui.core.util.MockServer");    // Create mockserver    var oMockServer = new sap.ui.core.util.MockServer({        rootUri: "http://mymockserver/",    });                   oMockServer.simulate("model/metadata.xml", "model/");    oMockServer.start();    // setting up model    var oModel = new sap.ui.model.odata.ODataModel("http://mymockserver/", true);    oModel.setCountSupported(false);    sap.ui.getCore().setModel(oModel);

Running application

ui3.JPG

I used my example openui5 application that can manage(add, edit, delete) users and boosted it with mockserver.

 

You can try the application with mockserver by yourself here - http://pmarcely.github.io/mockserver.html

 

All the codes are also in my github:

 

 

Remarks

  1. It seems strange to me that metadata are in XML, while sample data in JSON, it would be smooth to work with one format.
  2. There are some error messages from mockserver in my application, even though it is working properly. If you know what it is wrong let me know.
  3. For more sophisticated usage you can check source code of application Cart in UI5 demo apps.

 

Hope you enjoy it!

Displaying Json in UI5 dynamically

$
0
0

Hello Everybody,

 

a couple of month ago I used Cesar’s  JSON Adapter to expose some data form function modules  as json. I wanted to test and display the different RFC’s and display their results using the same html page and ui5 javascript code.

 

The code ideally should be dynamic enough so that we could add/remove RFC Tables (Json data) or change and add elements to the RFC structure / json response. I also wanted to be able to consume other json service like Northwind or weather api calls  and display them using the same mechanics. To make the display of data easier; tables with just one row of data should be displayed transposed in two columns (Fieldname / Value) vs one long single row of data. Sometime there structures (in some RFC) are long and in most case these only return one how of data and then it is annoying to scroll to find the data.

 

Also export parameters which are display in the json response should be collected and displayed under one tab e.g EXPORTPARAMETER to make it easier to find them.

 

Below what i came up with ...have fun with it.

 

Here an example of a rfc json out put: json(p) data

Here JS Bin with the ui5 code

 

 

Reference:

Jsfillder: http://jsfiddle.net/8mkcyrw4/22/

or JS Bin

Github: https://github.com/markusvankempen/dynamictables

Test Url:http://sapui5.mybluemix.net/

Test Service Example:

http://sapui5.mybluemix.net/data0.jsonp

http://sapui5.mybluemix.net/data1.jsonp

http://services.odata.org/V3/Northwind/Northwind.svc/Orders?$format=json&$callback=getJSON

http://api.openweathermap.org/data/2.5/weather?q=Toronto&mode=json&units=metric&callback=getJSON

Json ABAP adapter

http://scn.sap.com/community/abap/connectivity/blog/2013/03/05/json-adapter-for-abap-function-modules

Facebook Friends List + UI5 + Hana Cloud Platform + RDE

$
0
0

Hi

 

Just bored of business scenarios, i was wondering how it would be to integrate UI5 app with social media Well, it has come out pretty cool & has been smoother when visualizing the data's from Facebook Graph API in UI5. It doesn't matter if it's facebook or twitter or any other social media, what matters is if the data is exposed in json or xml or odata then UI5 fits into it. This make me believe that UI5 apps are just not limited to business scenarios & it's limited to one own imagination. Meanwhile, i had a confusion in choosing where to host the app - Parse or Hana Cloud. I initially went with parse assuming it would be simple to deploy a fb app, as parse is a company acquired by facebook. After analysing the docs of parse, it needed a bit of time for me to carefully go through the docs to get started which i wasn't interested.

So switched back to Hana cloud platform, where i already have an account & a new HTML5 application can be deployed in minutes. But this time i wanted to get hands dirty with River RDE as i read few blogs about it. Amazingly, subscribing to RDE & getting a repo was just a cake walk. From there cloning the repo, committing the changes & deploying to cloud was just in a matter of clicks. It was a smoother & faster way of developing the app. The app i tried was about retrieving the friends details from user's account & visualize it in a splitapp of UI5 . You can find the live app running here,

 

https://ui5friendslist-c5193288trial.dispatcher.hanatrial.ondemand.com/


As a prerequisite to run the app, you would need a hanatrial account & fb account. Let me share few snaps of the app,


ui5app.JPG


mutual.JPG

 

 

git repo on hanatrial- https://git.hanatrial.ondemand.com/c5193288trial/ui5friendslist (not accessible directly)

 

Just do a pull request if you wanna commit your changes to the repo.

 

For a quick look on the code, created a repo in github - ikiw/ui5friendslist · GitHub

 

Regards

Sakthivel

UI5 Icon-Cheatsheet

$
0
0

As I'm constantly looking for Icons that I can use in my UI5 application I created a small website as an Icon Cheatsheet.

You can find it here: UI5 Icon Cheatsheet

 

It is a simple and small hobby-project but i think I will add more functions in the coming days and weeks.

2014-09-02 13_31_53-UI5 Icon Cheatsheet.png

Consuming Northwind(Odata) Service using SAPUI5 Mobile Template in RDE

$
0
0

Hi,

 

I would like to share something which I tried and I hope it helps someone. I tried to consume northwind Odata services using River RDE ( sapui5 template) and the steps are explained below.

  • In the Hana cloud Platform, add the following destination.

1.png

  • Create an SAPUI5 mobile template project.

2.png

  • After creating a project there will be a file inside the project named neo-app.json.

3.png

  • In neo-app.json, add the following code.

4.png

  • Add the following code where you want to consume the service .

5.png

UI5 Playground

$
0
0

In this post I would like to introduce UI5 Playground, which I hope will help UI5 developers as much as it has helped me throughout my projects revolving UI5 (SAPUI5/OpenUI5).

 

The project aims to make it easier to develop applications with UI5  by abstracting away many of the repetitive programming tasks related to MVC, routing, querying views/DOM, working with data, etc…, and offering solutions to common development scenarios in UI5.

It presents the topics discussed and presented in the TDG (The Definitive Guide) application and extends on them.



Why play?

Avoid CORS for RAD (rapid application development) in client


To start developing simply cmd from project root and run

$ grunt server

This project is built using "generator-sapui5". One of the really cool things you'll find in the grunt.js file is how to use "grunt-connect-proxy" for your local or CI flows inside "connect.proxies", approx. line 77.

The great thing about the connect-proxy is that you can work off a local web server and still talk 3rd party domains, as you would your application host.

Connect proxy for UI5Playground.png


This reverse proxying is very useful in development and continuous integration testing where you want to test your new client code against currently deployed services. it allows you to test against real services without deploying a server especially for testing.

In production it allows you great flexibility in that you can host the client and reverse proxy in one server and decide during request time where you'd like to proxy the requests from. This allows for true separation of client from server.

With this project we are using Node.js as the server with grunt-connect-proxy. In a later post I will address the benefits of using Node.js in development and CI, regardless of production environment. In production you can use the great open source component by SAP, cloud-connectivityproxyof you're using a Java server. In Apache there is the "mod_proxy" extension which implements this mechanism.

 

In this project there is also an experimental fall back method that is browser based (no server proxying) in the index file, line 27 there is a public CORS server request hijacker. This is of course for fun and hacking, I would not use this on a production app. If you're working with Bracketsor Webstorm you can just run index.html in browser (these IDEs spin up a local webserver to serve your web application) and it'll just work (accessing NorthWind OData). In fact when you run the project online from GitHub pages, the app will make use of corsproxy.com via the hijacker as I could not reverse proxy from Github. before highjacking the request to 3rd party domains we’re checking if the application host will also serve the 3rd party api calls, and upon failure we fallback to highjacking the requests from the browser.

 

Search OData


Things like searching on an OData bound list or table become as easy as (demo here). This is instrumented with pure OData, no search provider is applied.

 

oBinding = oList.getBinding("items"); 

oBinding.x_search(["Name","Description","Category/Name","Supplier/Name"],"cheese");

 

"x_search" makes use of another new function on the prototype, "x_addFilter". Filters added to the binding in this way are static, so you may filter the list further, like this for example with the view settings dialog, without losing your previous search query until you execute the same command with an empty query string.

 

oList.x_search(["..."],""); 

Avoid boilerplate code (redundant code)

 

Instead of this boilerplate for each controller in your application

 

sap.ui.core.mvc.Controller.extend("ui.demo.view.Detail",{ 

onInit :function(){ 

  var router = sap.ui.core.UIComponent.getRouterFor(this); 

  router.attachRouteMatched(this.onRouteMatched,this); 

  }, 

onRouteMatched :function(oEvent){ 

  var oParameters = oEvent.getParameters(); 

  if(oParameters.name !=="product"){ 

       return; 

  } 

// Route matched logic here 

} 

}); 

 

With the help of  "ui5lib.base.Controller" the above can be written as such:

 

ui5lib.Controller.extend("ui.demo.view.Detail",{ 

     onMyRouteMatched :function(oEvent){ 

       // Route matched logic here 

     } 

}); 


Get i18n texts


Using “ui5lib.base.Controller” use the following call to get the i18n bundle defined on your component.


oController.getText(key,params)


instead of


var sComponentId = sap.ui.core.Component.getOwnerIdFor(oController.getView());

var i18nBundle =  sap.ui.component(sComponentId).getModel("i18n").getResourceBundle();

i18nBundle.getText(key,params);


Use standard model inheritance for fragments and fragment-dialogs


You may have noticed that fragments and dialogs do not enjoy model inheritance like regular controls. And you might have run into a few hicks trying to use a component, while still having models on core (sap.ui.getCore()). The model inheritance is not straightforward in that dialogs do not inherit models and fragments on view within a component do not inherit models from core.


You can achieve straightforward model inheritance in one the following ways:


var oDialogFragment = sap.ui.jsfragment("testdata.fragments.JSFragmentDialog");

oDialogFragment.setModel(this.getView().getModel());

oDialogFragment.open();


or


var oDialogFragment = sap.ui.jsfragment("testdata.fragments.JSFragmentDialog");

this.getView().addDependent(oDialogFragment);

oDialogFragment.open();


Using “ui5lib.ui5x”, this becomes a simple call that will cater to fragments and dialog content, attaching them to the view of the Controller from which they are spawned.


var oDialogFragment = sap.ui.jsfragment("testdata.fragments.JSFragmentDialog", oController);


Data driven tiles UI and dynamic routing


One of the nice things in the UI5Playground app is that it implements a draft of dynamic routing in “MyRouter.js”. Meaning that if you use a sane file structure (in my opinion1,2), you get routing for free. you’ll notice I have only defined the initial route and the notfound route in my component.js, and yet routing works as expected from the tile and from the address bar or history. All of the demos presented in the Playground are routed by convention. It works nicely from hash-change and navigation events alike.


Note that if not used wisely this can impact performance (see performance issues and roadmap below).


This allows for great flexibility in demoing/testing features by just pasting a directory containing all of the files for that feature into the views directory (I often do this to tinker around with the code behind samples in the demokit). The dynamic routing will create a registred resource and the corresponding route on the fly. One thing to note is that naming convention required for dynamic routing to the resources inside your feature directory, “feature-dir-name.resourcename”. For example, “Product.Master” or “Product.ViewSettings” where “Product” is the name of the feature directory.


The reason I’m discussing data driven tiles with dynamic routing is that this encapsulates a pattern I think is important,

keep the client (web app) on a need to know basis.

The UI should be generated with only the information relevant to the current user. Now imagine you have a cloud application with multiple tenants or role based access and each has access to different features. With UI5 Playground the tiles a generated from JSON that can be rendered by a service, and there is no client file that suggests other features that may be available (routes config) such as the best practice presented in “The Definitive Guide

Now, you may argue that the routes config in the component.js can be rendered on server and you would be right, but in the interest of DRY, why repeat yourself in the routes config when you have already defined the root features available to your client for the initial view of the application.

A mixed approach may very well be the way go here in terms of DRY, SoC, and performance. use dynamic routing for all flat navigations from the root of your applications, perhaps one level more where it seems appropriate and render the rest of your routes from a service. Predefined routes are always used first, a dynamic route will only be attempted when there is no matching route for a given navigation.


Etc, etc

Some plumbing

If you’ve dived into the demo you may have noticed that the UI5 Playground uses another repository “ui5lib” intensively. In the SoC spirit the code in your application should only implement your unique business logic the rest should be handled by the framework UI5 or extensions (hence ui5lib). This is a collection of addon libraries and components to assist development of UI5 applications. Keep in mind this a work in progress, script tags in the HTML is not really the best way to consume web resources.


Oh, and

There are more helpers and extensions in ui5lib such as


  • JSONModel with detailed data changed events, delete and add record methods, etc…
  • Helpers like oElement.getBoundProperty() which returns
      var context = this.getBindingContext();
      returns context.oModel.getProperty(context.sPath+(!!sPath? ('/'+sPath): ''));
  • Prototypal extension of ODataListBinding to support static filters
  • More…


Notes

Please refer to the project page at Github

Roadmap

Please refer to the project page at Github

Less Coding, More Designing: The New SAP River RDE Layout Editor

$
0
0

As announced in the Release Notes for SAP River RDE, SAP River RDE 1.3 is now available on trial. This version comes with a nice new feature: The layout editor makes developing HTML5/SAPUI5 applications even faster and simpler for you!

 

And this is what it looks like:

1.png

As you can see, the layout editor has the following areas:

  • Palette: Contains the SAPUI5 controls. You can expand or collapse the sections by clicking the arrows, and dragging and dropping the controls to the canvas.
  • Canvas: The content of the XML view is displayed in a way that closely corresponds to how it will appear in your finished application.
  • Properties/Data pane: Shows the properties and data (entity sets and properties of the OData service used by the application) of a marked control.
  • Outline pane: Outline of your XML view (click the icon  in the right side bar to display it).

 

In the documentation of the SAP River RDE layout editor you can find a step-by-step tutorial that walks you through the major features the new layout editor offers. It guides you through the process of creating a SAP Fiori starter application and enriching it with additional controls in just a few minutes.

 

So without further ado, let’s just try it!


Before You Start


  1. Create the OData model file SalesOrderService_metadata.xml and store it locally on your computer. Copy the content of the XML file from the following document: OData Model for a Simple Sales Order Service
  2. In case you already worked with SAP River RDE with a former release, it’s advising to clear your browser cache before starting SAP River RDE. So open Google Chrome (the layout editor only runs in this browser) and clear the browser cache.
  3. Start SAP River RDE in Google Chrome.

 

Create an Application for Sales Order Tracking


  1. Choose File -> New -> Project
  2. On the Basic Information screen, enter the project name (e.g. SalesOrders) and choose Next.
  3. On the Select a Template screen, choose SAP Fiori Starter Application and choose Next.
  4. On the Data Connection screen, choose Browse. In the Open dialog, browse to your local SalesOrderService_metadata.xml file and choose Open. On the Data Connection screen choose Next.
  5. On the Template Customization screen, enter the following mapping data:

Master Section:

Field

Mapping Data

Title

Sales Orders

OData Collection

SalesOrders

Item Title

SalesOrderNumber

Numeric Attribute

TotalAmount

Units Attribute

Currency

Attribute 1

CustomerID

Attribute 2

CustomerName

Search Field

SalesOrderNumber

Detail Section:

Field

Mapping Data

Title

Sales Order

Detail Text

Sales Order Details

Item Title

CustomerName

Numeric Attribute

SalesOrderNumber

Units Attribute

CustomerID

Attribute 1

NetPriceAmount

Attribute 2

TaxAmount

Attribute 3

OrderDate

6. Choose Next.

7. On the Confirm screen, choose Finish.


Now the Exciting New Part: Edit Your Application with the Layout Editor


  1. Go to your new project, expand the view folder and select Detail.view.xml.
  2. Open the context menu; choose Open With -> Layout Editor.
  3. The Detail.view.xml opens up in a new tab with layout editor capabilities. By default, the Outline pane is closed. Although we only need it at the very end of our exercise, you might want to open it up by clicking the icon 2.png in the right side bar.
  4. Let’s start with something easy and delete the icon 3.png on the bottom bar: Select the control in the canvas and drag it outside of the canvas or press key Del.
  5. Since we want to adjust the icon tab bar, we first have to change some of the properties of the IconTabFilter control.
    1. In the canvas, select the icon of the tab filter.
      In the Outline pane, sap.m.IconTabFilter is selected.
    2. In the Properties/Data pane, expand the Properties.
    3. In the Data section, enter the value Hint to the field Key.

4.png

6. Next step is to add a new icon tab filter to the icon tab bar.

  1. In the palette, expand the Container section. Alternatively you can use the search field and search for example for filter or tab.
  2. Drag the IconTabFilter control from the palette to the canvas and drop it on the information icon.

5.png

7. As our new tab should contain customer data, we will change some properties of the new IconTabFilter control.

  1. In the canvas, select the icon of the new tab filter. Note that in the Outline pane, sap.m.IconTabFilter is selected -but more on that later.
  2. In the Properties/Data pane, the Properties with all its sections are expanded.
  3. Go to the Appearance section and select the value Default for the Icon Color field.
  4. As we do not need any numbers in our tab, we delete the default value of the Count field in the Data section and enter the value Customer for the Key field.
  5. In the Misc section, change the value of the Icon field to sap-icon://customer and the value of the Text field to Customer.

6.png

8. Now the new icon tab filter needs some content (some fields to display customer detail data). To add that, we make use of the SimpleForm control.

a. In the palette, expand the Container section or search for the simple form via the search field.

b. Drag the SimpleForm control from the palette to the canvas and drop it on the icon of the new tab filter.

7.png

9. Cool, with the simple form already some field elements are provided, we only need to adjust them a bit.

a. In the canvas, select the title in the simple form.

b. In the Properties/Data pane, in the Properties section, under Appearance, change the value of the Text field to Customer Details. Hint: You have to hit Enter to make your entries visible in the canvas.

8.png

c. In the canvas, select Label 1 in the simple form.

d. In the Properties/Data pane, in the Properties section, under Misc, change the value of the Text field to Sales Organization.

9.png

e. In the canvas, select Label 2 in the simple form.

f. In the Properties/Data pane, under Properties, under Misc, change the value of the Text field to Sales Organization Name.

g. Delete the second input field under Sales Organization.

11.png

10. Now we need to bind the two input fields to some value.

  1. In the canvas, select the Sales Organization input field in the simple form.
  2. In the Outline pane, the corresponding control is marked in the control tree. Expand the highlighted sap.m.Input node, then the properties node, and select the property value.
  3. In the Properties/Data pane you noticed that this time Data is expanded.  Open up the SalesOrders node and select SalesOrganization. Hint: In the Outline pane, the binding is indicated by the text {SalesOrders.SalesOrganization} next to the property value.

12.png

d. Do the same steps for the input field of Sales Organization Name in the simple form but select SalesOrganizationName from the SalesOrder treein the Properties/Data pane.

e. Finished! Just save your changes.

 

Let’s check what the result looks like

  1. In your project folder, select the file index.html.
  2. In the context menu, select Run -> Run with Mock Data.
  3. In the Run with Mock Data dialog box, choose Run (no further input required).
  4. The application preview is started, the application is loading and data is being mocked based on the service structure you have created. Hint: As the preview with mock data opens up in a pop-up window you might need to allow pop-ups from this webpage in your browser settings.

15.png


Hope you had fun following this small tutorial. Let us know what you think about the new layout editor


SAPUI5 with Google API's

$
0
0

From last few weeks, I am continously engaged in learning SAPUI5 and I must say, I am compeltely in love with it!!

 

In this blog, we will see how to use any Google API with SAPUI5. There are many public API's available which can be consumed and that way we can save our time and effort in building complex UI's.

 

All you have to do is to add the following line in your <head> element of your index.html file.

 

<script type="text/javascript" src="https://www.google.com/jsapi"></script>

 

 

The src element points to a javascript file, which has a single method

 

google.load

 

 

 

Using this method you can load any individual Google API's.

 

Here's the list of Google API's packages which could be used with the above method. Each package will have its own sets of methods, which can be used to load/draw the contents.

 

As an example, we will use the core chart package.

 

Add the follwoing lines in the index.html file.

 

1.PNG

 

 

We have created a simple javascript file which will draw a core chart and placed it in the <div> of our index.html.

 

Output would be like

 

2.PNG

Let's play around with these kind of stuff and get more complex API's to work.

 

I have modified this blog to get the values dynamically. Please visit Dynamic SAPUI5 with Google API's

 

Cheers!

Dynamic SAPUI5 with Google API's

$
0
0

This blog is i continuation with my previous blog of SAPUI5 with Google API's

 

We will get values form the UI and then pass it to the API. Change the index.html file as shown below.

 

<!DOCTYPE HTML>

<html>

  <head>

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

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

 

 

 

  <script src="resources/sap-ui-core.js"

  id="sap-ui-bootstrap"

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

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

  </script>

  <script type="text/javascript" src="https://www.google.com/jsapi"></script> 

 

  <script type="text/javascript">

 

 

  google.load("visualization", "1", {packages:["corechart"]});

 

 

 

  var oMatrix = new sap.ui.commons.layout.MatrixLayout({

         layoutFixed : true,

         width : '300px',

         columns : 2

});

 

  oMatrix.setWidths('100px', '300px');

    var oCell = new sap.ui.commons.layout.MatrixLayoutCell({

           colSpan : 4

});

oCell.addContent(new sap.ui.commons.TextView({

           text : 'My Daily Activities',

           design : sap.ui.commons.TextViewDesign.H1

}));

oMatrix.createRow(oCell);

 

oLabel1 = new sap.ui.commons.Label({

     text : 'Work'

});

 

oInputField1 = new sap.ui.commons.TextField("oInputField1");

oLabel1.setLabelFor(oInputField1);

oMatrix.createRow(oLabel1, oInputField1);

 

oLabel2 = new sap.ui.commons.Label({

           text : 'Eat'

});

oInputField2 = new sap.ui.commons.TextField("oInputField2");

oLabel2.setLabelFor(oInputField2);

oMatrix.createRow(oLabel2, oInputField2);

 

oLabel3 = new sap.ui.commons.Label({

     text : 'Commute'

});

oInputField3 = new sap.ui.commons.TextField("oInputField3");

oLabel3.setLabelFor(oInputField3);

oMatrix.createRow(oLabel3, oInputField3);

 

oLabel4 = new sap.ui.commons.Label({

    text : 'Watch TV'

});

oInputField4 = new sap.ui.commons.TextField("oInputField4");

oLabel4.setLabelFor(oInputField4);

oMatrix.createRow(oLabel4, oInputField4);

 

 

oLabel5 = new sap.ui.commons.Label({

    text : 'Sleep'

});

oInputField5 = new sap.ui.commons.TextField("oInputField5");

oLabel5.setLabelFor(oInputField5);

oMatrix.createRow(oLabel5,oInputField5);

 

 

 

 

 

 

//callback function for successful requests

function onLoad() {

  var t1 = oInputField1.getValue();

  var t2 = oInputField2.getValue();

  var t3 = oInputField3.getValue();

  var t4 = oInputField4.getValue();

  var t5 = oInputField5.getValue();

 

  t1 = eval(t1)

  t2 = eval(t2)

  t3 = eval(t3)

  t4 = eval(t4)

  t5 = eval(t5)

 

  var data = google.visualization.arrayToDataTable([

                                                       ['Task', 'Value'],

                                                       ['Work',t1],

                                                       ['Eat',t2],

                                                       ['Commute',t3],

                                                       ['Watch TV',t4],

                                                       ['Sleep',t5]

                                                     ]);

 

 

 

 

 

     var options = {

       title: 'My Daily Activities',

       is3D: true,

     };

 

 

     var chart = new google.visualization.PieChart(document.getElementById('content'));

     chart.draw(data, options);

}

 

 

 

 

 

var oButton1 = new sap.ui.commons.Button({

  text : "Draw",

  tooltip : "This is a test tooltip",

  press : function() {

  google.setOnLoadCallback(onLoad());}

});

 

 

oMatrix.createRow(oButton1);

oMatrix.placeAt("content");

 

 

 

 

 

     </script>

 

 

  </head>

  <body class="sapUiBody" role="application">

  <div id="content" style="width: 900px;height: 500px;"></div>

  </body>

</html>

 

 

Output:

 

op1.PNG

 

op2.PNG

 

I will definately try and enhance the code to get more complex API's to work. Cheers.

SAP Fiori and Google Analytics Online Demonstration.

$
0
0

With the release Fiori, SAP has announced to the world that it is serious about improving the lives of users and it is spending resources providing easy to use tools. Fiori provides a greatly enhanced user interface built on an up to data HTML5 architecture. However, the question now comes up ‘How are my users using the new tools”?

With Google Analytics, you can determine where your visitors are coming from, which links on your site are getting the most hits and how long the visitors spend on various pages of your site. In addition to providing critical marketing data, it also tracks browser features so that you can make informed design decisions. Analytics will tell you the screen resolution and connection speed of your users.

Integration of Google Analytics with custom Fiori applications (and SAPUI5 architecture in general) will provide site owners and administrators a view into HOW the users are using the system, as well as key demographic information on those users.

Configuring JetBrains WebStorm for UI5 development

$
0
0


Why use WebStorm? Some background

 

Today, Eclipse has grown to quite a robust and widely used Java IDE, however it lacks severely in the Web / Javascript department. For web development -- not only SAPUI5 / OpenUI5, but in my opinion any webdevelopment -- I strongly feel we should look further than Eclipse.


Although SAP provides pretty useful Eclipse plugins for SAPUI5 / OpenUI5 development, it still doesn’t help you write better, efficient, correct code.


The same is true for text editors like Sublime Text and Atom, which -- although they have plugins that allow for rudimentary syntax highlighting and code checking -- don't have the context knowledge of the Javascript code you are writing, let alone check for syntax errors, unused variables/functions, type checking, and function signature mismatches, to name just a few.


JetBrains WebStorm actually does all that: it is aware of your code, it does a good job at inspecting and analyzing your code, and has terrific support for other HTML5/CSS related stuff (for instance, it does refactoring across multiple file types such as *.js and *.css). And if you add JsDoc comments to your code, you even benefit from proper type checking! You really have to try it to believe it.


And once you complete the steps described in this blog, you will benefit from excellent UI5 coding support as well!


An small example showcasing WebStorms' awesomeness when developing UI5 code can be seen  in the image below (click image to enlarge):

Screen Shot 2014-09-21 at 12.41.32.png

Here you see the WebStorm IDE with a MyView.controller.js file in the active editor tab. In the onInit() method, a variable oView is defined, and as you can see, the code completion is fully aware that within the controller 'this.getView()' is 1) a reference to the controller's view, 2) that it's of type sap.ui.core.mvc.View, and 3) provides access to the view's methods and events. In addition, it shows the onInit() function and oView variable as 'unused', making it easy to find redundant code. No other IDE I know of does this so perfectly and blazingly fast as WebStorm!


WebStorm isn't Open Source like Eclipse, but a personal license costs a mere 44 EUR and as such is worth it every penny.


Unfortunately, it currently has no support yet from SAP or the Open Source community for UI5, but according to some of the topics on SCN and Stackoverflow regarding UI5 development with WebStorm, it seems quite in demand. This blog tries to fill the gap and help you set up WebStorm for use with UI5 development.

 


Prerequisites


In order to use XML validation and code completion when using XML Views, we need the XML definition for the UI5 libraries. For reasons unknown, these definitions aren’t included in the OpenUI5 download, but they are included in the UI5 plugin for Eclipse. So we need to have Eclipse installed with the UI5 plugin.


And of course, you need to have WebStorm installed

 


Step 1 : Include UI5 libraries

 

After you have installed WebStorm, we need to make it OpenUI5-aware. First, we include the UI5 libraries. Since I mainly use the sap.ui.core and sap.m libraries, I will use these now as well. If you need other libraries, you can include these in the same way.


  1. Open WebStorm, and from the ‘Welcome to WebStorm’ screen, select ‘Configure > Preferences’.Screen Shot 2014-09-20 at 15.53.04.png

  2. From the ‘Template Project Settings’, select ‘JavaScript > Libraries’ and click the ‘Add...’ button.
  3. In the dialog, specify a name and version, and set ‘Visibility’ to ‘Global’.
  4. Click the ‘+’ sign, and choose ‘Attach Files...
  5. Navigate to the folder you have downloaded and extracted the OpenUI5 SDK, and select the “./resources/sap-ui-core-all-dbg.js” file:
    Screen Shot 2014-09-20 at 15.56.43.png
    and click ‘OK’
  6. Repeat steps 4. and 5. for file “./resources/sap/m/library-all-dbg.js”.
  7. Both files are now listed in the ‘New Library’ list, and you can click ‘OK’ to save our just configured 'OpenUI5' library.



Step 2 - Add XML definitions


Now, we need to add the XML definitions for use with XML Views.


  1. First, we need to copy the XML definitions from our Eclipse UI5 plugin. Navigate to your Eclipse ./plugins folder.
  2. Locate both ‘com.sap.ui5.core_n.nn.n.jar’ and ‘com.sap.ui5.mobile_n.nn.n.jar’ files, and extract their content.
  3. From the extracted content, navigate to the ./libraries folder and copy the *.xsd file to a different directory on your computer. Do this for both the core and mobile libraries.

    Screen Shot 2014-09-20 at 16.07.45.png
  4. In WebStorm, from the ‘Template Project Settings’, select ‘Schema’s and DTDs’.
  5. Under ‘External Schemas and DTDs’ click the ‘+’ button.
  6. Switch to the 'Explorer' tab, and navigate to the location where you copied the sap.ui.core.xsd file, and provide an URI ‘sap.ui.core
    Screen Shot 2014-09-20 at 16.12.55.png
  7. Do the same for sap.m.xsd, with URI ‘sap.m’.
  8. Both XSD’s are now listed under ‘External Schemas and DTDs’.

    IMPORTANT: Make sure you deselect both checkboxes next to these files! It’s not clear at first sight, but by deselecting the checkboxes you define the definitions as ‘Globally Available’ for every project. Having them checked makes them available to the current project only, which isn't what we want:
    Screen Shot 2014-09-20 at 16.15.01.png
  9. Click ‘OK’ to apply the changes to the preferences, and you’re back at the Welcome screen.



Step 3 - Test our new configuration


Now it's time to see if what we have configured is actually working and useful.


  1. In the Welcome screen, click the ‘Back’ button next to the ‘Configuration’ header, and select ‘Create New Project’. Choose a project name, a project location, and set 'Project Type' to 'Empty project'
    Screen Shot 2014-09-20 at 16.19.41.png
  2. Let’s create a basic UI5 project directory structure: add a WebContent folder with an index.html file, and a subfolder ui5test with a controller file MyView.controller.js and XML view file MyView.view.xmlScreen Shot 2014-09-20 at 16.23.38.png
    As you can see in the above screenshot, our globally defined library 'OpenUI5' is linked as well.

  3. In the controller, lets write some UI5 specific code and see if code completion works:

    Screen Shot 2014-09-20 at 16.28.12.png
  4. Cool! As you see, all methods and properties come instantly available for code completion:
    Screen Shot 2014-09-20 at 16.30.05.png
    Also, as you can see from the previous image, variable ‘oModel’ is shown strikethrough, indicating the variable is never used and therefor redundant. This is just one of the benefits WebStorm has over Eclipse: identifying unused Javascript variables and functions!
  5. Now, lets create an XML view and see if code completion / XML validation works too:

    Screen Shot 2014-09-20 at 16.34.44.png
  6. Awesome! And even here, as shown in the image you see the references to the unused namespace declarations ‘mvc’ and ‘html’ shown strikethrough.



Additional step: Create UI5 file templates


Now, if you use the Eclipse with the UI5 plugin, the initial content for the controller and view files are generated, but in WebStorm we have to write it ourselves. Luckily, WebStorm provides a mechanism called 'File and Code templates'. In here, I have defined placeholder templates for UI5 index.html file, and controller / view files. Using 'File Template Variables' I have used predefined variables ( ‘${NAME}’ for getting the filename without extension) as well as custom defined variables (‘${UI5_Namespace}’ in which I specify the namespace for the current file):

Screen Shot 2014-09-20 at 16.39.49.png

If you have defined such templates yourself, you can now right-click a project web folder and you’ll see the file templates listed in the context menu:

Screen Shot 2014-09-20 at 16.42.33.png

If I now choose my custom ‘UI5 Controller’, after you specify the File name and UI5 Namespace:

Screen Shot 2014-09-20 at 16.43.46.png

 

...the new file is created using the specified properties:

Screen Shot 2014-09-20 at 16.44.23.png



Summary


This is just the basics of making WebStorm UI5 aware, and I’m all ears for any other methods or additional configuration to make UI5 development as easy and streamlined as possible!

Sample ODATA model in SAPUI5 and issues faced

$
0
0

Introduction of ODATA

 

 

OData services are web services that expose some resources. You
can access these resources via URL. OData protocol specifies how you can access
data via HTTP queries. The basic idea is that you can open some URL with
parameters that will execute queries against the resources.

 

 

Similar to REST OData builds on core protocols like HTTP and
commonly accepted methodologies

 

 

Now getting on with building a sample project using ODATA model.
Here in this article I would even address the issues creeping up while building
an SAPUI5 project consuming an ODATA service so that you have a Demo project,
the issues and their corresponding work around, all under one roof.

 

 

Here I would use the following odata service:

 

 

http://services.odata.org/OData/OData.svc

 

 

 

You would find an xml
file showing the entities.

 

 

 

First test the service
by pasting the url in the browser.

 

 




  If so then this
service is ready for its use in a Simple Odata model in SAPUI5 project.

 

 

Now Lets Create a
sample project to test this:

 

 

  1. Open Eclipse(Juno/Kepler/Luna). Goto File-  New-Other...
  2. Select SAPUI5 Application Development-Application Project

  3. Give a suitable name

   4.Check the Desktop radio Button.

   5.Select Javascrpit as the Development Paradigm

   6.Click finish.

   7.Since we need a table on the UI. So the bootstrap needs to be changed a bit.

 

 

In the
index.html file of the project replace the your bootstrap with the following
code.

 

 

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

       data-sap-ui-libs="sap.ui.commons,sap.ui.ux3,sap.ui.table"

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

</script>

 

 

    8. Since using MVC architecture in SAPUI5 is greatly appreciated, We will be using the same. So now we will define the view.
For that paste the following code within the createContent :
function(oController) of your view .js page.

 

 

                // Create an instance of the table control

 

                        var oTable2 = new sap.ui.table.Table({

 

                                    id: "Products",

 

                                    title: "Table with fixed columns Example",

 

                                    visibleRowCount: 7,

 

                                    firstVisibleRow: 3,

 

                                    selectionMode: sap.ui.table.SelectionMode.Single,

 

                                    navigationMode: sap.ui.table.NavigationMode.Paginator,

 

                                    fixedColumnCount: 7,

 

                                    toolbar: new sap.ui.commons.Toolbar({

 

 

 

 

 

                                                items: [

 

 

                                                new sap.ui.commons.Button({

 

                                                            text: "Create",

 

                                                          press: function() {

 

                                                                        oController.Create();

 

                                                            }

 

                                                }),

 

 

                                                new ap.ui.commons.Button({

 

 

                                                            text: "Update",

 

                                                            press: function() {

 

                                                                        oController.Update();

 

                                                            }

 

                                                }),

 

                                                new ap.ui.commons.Button({

 

                                                            text : "Delete",

                                                         press: function() {

 

                                                                        oController.Delete();

 

                                                            }

 

                                                }),

 

                                                ]

 

                                    })

 

                        });

 

 

 

 

 

                        // Define the
columns and the control templates to be used

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new sap.ui.commons.Label({

 

 

                                                text: "ID"

 

                                    }),

 

 

                                    template: new ap.ui.commons.TextField().bindProperty("value",ID"),

 

                                    sortProperty: "ID"

 

 

                        }));

 

 

 

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text: "Name"

 

 

                                    }),

 

                                    template: new ap.ui.commons.TextField().bindProperty("value","Name"),

 

                                    sortProperty: "Name"

 

 

                        }));

 

 

 

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text: "Description"

 

 

                                    }),

 

 

                                    template: new sap.ui.commons.TextField().bindProperty("value",  "Description"),

 

 

                                    sortProperty: "Description"

 

                        }));

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text: "ReleaseDate"

 

 

                                    }),

 

 

                                    template: new sap.ui.commons.TextField().bindProperty("value",  "ReleaseDate"),

 

 

                                    sortProperty: "ReleaseDate"

 

 

                        }));

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text: "DiscontinuedDate"

 

 

                                    }),

 

 

                                    template: new sap.ui.commons.TextField().bindProperty("value",  "DiscontinuedDate"),

 

 

                                    sortProperty: "DiscontinuedDate"

 

 

                        }));

 

 

 

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text: "Rating"

 

 

                                    }),

 

 

                                    template: new sap.ui.commons.TextField().bindProperty("value",  "Rating"),

 

 

                                    sortProperty: "Rating"

 

 

                        }));

 

 

                        oTable2.addColumn(new sap.ui.table.Column({

 

 

                                    label: new ap.ui.commons.Label({

 

 

                                                text
:
"Price"

 

 

                                    }),

 

 

                                    template: new ap.ui.commons.TextField().bindProperty("value",  "Price"),

 

 

                                    sortProperty: "Price"

 

 

                        }));

 

 

                        returnoTable2;

 

 

  9. Now  lets move to the controller part. In the
controller.js page define the following the following:


In theonInit:function() paste the following Code:

 

 

// Create a model and bind the table
rows to this model

 

          var oModel = new sap.ui.model.odata.ODataModel("http://services.odata.org/OData/OData.svc", false);

 

             var oTable =sap.ui.getCore().byId("Products");

      oTable.setModel(oModel);

 

  oTable.bindRows("/Products");

 

 

 

  10. Save and run.

 

 

Note:
The Create, Update and Delete buttons on the top are not functional as we have not defined their functionality.

 

 

Issues:

 

 

  • The most commonly faced error is “No DATA ” in the binded table on the UI.

 

Try testing in Chrome and press F12 so that you could see the Console log.

 

 

If the error is as follows:

 

 

Failed to load resource: the server responded with a status
of 501 (Not Implemented) http://services.odata.org/OData/OData.svc/$metadata

XMLHttpRequest cannot load
http://services.odata.org/OData/OData.svc/$metadata. Invalid HTTP status code
501

 

 

Then, go to the controller.js page, in the section where we have created a model we have used the url

 

http://services.odata.org/OData/OData.svc

 

 

Replace it with the following:

 

 

“proxy/http/services.odata.org/OData/OData.svc”

 

 

If the error is as follows:

 

 

The following problem occurred: HTTP request failed400,Bad
Request,<?xml version="1.0"
encoding="utf-8"?><m:error
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code
/><m:message xml:lang="en-US">

 

 

The
MaxDataServiceVersion '2.0' is too low for the response. The lowest supported
version is '3.0'.

 

 

</m:message></m:error>

 

 

 

Then you should go for V2<Version 2> service of ODATA.

 

 

For that, go to the controller.js page, in the section where we have created a model we have used the url:

 

 

http://services.odata.org/OData/OData.svc

 

 

Replace it with the following:

 

 

“proxy/http/services.odata.org/V2/OData/OData.svc”

 

 

 

Now test it again, and it would work.

 

 


SAPUI5 JSONModel undo redo

$
0
0

Background

 

We all are used to having undo redo functionality in applications which we use everyday. Undo redo can be found in text editors, email programs, graphics editors, most of the online tools etc. Wouldn’t it be nice to have it also in our shiny new business applications? Wouldn’t that be one essential part of the user experience?

 

Here it is. Undo redo functionality for UI5 JSONModels:

Implementation

 

Before coming up with the idea of this undo redo implementation, I was thinking what could be a good use case for a reusable UI5 Faceless component (class: sap.ui.core.Component)

Faceless components do not have a user interface and are used, for example, for a service that delivers data from a back-end system.

 

That’s when I understood a nice use case. Attach it with a Model so that changes made to the Model can be kept track of.

How should we continue with the implementation, then? There were basically two options I could think of:

 

  1. Bind the Faceless component directly into the Model and listen when it dispatches change events.
  2. Wrap the Model with another construct so that every time we change any value in the model it goes through our wrapper.

 

I first pondered with the first option as it would’ve been more comprehensive. No matter how the model would have been changed, we could have tracked the changes. Unfortunately, this was not an option, as we cannot bind a Faceless component to the Model directly (see http://scn.sap.com/thread/3492009 for possible solution).

 

Luckily the second option proved to be possible. One downside, of course, is that we have to make every change to the Model using our wrapper. But once you take it, it’s now nice as we have single point of entry for methods modifying our model.

Below you can find the code for undo redo component.

 

jQuery.sap.declare("util.undoRedo");      util.undoRedo = (function(jsonModel){             var _jsonModel = jsonModel;        var _undoStack = [];        var _redoStack = [];        var updateModelValue = function(sPath, oValue, oContext) {          _jsonModel.setProperty(sPath, oValue, oContext);        };        return {          setProperty: function(sPath, oValue, oContext) {                     var oldValue = _jsonModel.getProperty(sPath);            updateModelValue(sPath, oValue, oContext)            window.console&&console.log("Updating stack with newvalue " + oValue + " old value " + oldValue);            // TODO also keep track of oldContext and newContext            // TODO should propably make a deep copy of oValue so that tracking works for objects also            // var newValue = JSON.parse(JSON.stringify(oValue));            // add new entry into the undoStack            _undoStack.unshift({"path": sPath, "oldValue": oldValue, "newValue": oValue});            window.console&&console.log("Undo stack is now: " + JSON.stringify(_undoStack));            // clear redo stack if needed            if (_redoStack.length > 0) {              _redoStack = [];            }          },          undo: function() {            var undoItem = (_undoStack.length > 0) ? _undoStack.shift() : null;            if (undoItem !== null) {              window.console&&console.log("Undo item is " + JSON.stringify(undoItem));              updateModelValue(undoItem.path, undoItem.oldValue);              // add item to redoStack              _redoStack.unshift(undoItem);            }                   },          redo: function() {            // TODO get item from redoStack            var redoItem = (_redoStack.length > 0) ? _redoStack.shift() : null;            if (redoItem !== null) {              window.console&&console.log("Redo item is " + JSON.stringify(redoItem));              updateModelValue(redoItem.path, redoItem.newValue);              // add item to undoStack              _undoStack.unshift(redoItem);            }          },        };    });

It is using module pattern to hide implementation details. I won’t go through all the code verbally as I think that code is best explained by itself. Just a few notes. Component keeps changes in objects that are saved in two stacks, one for undo and another for redo. Change objects contain info about path, oldValue and newValue. In undo value in the path is replaced with oldValue and in redo value is replaced with newValue. Changes are saved as objects so saving possibly only works for simple types. Saving objects or arrays could be possible if change data was kept in json format (see TODO in code).

 

Here’s how to use the code with two different examples:

jQuery(function() {        // create model        var modelJson = {"textVal" : "initial value"};        var model = new sap.ui.model.json.JSONModel(modelJson);        sap.ui.getCore().setModel(model);        // initialize undo redo component and wrap JSONModel with it        var undoRedoComponent = util.undoRedo(model);        var textInput = new sap.m.Input({          //value : "{/textVal}",          change : function(evt) {            var newVal = evt.mParameters.newValue;            // change value on Model through undoRedo so that it can keep track of changes            undoRedoComponent.setProperty("/textVal", newVal);          }        });        // BindingMode should be Oneway because undoRedo does not listen to changes in the model directly        textInput.bindValue("/textVal", null, sap.ui.model.BindingMode.OneWay);        var hbox = new sap.m.HBox();        var undoButton = new sap.m.Button({text: 'Undo',          press : function() {            undoRedoComponent.undo();          }});        var redoButton = new sap.m.Button({text: 'Redo',          press : function() {            undoRedoComponent.redo();          }});             hbox.addItem(undoButton);        hbox.addItem(redoButton);             textInput.placeAt('content');        hbox.placeAt('content');      });
jQuery(function() {        // create model        var beers = [          {"style": "Imperial Stout", "name": "Plevna Siperia", "rating": 3},          {"style": "Weissbier", "name": "Paulaner Naturtrüb", "rating": 3},          {"style": "India Pale ale", "name": "Founders Centennial IPA", "rating": 3},          {"style": "Trappist", "name": "Orval", "rating": 3},        ];        var modelJson = {"listItems": beers};        var model = new sap.ui.model.json.JSONModel(modelJson);        sap.ui.getCore().setModel(model);        // initialize undo redo component and wrap JSONModel with it        var undoRedoComponent = util.undoRedo(model);        // TABLE STARTS HERE        //Create an instance of the table control        var oTable = new sap.ui.table.Table({          title: "Beers table",          visibleRowCount: 7,             firstVisibleRow: 3,          columnHeaderHeight: 30,           selectionMode: sap.ui.table.SelectionMode.Single,          toolbar: new sap.ui.commons.Toolbar({items: [            new sap.ui.commons.Button({text: "Undo", press: function() {              undoRedoComponent.undo();              // we refresh the model to show changes              model.refresh(true);            }})          ]}),          extension: [            new sap.ui.commons.Button({text: "Redo", press: function() {              undoRedoComponent.redo();              // we refresh the model to show changes              model.refresh(true);            }})          ]        });        //Define the columns and the control templates to be used        var oColumn = new sap.ui.table.Column({          label: new sap.ui.commons.Label({text: "Name"}),          template: new sap.ui.commons.TextView().bindProperty("text", "name"),          sortProperty: "name",          filterProperty: "name",          width: "200px",          editable: false        });        var oColumn2 = new sap.ui.table.Column({          label: new sap.ui.commons.Label({text: "Style"}),          template: new sap.ui.commons.TextView().bindProperty("text", "style"),          sortProperty: "style",          filterProperty: "style",          width: "200px",          editable: false        });        // BindingMode should be Oneway because undoRedo does not listen to changes in the model directly        var oColumn3 = new sap.ui.table.Column({          label: new sap.ui.commons.Label({text: "Rating"}),          template: new sap.ui.commons.RatingIndicator({            maxValue: 5,            change: function(evt) {                         var value = evt.mParameters.value;              var bindingContext = evt.getSource().getBindingContext();              window.console&&console.log("binding context is " + bindingContext);              undoRedoComponent.setProperty(bindingContext.sPath + "/rating", value);            }          }).bindValue("rating", null, sap.ui.model.BindingMode.OneWay),          sortProperty: "rating",          filterProperty: "rating",          width: "200px"        });        var oCustomMenu = new sap.ui.commons.Menu();        oCustomMenu.addItem(new sap.ui.commons.MenuItem({          text:"Custom Menu",          select:function() {            alert("Custom Menu");          }        }));        oColumn.setMenu(oCustomMenu);        oTable.addColumn(oColumn);        oTable.addColumn(oColumn2);        oTable.addColumn(oColumn3);        oTable.bindRows("/listItems");        oTable.placeAt('content');      });

Most important thing to note here is that undoRedo component does not work with two-way binding. That is because it cannot keep track of changes made to the Model using View to Model change. This is similar to how formatters work so I don’t see this as a big problem.

 

Todo

  • Make undoRedo work with Objects. I’ve only tested it with simple types
  • Allow adding items into and removing them from arrays in a Model. Example use case: add a row into a table
  • Set maximum size of undo stack to limit memory usage in production applications
  • Make undoredo component listen to all changes made to the Model even if they were made directly

Live examples

 

Example 1: http://jsbin.com/weboqi/1/edit

Example 2: http://jsbin.com/norani/1/edit

 

Thanks for reading!

SAPUI5 Programming Tips & Tricks


Creating UI5 application project with multiple JS files

$
0
0


Introduction


When I started working on SAP UI5 Application in eclipse, I remember coding everything in a "createContent: function(oController){}" function generated by application creation wizard, ended up with thousands of lines. Finding things in this code and version management (when other folks are working on same application) is not an easy task.

 

First thing that we learnt in ABAP after some basic programming is Modularization Techniques for better readability and re-usability of code. Why should we give such an importance to these techniques? Because, implementation is not all about the application.. it should get support from other teams after implementation. A well written program can save up to 40% of review time, easy to extend, minimize defects and much more. UI5 application is not exception for that, right?

 

We have well documented Modularization Techniques for UI5 projects in tool-kit. In this blog, I am going to explain one of the technique i.e. how to use multiple JS files to simply UI5 application project.

 

Creating UI5 application project with multiple JS files

 

Create one project in eclipse with initial view name "Demo". As expected, we got controller and view under "Demo/WebContent/demo" folder in the project application.

one.png

Let's add Application Header, Button and Table to the page as shown below. We need to pass these controls to one vertical layout and add Layout to index page.

Out.png 

Now we need to add Application header & Button to the default view (generated by wizard) and create Table and it's functions in new/separate JS file. For that, Let's create new folder "util" under "WebContent" (You can give any name to folder).


fold.png

Create one .JS file under this new folder.

js.png

You can give any name to this JS file. You project folder should look like below after above two steps. "util" is my folder name and "OtherFunction.js" is my JS file name.


after.png


Now add below content to OtherFunction.JS file. This is just copy & paste of sample code of Table control from SAP UI5. However, make sure to remove line where it places the content on screen (remove oTable.placeAt("sample1")). Also, give unique ID to your table to be able call this from other places of application. In below code sample, I am using "table1" as ID for my oTable.

Tab.png

Now, create Application Header and Button in Demo.view.js file. Add these two controls to vertical layout control along with the Table control that we created in OtherFunction.js file. As you can see here, we are calling oTable with help of reference ID "table1".

ViewCode.png

Now you can add further code in function of button press and modify the properties of the table. In this example, I am just using getVisible and setVisible property.. but we can use any other property based on the requirement.

shade.png


Before running this application, we need to add our new JS file as source file in INDEX.HTML page and of course ui.tables library for table control. It should look like below:

util.png

With that, we've successfully created UI5 application with one additional JS file from different folder. You can add number of JS files to this folder, but when mention that as a source file in index.html it should be in right order. For example, If I move "util/OtherFunction.js" reference from Line 15 to Line 22 in above code, it won't work because I am using OtherFunction.js scripting in Demo.View.js. However, you can handle these dependencies with jQuery.sap.declare & jQuery.sap.require functions as guided here. Next time, I will extend this blog to show how it works with same example.


There will be no dependency between these file while we deploy or submit this application to server, which will allow to engage more people in single application.


Thanks for going through this blog.


Regards,

Naveen Inuganti






SAPUI5 Choropleth Map Control

$
0
0

Background

 

In this blog post, I’ll introduce a reusable choropleth map UI5 control that can be bind to a model.

 

There are already a few examples (e.g. Konstantin Anikeev 's blog and John Patterson 's blog) of how to use maps with UI5. They are mostly using Google Maps library and provide functionality such as geolocation and markers. I wanted to have a try with leaflet that is “An open-source JavaScript Library for Mobile-Friendly Interactive Maps” and use it for displaying tabular data on a map. My goal was to provide an easy-to-use UI5 component that provides the basic functionality of mapping tabular data, nothing more, nothing less.

 

A choropleth map is used to show proportional values, such as population density, on a map using shaded or patterned areas. It provides a visual tool for understanding variability of a given variable within a region. Choropleth maps are preferred form of map display when dealing with data that conforms to clearly defined areas, such as countries.

 

Here’s an example of UI5 choropleth map control bind to a model:

 

 

Implementation

 

 

I decided to make a control that can be used for displaying country data on a world map. For that I needed some data. Getting geographic data can be sometimes difficult especially if it has to be open source. Luckily there are more and more places that work to get more data more easily available. Examples are Natural Earth which is built by collaborators and supported by NACIS (North American Cartographic Information Society), and Open Knowledge (http://data.okfn.org/ ). I use Open Knowledge’s world country boundary json and World Bank’s GNI (gross national income) per capitadatasets in the example. I also use MapQuest’s tile service to display the background map.

 

For the UI5 part of the implementation, I am creating a custom control  that handles the leaflet library. User only has to plugin the model to the control and define which fields contain the data that should be displayed. Implementation of the control can be found in github (link in the end of the post):

 

There's two js/json files used in the example: countries.js contains the geoJson (multi)polygons for the world’s countries and GNIpercapita contains data about individual countries GNI. countries.js is used only by the control and user just needs to include it in the html page. GNIPerCapita is provided by the user and requirement is that the data contains a list of objects that have ISO3 country key in some field (this can be mapped with idField property) and a value (mapped with valueField property) that can be converted to a number using defined format. Format is hard-coded at the moment but could also be given using a metadata property or even callback function.

 

 

Here’s an example of the map

 

map_example.png

 

Integrating with model changes using UI5 Table

 

Getting the map to show was the first part but now let’s integrate the map with UI5 model changes. With a choropleth map, natural approach is to use table to modify the data so let’s do that next.

 

Integrating with the table actually requires almost no changes to the map control itself. We only have to bind the table to the model the map also uses and just refresh the map once there are changes. Even refreshing could probably be automated but I leave that as an exercise to the reader. You can find the code for integrating with the table in the end of the article. Here I show the output:

 

maptable_example.png

 

And after modifying the value for Russia (RUS) in the table:

 

maptablechange_example.png

 

Code example:

 

kjokinen/ui5choroplethmap · GitHub


Thanks for reading!

Coloring Table Cells Conditionally in SAP UI5

$
0
0

Introduction

This document helps how to color table cell/row conditionally in SAP UI5.


Step by Step Process

To create a Table refer this example in the Demo Kit: SAPUI5 SDK - Demo Kit - Table

We can color individual table cell or entire row based on condition by setting the css style class.


Here we will see a simple example to color the table cell based on the amount value.

Here is the code for the UI5 application.

 

<!DOCTYPE HTML><html><head><title>Table Cell Color Demo </title>      <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta http-equiv='Content-Type' content='text/html;charset=UTF-8' />    <script src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"             id="sap-ui-bootstrap"             data-sap-ui-libs="sap.ui.commons, sap.ui.table"             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 -->    <style type="text/css">        .green {            background-color: #66FF33;         }        .red {            background-color: #FF3300;        }        .yellow {            background-color: #FFFF66;        }    </style>    <script>            // Model Data (local)        var aData = [{            order: "456",            customer: "SAP",            curr: "EUR",            amount: 30000        }, {            order: "457",            customer: "Jateco",            curr: "EUR",            amount: 1300        }, {            order: "458",            customer: "SAP",            curr: "EUR",            amount: 1200        }, {            order: "459",            customer: "Sorali",            curr: "EUR",            amount: 750        },  {            order: "460",            customer: "Ariba",            curr: "EUR",            amount: 1500        }, ];        // Define a table          var oTable = new sap.ui.table.Table({            title: "Order Details", // heading of the table            visibleRowCount: 5, // Visible no of Rows of table            selectionMode: sap.ui.table.SelectionMode.Single, // Singe or Multi            navigationMode: sap.ui.table.NavigationMode.Paginator, //Paginator or Scrollbar                         enableColumnReordering: true, // Allows you to drag and drop the column and reorder the position of the column            width: "800px"        });        // Add table Columns        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Order" // Creates an Header with value defined for the text attribute            }),            template: new sap.ui.commons.TextView({                text: '{order}', // binds the value into the text field defined using JSON                          }),            width: "150px" // width of the column        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Customer"            }),            template: new sap.ui.commons.TextView({                text: '{customer}'            }),            width: "150px"        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Currency"            }),            template: new sap.ui.commons.TextView({                text: '{curr}'            }),            width: "100px"        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Amount"            }),            template: new sap.ui.commons.TextView().bindProperty("text", "amount", function(cellValue) {               // remove styles else it will overwrite                 this.removeStyleClass('green');                this.removeStyleClass('yellow');                this.removeStyleClass('red');                // Set style Conditionally                if (cellValue >= 1500) {                    this.addStyleClass('green');                } else if(cellValue < 1500 && cellValue > 1000) {                    this.addStyleClass('yellow');                } else{                this.addStyleClass('red');                             }                return cellValue;            }),                        width: "100px"        }));        //Create a model and bind the table rows to this model        var oModel = new sap.ui.model.json.JSONModel(); // created a JSON model              oModel.setData({ // Set the data to the model using the JSON object defined already            modelData: aData        });        oTable.setModel(oModel);        oTable.bindRows("/modelData"); // binding table rows        //Place the Table on the UI        oTable.placeAt("orders");    </script></head><body class="sapUiBody">    <div id="orders"></div></body></html>

 

Result:

Now we can see, the table cells are colored accordingly to the condition

table_cell_color.JPG

 

 

We will now see how to color the entire row conditionally based on the amount value.

 

Here is the Code:

 

<!DOCTYPE HTML><html><head>    <title>Table Row Color Demo </title>    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta http-equiv='Content-Type' content='text/html;charset=UTF-8' />    <script src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"                id="sap-ui-bootstrap"                data-sap-ui-libs="sap.ui.commons, sap.ui.table"                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 -->    <style type="text/css">        .green {            background-color: #66FF33;        }        .red {            background-color: #FF3300;        }        .yellow {            background-color: #FFFF66;        }    </style>    <script>        // Model Data (local)        var aData = [{            order: "456",            customer: "SAP",            curr: "EUR",            amount: 30000        }, {            order: "457",            customer: "Jateco",            curr: "EUR",            amount: 1300        }, {            order: "458",            customer: "SAP",            curr: "EUR",            amount: 1200        }, {            order: "459",            customer: "Sorali",            curr: "EUR",            amount: 750        }, {            order: "460",            customer: "Ariba",            curr: "EUR",            amount: 1500        }, ];        // Define a table        var oTable = new sap.ui.table.Table({            title: "Order Details",            visibleRowCount: 5,            selectionMode: sap.ui.table.SelectionMode.Single,            navigationMode: sap.ui.table.NavigationMode.Scrollbar,            width: "800px"        });        // Add table Columns        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Order"            }),            template: new sap.ui.commons.TextView({                text: '{order}',            }),            width: "150px"        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Customer"            }),            template: new sap.ui.commons.TextView({                text: '{customer}'            }),            width: "150px"        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Currency"            }),            template: new sap.ui.commons.TextView({                text: '{curr}'            }),            width: "100px"        }));        oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({                text: "Amount"            }),            template: new sap.ui.commons.TextView({                text: '{amount}'            }),            width: "100px"        }));        //Create a model and bind the table rows to this model        var oModel = new sap.ui.model.json.JSONModel();        oModel.setData({            modelData: aData        });        oTable.setModel(oModel);        oTable.bindRows("/modelData");        //Place the Table on the UI        oTable.placeAt("orders");        // Set Row Color Conditionally        var colorRows = function() {            var rowCount = oTable.getVisibleRowCount(); //number of visible rows            var rowStart = oTable.getFirstVisibleRow(); //starting Row index            var currentRowContext;            for (var i = 0; i < rowCount; i++) {              currentRowContext = oTable.getContextByIndex(rowStart + i); //content                // Remove Style class else it will overwrite                oTable.getRows()[i].$().removeClass("yellow");                oTable.getRows()[i].$().removeClass("green");                oTable.getRows()[i].$().removeClass("red");                var cellValue = oModel.getProperty("amount", currentRowContext); // Get Amount                // Set Row color conditionally                if (cellValue >= 1500) {                    oTable.getRows()[i].$().addClass("green");                } else if (cellValue < 1500 && cellValue > 1000) {                    oTable.getRows()[i].$().addClass("yellow");                } else {                    oTable.getRows()[i].$().addClass("red");                }            }        }        $(document).ready(function() {            // Attach Scroll Handler            oTable._oVSb.attachScroll(function() {                colorRows()            });            colorRows(); // Color Rows initially        });    </script></head><body class="sapUiBody">    <div id="orders"></div></body></html>

 

Result:

Now we can see, the whole table rows are colored based on the amount value

table_row_color.JPG

 

This should also work even if we change the Visible Row count of table.

 

Result after changing the Visible row count to 3:

table_row_color1.JPG

After Scroll:

table_row_color2.JPG

 

 

You need to modify the code if you use the Navigation mode as Paginator instead of Scrollbar.

 

Here is the code snippet for Navigation Mode - Paginator:

 

// Set Row Color Conditionally        var colorRows = function() {            var rowCount = oTable.getVisibleRowCount(); //number of visible rows            var rowStart = rowCount * ( oTable._oPaginator.getCurrentPage() - 1); //starting Row index            var currentRowContext;            for (var i = 0; i < rowCount; i++) {               currentRowContext = oTable.getContextByIndex(rowStart + i); //content                // Remove Style class else it will overwrite                oTable.getRows()[i].$().removeClass("yellow");                oTable.getRows()[i].$().removeClass("green");                oTable.getRows()[i].$().removeClass("red");                var cellValue = oModel.getProperty("amount", currentRowContext); // Get Amount                // Set Row color conditionally                if (cellValue >= 1500) {                    oTable.getRows()[i].$().addClass("green");                } else if (cellValue < 1500 && cellValue > 1000) {                    oTable.getRows()[i].$().addClass("yellow");                } else if (cellValue < 1000 && cellValue > 0) {                    oTable.getRows()[i].$().addClass("red");                }            }        }        $(document).ready(function() {            //Attach Page handler            oTable._oPaginator.attachPage(function(){                colorRows()            });            colorRows(); // Color Rows initially        });

 

Result:

table_row_color3.JPG

table_row_color4.JPG

 

Here, I just demonstrated a simple example to color table cells/rows conditionally based on cell value. You can use according to your requirements( with nice color codes, not the ugly colors as demonstrated ).



UI5 is growing – and hiring! A look behind the scenes...

$
0
0

This is going to be a completely non-technical blog post, but still one that might give you interesting insight you normally don't get when looking at SAP and the SAPUI5 library from outside.

 

It is no secret that SAP bets big on SAPUI5/OpenUI5, building hundreds of UI5 applications with more than thousand developers. But let’s have a look behind the scenes – what does this mean for the development of UI5?


One sign of that big investment is the continuous growth around UI5:

 

  • The two “original” UI5 teams developing the core and controls in Walldorf (and about 90% of what is available in OpenUI5) have grown almost monthly and now finally been split into three (still large) scrum teams. One is focusing on the core (data binding, MVC,...), one on controls (desktop and mobile), and one on consumption topics (best practices, demo applications etc.). These teams have new abbreviated names, according to their responsibilities: we call them team "co", team "co" and team "co". Nah, that was a joke, we are actually struggling over the names right now. :-)

Constantly getting new young developers into the team is for sure keeping us agile and making sure that UI5 evolves and stays up-to-date and we don't get lazy. One example for such new ideas is theOPA test framework, which was initiated and developed by such a new team member.


  • In addition to these three teams, there are now additional teams in Sofia (Bulgaria) being staffed that tightly collaborate with the Walldorf teams to continue development of this very heart of UI5, mainly in the area of UI controls. That’s a very talented and enthusiastic bunch of people and I’m sure we’ll see great things coming from there.  Among the first results of their work there will be “High Contrast” theme support for the sap.m controls and a very useful new layout. They are still hiring, see the last section of this post.


  • Over time, a growing number of other teams all over the world have developed more and more UI5 content. Some of that is in the sap.m library, a lot went into other control libraries that are not part of the OpenUI5 Open Source package or not even of SAPUI5, usually because the content is specific for certain application areas or for usage with SAP systems, so it is not useful for external users. But this is a lot of content. we are talking about dozens of teams here!


  • The effort to make JavaScript (and UI5) development more efficient was started in a small but quickly growing “UI5 tools” team, but has now extended/moved to several teams in Israel working on theSAP Web IDE(formerly known as “SAP River RDE”).


  • There are many others I usually tend to forget because they are not writing code, but there is a big job done by interaction and visual designers to make UI5 look and feel great, there are accessibility experts, documentation developers,... so many people paid by SAP to make UI5 better and easier to use – and you profit from that when using SAPUI5 or OpenUI5.

 

So you see there is a lot going on around the core of UI5, and this significant investment for sure indicates how serious SAP is about SAPUI5 and OpenUI5.

 

Still, despite of all that growth around UI5, those of us in the center of the storm are focused on developing SAPUI5/OpenUI5 as a useful standalone UI library. This was our plan from the first day and is witnessed by all the efforts going into the OpenUI5 Open Source version. One consideration is always: how can we make it better for that developer with nothing but a text editor and a web server?

 

 

Anyway... I digress... I mentioned that UI5 is hiring! The new teams in Sofia are still growing and have several open positions ranging from Junior Developers to Architects and also including Infrastructure Engineers. They have created a very nice web page introducing SAPUI5, their teams and detailing the job offers:

https://sapuisofia.bg  - it's even worth a look when you are not looking for a job.

If you want to be part of this success story, you just need to move to Sofia... ;-)


And if not, after reading this blog post you can at least move on with the warm feeling that lots of people are doing their best to make UI5 better for you. :-)

SAPUI5 and OpenUI5 and more

$
0
0

Hi all,

 

we would like to share important news although one or the other might have already realized them.

 

OpenUI5

Since last Friday, we have enabled code contributions to OpenUI5. First of all, this obviously gives you the option to contribute to and improve OpenUI5 as well as SAPUI5. So if something is not as expected, you can do more than just asking for help. You now might become active and suggest the appropriate coding that you think will solve the issue or improves the behavior. Besides that, the technical enablement of the open source build has influenced the way how SAPUI5 and OpenUI5 are structured respectively which build tools are used. You can now also e.g. use the build-free development mode based on Node and Grunt as described here https://github.wdf.sap.corp/openui5/openui5/blob/master/docs/developing.md. This gives you and us additional faster development round trips when developing controls or control extensions to SAPUI5/OpenUI5. 

The other aspect that you should consider is the option to find or ask for information not only within the SCN community, but also on stackoverflow using the tags “sapui5” or the search term “openui5”. The appropriate search string is http://stackoverflow.com/questions/tagged/sapui5%20or%20openui5. By implication, when asking a question in stackoverflow the tag to be used is “sapui5”.

You can find more details on http://openui5.org/ .

 

Transparency

Along with the decision to allow code contributions, we have changed the way how our developers work internally. Looking into openui5 on github, you can see the activities of our developers on a very fine granular basis. Basically every commit to one of the open sourced areas of SAPUI5 is directly visible in OpenUI5 as well. This obviously gives you the information on our current priorities but maybe even more importantly, the ability to test with kind of ß-versions before we officially release the software. If many of you would do this, this will help you to avoid surprises when installing the SAP support packages later on and obviously it would help us to realize and fix issues before releasing the software.  As of today, you can assemble your own package using the new build infrastructure, but we’ll also provide pre-packaged archives along internal milestones in the future.   

 

Roadmap handling

As mentioned beforehand, there is already complete transparency based on the fine granular commit messages. However, it is maybe not so easy to decrypt these fine granular messages when being interested in the high level picture. Thus along the tradition of open source projects, we have decided to try to make the product roadmap more transparent so that consumers and potential contributors have this information at hand when planning consumption or code contributions. This will be quite detailed for the next 4 weeks and as detailed as possible for the next release or releases. This information will reflect the internal planning, so please accept that it is not a commitment as there might be problems during execution or there might be changes in priorities/plans. In both cases, the roadmap would be adjusted so that you as soon as possible get a clear picture again.

 

So please discover your new options, provide us with feedback and stay tuned with regard to the roadmap that is going to come soon.      

 

Best regards

Stefan

 

Viewing all 789 articles
Browse latest View live




Latest Images