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

ScrollReveal and SAPUI5

$
0
0


Introduction


ScrollReveal.js is a javascript resource for animating objects as they appear in the viewport. I wanted to make a proof of concept and see if it can work together with SAPUI5.

 

Here a link to the ScrollReveal library webpage also implementing it's own library:

 

https://scrollrevealjs.org/



Using ScrollReveal



First you have to include the javascript with the library with:



<scriptsrc="https://cdn.jsdelivr.net/scrollreveal.js/3.0.9/scrollreveal.min.js"></script>


One way to make it work is apply a class to an element in HTML

 

<!-- HTML -->

<divclass="foo"> Foo </div>

<divclass="bar"> Bar </div>


Start ScrollReveal and apply the reveal method to the required classes.

// JavaScript

window.sr=ScrollReveal();

sr.reveal('.foo');

sr.reveal('.bar');


With that you will implement an animation to the <div> when it enters into the screen when scrolling.


Here the official help:

jlmakes/scrollreveal.js - JavaScript - GitHub


Implement on SAPUI5



We have to be sure that SAPUI5 elements are already loaded when reveal method is called, so we will do it when document is ready and we will apply the reveal to all elements with class "foo".

 

$('document').ready(function(){      window.sr = ScrollReveal();      sr.reveal( '.foo', { delay: 500, scale: 0.9, opacity: 0.1 } );
});

Here an example of a SAPUI5 Panel



You have some panels and when you scroll down and panels enter into screen, they are shown with an animation. You have to check the working example but here a screenshot of a panel making a fade in when you scroll down.


scrollreveal.png


You can see a working example in the following jsbin.


https://jsbin.com/hiyiyo/edit?html,output

 


Conclusion

This was only a test for me if an external library canwork with SAPUI5. What I mean is that I'm not using ScrollReveal in a productive tool but could be a starting poing to someone who starts playing with ScrollReveal and SAPUI5.

 


Run Configurations in SAP Web IDE

$
0
0

With the last SAP Web IDE version for 2015 many new features and improvements were introduced.

One of the biggest improvement was the new Run Configurations UI that was faced lifted and now it is more elegant and user friendly

 

So what is this Run Configurations?

Run configurations enable you to test your app with different settings.

Currently there are 3 different types of configurations:

  • Web Application: lets you test any HTML file in you project.
  • Unit Test: allows you to run any qunit file in your project.
  • SAP Fiori Component on Sandbox: runs the component.js file in a Sandbox FLP.

 

OK, and what can be done there?

First of all, the basics, such as defining whether to use the Frame or a mock server. This can be set from the General tab.

 

But there are some additional cool features that can save you some time.

Do you need to add URL parameters every time you run the app?
Do you find yourself clicking repeatedly before you get to the view you are actually testing?

Not any more! In the URL Components tab, you can now add the URL parameters you use in your app and the URL hash fragment you need for navigating.

 

pic1.png

 

 

You can also run your app with different SAPUI5 versions so you can test your app behavior and see the different look and feel of the different versions.

 

pic1.png

 

Lastly, you can easily change the ABAP backend system consumed by the app or any other destination your app uses without having to go to the neo-app.json file!

 

 

pic1.png

 

More improvements are coming soon, so stay tuned!!

 

Elina

Working with Kendo UI controls in SAPUI5

$
0
0

Intro

Every once in a while, you may find yourself wanting to stretch the visual limits of SAPUI5. Luckily, SAPUI5 provides the option of using other controls libraries. In principle, this should be fairly straight-forward. Some of the 3rd party control libraries are even built on JQuery, and thus share the same foundation as UI5. Including them in your UI5 app should in principle be easy.

In real life, however, most such third-party control libraries need some tweaking in order to be seamlessly integrated in a UI5 environment. This is particularly true when working with XML views, which is the preferred way of creating UI5 applications. XML views in SAPUI5 can have some “quirky” consequences on the related controller Javascript code needed for third-party controls. Also, the fact that most of the documentation for the main third-party control libraries refer to Javascript views, not XML, can pose interesting challenges.

This blog aims to provide a walkthrough of challenges and pitfalls related to using controls from the Kendo UI framework in SAPUI5. I will focus on some simple chart implementations, and show how to use these in XML views. Also, I will show how to feed remote data into the chart controls, using OData.

Note: some of the code screenshots may be difficult to read; please click them in order to enlarge!

Preparations

The following example has been created using the Web IDE on the HANA Cloud Platform – HCP. In the Web IDE, select New->Project from template->SAPUI5 Application. This gives you a simple UI5 application with one view (which should be of type XML).

The next step is to import the CSS and Javascript libraries into the application. Using references to content on the web is not recommended, as this might result in cross-domain errors under certain circumstances (such as when running your app from a Fiori Launchpad).

This is the folder structure with the Kendo JS and CSS libraries:

 

pic1.png

 

Creating the simple app

We’ll create a simple app based on a sample OData service, and implement a Kendo chart control to visualize the data. The Kendo chart control provides a wide range of different chart types; I will show a couple of these. The functionality is similar – once you implement one, you can easily switch to another.

The OData service resides on a Netweaver Gateway system. For the purpose of illustration, I have created a simple table that shows the distribution of zombie observations across the US. (Another distinct advantage of using zombies is the fact that zombie starts with the letter “Z”, which makes it particularly useful for creating custom SAP objects like “zombietable”.)


The OData service based on my zombie table is created in the Gateway Builder (transaction SEGW). This is outside the scope of this blog; there’s an excellent book from SAP Press dealing with these topics.

The resulting metadata of my OData service (extract):

pic2.png

And part of the resulting ZombieSet record set:

pic3.png

With our OData service set up and running, it’s time to do the fun stuff: the Kendo in UI5 application.

The UI5 application

As mentioned, I started by using the Web IDE wizard to create a simple UI5 project. The wizard provides the folder structure we need for our app, and we can also ask it to generate the first view (which should be of type XML). The advantage of XML views is that it forces us to adhere to the MVC pattern, unlike Javascript views which literally allows for any kind of Javascript functionality to be embedded into the view code. (Don’t use Javascript views, use XML! Grown-ups never use Javascript views!!)

If we follow the wizard’s recommendations, we’ll end up having one initial view called “View1” with a related controller.

I already mentioned the need for importing the Kendo CSS and Javascript files into their specific folders (the existing css folder for the CSS files, and Kendo JS files into a specific folder). When this is done, we need to register these in the manifest.json file:

pic4.png

The manifest.json file is a JSON model which acts as the “repository” of resources for our application. It should already contain a reference to the UI5 css file (css/style.css); all we need is to add the remaining Kendo CSS references, and also a specific section for the Kendo Javascript files as seen above. By doing this, there is no need to make references to these resources in the index.html file.

Our XML view file will be quite simple. All it contains is a “div” element which holds our Kendo chart (and another div to encapsulate it). This is the code:

pic5.png

That’s it – really. I promise the controller will be a bit more complicated!

Kendo source code

In order to include a Kendo UI control, we need to embed some Kendo Javascript code into our view controller. The Kendo UI site contains sample code for all of the Kendo controls. Ideally, all we would have to do is copy the code related to “our” control (the Kendo chart in our case) and paste it into our view controller. However, there are two major hurdles waiting for us: the fact that we’re using XML views, and that Kendo controls only work with JSON data. Since we’re in an SAP environment, we’re of course using OData, and as already mentioned we also decided to stick to XML views.

Both of these hurdles require some tweaking of the Kendo code.

Let’s look at the standard Kendo code for a bar chart:

pic6.png

This is an excerpt. As we can see, the data source here is a JSON model. This will not work for us; we receive our remote data in OData format, and what we need to do is convert this into JSON.

Luckily, this is easy enough with SAPUI5 – we’ll see that in a minute.

Here is the controller code, section by section.

pic7.png

The main part here contains the onAfterRendering method. This is where we invoke the Kendo script – we do this after SAPUI5 has finished the general rendering of the view, that is, built all the standard UI5 framework elements.

We start by declaring our OData service url, and the path to the relevant record set within this service.

We then define a variable for the OData model.

Then, we set the scope variable that equal to this. “this” is a reference to the current scope, or “where we are now” in layman’s terms. By defining a new variable “that” and aligning it with “this”, we can refer to the createChart function inside the “success” callback function for our oDataModel.read logic. OK, this might seem complex (as promised), but the main idea is that we need to keep a reference to “where” we can retrieve the createChart function. Without using the “that” variable, we will loose sight of it within the “success” function, since we will have another scope there – “this” will not refer to the context where createChart is defined anymore.

It’s a bit like going through a wormhole to another universe, and trying to find Andromeda by looking at the sky. Won’t work. By declaring “that” before going, and taking it with you, you won’t be lost.

What goes on inside the “success” function – which is only invoked if the read of the OData model succeeds – is that we call the createChart function (I’ll get to it in a minute), then invoke a couple of Kendo-related commands that adds attributes to the finished chart.

The next part of our controller contains the actual Kendo chart function:

pic8.png

This is almost a copy/paste of the code from the Kendo samples site. The only things changed are the variable names (ZombieNumber and ZombieCity, from our OData model), as well as the “selector” – which actually warrants a section of its own. Finally, the specification of our data source and schema, which is also explained in detail below.

 

Use of selectors in Kendo code

Kendo JS is based on JQuery, and uses “selectors” in order to identify page elements. Selectors are a key concept in JQuery (and thus SAPUI5) – this is worth reading up on. As in "the following section won't make much sense if you don't know what a selector is". I've provided a link to some excellent info further down.

Anyway, this whole selector thing poses a specific challenge when working with SAPUI5 XML views. In these views, the element id’s are “amended” by SAPUI5 on rendering. What happens is that the view name is added as a prefix to the element id, in order to uniquely define elements across views. Here is an example:

In our Kendo chart, the “div” element is named “chart”, as seen below:

pic9.png

What happens if we simply paste the standard Kendo Javascript code into our controller – with a selector “chart”? Let’s look at how the sample Kendo code appears:

pic10.png

This is the start of the createChart function, as retrieved from the Kendo sample site. As we can see, the function starts by using a selector identifying the “chart” element in our XML page. What happens if we use the code with the selector “as-is”?

The chart will not appear. This is because of the re-naming of our div element by the SAPUI5 rendering. If we look at the debugger, we can expand the elements to find our div:

pic11.png

As can be seen, SAPUI5 prefixes the element id with two underscores, followed by the view name (which, by the way, does not correspond to the actual view name as given by us; SAPUI5 generates brand new view names following the convention “xmlviewN”, where N is a number starting with 0), then two dashes, then finally our given id for the chart. Thus, “chart” in “View1” becomes “__xmlview0—chart”.

What we need to do, is tweak the Kendo code to correspond to the “new” naming done by SAPUI5. By altering the above selector slightly, we can make it look for all “div” elements containing the string “chart”:

pic12.png

Note that I am also passing our JSON “myData” to the function – this is my JSON model as derived from the original OData service. The main thing here is that the selector now works also in an SAPUI5 XML content.

More info on JQuery selectors and how to build them can be found here:

http://www.w3schools.com/jquery/jquery_ref_selectors.asp

Data provisioning - stuffing our charts with zombies

Kendo UI controls work with static, local or remote data. Static in this context means hard-coded values in the Javascript code for the Kendo control. This is usually not too interesting from an SAPUI5 point of view.

Local data relate to locally defined JSON models. This also amounts to hard-coding for mockup scenarios, and is also not very interesting for “real” applications.

Our example works with remote data – provided by a Gateway OData service. For use in the Kendo controls, the data will have to be in JSON format. Because of this “limitation”, we translated the data to JSON format when reading the OData service.

One issue with this way of providing JSON data from an OData source is that the Kendo code has issues with “complex” data models, such as the ones provided by OData-to-JSON conversion. If we simply declare our chart by copying and pasting the generic Kendo sample code, like most exampoles found on the site (related to JSON models) we may run into problems.

Running “standard” Kendo chart code will easily result in the following error:

pic13.png

This is due to the relative complexity of our JSON data:

pic14.png

Note the “results” element at the top of the JSON structure.

In order to resolve this, we need to declare a “schema” in our dataSource parameter for the chart:

pic15.png

Here, we declare the header node = “results” – this is all that is needed to enable Kendo to correctly traverse the JSON model.

A Kendo forum post regarding this issue can be found here:

http://www.telerik.com/forums/kendo-chart-e-slice-is-not-a-function-with-remote-data

 

Resulting UI

The result of our efforts:

pic16.png

As can be seen, Las Vegas is the place to steer clear of, regarding zombies.

Changing the chart type: Donut chart

With the above framework in place, it’s fairly easy to create new chart types. We simply alter the createChart function to specify a different type:

pic17.png

Result:

pic18.png

(Note that some chart types are suitable for specific types of data – depending on the complexity of the data).

I hope this provided some ideas of what is possible; the concepts should be useful also for other 3rd party UI libraries.

These examples were developed using Web IDE on a HANA Cloud platform, with data pulled from a Gateway system.


SAPUI5 and Twitter API

$
0
0

Hi,

 

This blog will show how to use the Twitter REST API in a SAPUI5 application.  In this example I will use the Twitter Search API (search/tweets.json).

All other API services can be found here: API Console Tool | Twitter Developers. (Log on with your twitter account)

 

Prerequisites:

 

- create a Twitter application (Twitter Application Management)

- retrieve: Customer Key, Customer Secret, Access Token and Access Token secret.

 

Creating a signature

 

This explains how to generate an OAuth 1.0a HMAC-SHA1 signature for a HTTP request. This signature will be suitable for passing to the Twitter API as part of an authorized request.


first we have to declare some variables:

 

var customer_key = "a5IGWlSrrLyI7GEPV5ZMY1MiP";
var customer_secret = "Ey9xYIZwSPfuMZhS4IItTbWB4hXQD7resrPJpYbGc4PeMJBRdp";
var access_token= "2744465306-RGKnQQl5l5p1bZBNlUqbYrEROBqvZx6ij5ZIOos";
var access_token_secret = "pQ2TvVjUOeqPE0Eyk7OekzKIPGzcDvTNBZuUmAZiH9awd";                                        
var signing_key = customer_secret + "&" + access_token_secret;                                        
var signature_method = "HMAC-SHA1";
var authorization_version = "1.0";
var method = "GET";
var protocol = "https";
var server = "api.twitter.com";
var version = "1.1";
var service = "search/tweets.json";


STEP 1: Create base url:

 

The base URL is the URL to which the request is directed, minus any query string or hash parameters.

 

var BaseURL = protocol + "://" + server + "/" + version + "/" + service;


STEP 2: Collect your parameters:

 

Next, gather all of the parameters included in the request.


var callback = "callback=twitterCallback";
var count = "count=" + this.count;
var language = "lang=" + this.lang;
var oauth_consumer_key = "oauth_consumer_key=" + customer_key + "&";
var oauth_nonce = "oauth_nonce=" + this.makeid() + "&";
var oauth_signature_method = "oauth_signature_method=" + signature_method + "&";
var oauth_timestamp = "oauth_timestamp=" + Math.floor(Date.now() / 1000) + "&";
var oauth_token = "oauth_token=" + access_token + "&";
var oauth_version = "oauth_version=" + authorization_version + "&";
var query = "q=" + encodeURIComponent(oEvent.getParameter("query"));
var result_type = "result_type=" + this.resultType;


STEP 3: create authorization parameter string and search options:

 

var oauth_parameters = oauth_consumer_key + oauth_nonce + oauth_signature_method + oauth_timestamp + oauth_token + oauth_version;
var searchOption = query + "&" + count + "&" + result_type;


STEP 4: Create parameterstring:

 

this is a very important step: concatenate all parameters alphabetically:

 

var parametersString = callback + "&" + count + "&" + language + "&" + oauth_parameters + query + "&" + result_type;


STEP 5: Create signature string:

 

  1. encode the complete parameter string
  2. encode the base url
  3. append the method. (method in upper case!!!)

 

var signatureBaseString = method + "&" + encodeURIComponent(BaseURL) + "&" + encodeURIComponent(parametersString);

 

it should look like this:

 

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fsearch%2Ftweets.json&callback%3DtwitterCallback%26count%3D100%26lang%3Dnl%26oauth_consumer_key%3Da5IGWlSrrLyI7GEPV5ZMY1MiP%26oauth_nonce%3DoJV2FF2PtC%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1453384662%26oauth_token%3D2744465306-RGKnQQl5l5p1bZBNlUqbYrEROBqvZx6ij5ZIOos%26oauth_version%3D1.0%26q%3Datos%26result_type%3Dmixed



STEP 6: Calculating the signature:


In this step we create the authorization signature.

 

Therefore, I use 2 scripts from CryptoJS ( crypto-js -   JavaScript implementations of standard and secure cryptographic algorithms - Google Project Hosting )

 

 

I downloaded them to my project folder and use them in my application:

 

jQuery.sap.require("TwitterSearch_v002.util.HMACsha1");
jQuery.sap.require("TwitterSearch_v002.util.EncodeBase64");

 

First I used:

 

jQuery.sap.includeScript("http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js");
jQuery.sap.includeScript("http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js");

 

but I get the message:

 

Mixed Content: The page at 'https://webidetesting1208672-s0009219687trial.dispatcher.hanatrial.ondemand…onentPreload=off&origional-url=index.html&sap-ui-appCacheBuster=..%2F..%2F' was loaded over HTTPS, but requested an insecure script 'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js'. This request has been blocked; the content must be served over HTTPS.t @ sap-ui-core.js:88

sap-ui-core.js:88 Mixed Content: The page at 'https://webidetesting1208672-s0009219687trial.dispatcher.hanatrial.ondemand…onentPreload=off&origional-url=index.html&sap-ui-appCacheBuster=..%2F..%2F' was loaded over HTTPS, but requested an insecure script 'http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js'. This request has been blocked; the content must be served over HTTPS.

 

getting the signature:

 

var hash = CryptoJS.HmacSHA1(signatureBaseString, signing_key);
var base64String = hash.toString(CryptoJS.enc.Base64);
var oauth_signature = encodeURIComponent(base64String);


STEP 7: Build the url

 

ok, so now we have averything to build our url to call the API:

 

concatenate as follow:

 

var URL = BaseURL + "?" + searchOption + "&" + oauth_parameters + "oauth_signature=" + oauth_signature + "&" + language + "&" + callback;

 

So now we have the url to retrieve the data.

 

Getting the data

 

I use JSONP to retrieve the data via a callback function.  The Twitter API supports the use of JSONP. In the beginning we have added the parameter "callback" to the parameter string. The name of the function can be chosen.  In this example I use "twitterCallback". Don't forget to add this parameter in the parameter string!!

 

first you have to inject the script in the header of the page:

 

var socialGetter = (function() {  /* just a utility to do the script injection */  function addScript(url) {  var script = document.createElement('script');  script.async = true;  script.src = url;  document.body.appendChild(script);  }  return {  getTwitterTweets: function(url) {  addScript(url);  }  };  })();

 

then, you have to define the callback function:

 

                                                window.twitterCallback = function(data) {                                                                if (data) {                                                                                var twitterResult = new sap.ui.model.json.JSONModel();                                                                                twitterResult.setData(data);                                                                                sap.ui.getCore().byId("__xmlview0").setModel(twitterResult, "twitterResult");                                                                }                                                };

 

notice that I use "window.twitterCallback". this is because a callback method is always a global function, so you have to declare a global function.

 

with this code:

 

 

sap.ui.getCore().byId("__xmlview0").setModel(twitterResult, "twitterResult")

;

I retrieve the search view and set the model "twitterResult".

 

ok, so now we can call the url:

 

socialGetter.getTwitterTweets(URL);

 

View

 

In the view I use a list of objectListItems:

 

<List busyIndicatorDelay="{masterView>/delay}" growing="true" growingScrollToLoad="true" id="list"  items="{ path: 'twitterResult>/statuses', sorter: { path: 'accountID', descending: false }, groupHeaderFactory: '.createGroupHeader' }"  mode="{= ${device>/system/phone} ? 'None' : 'SingleSelectMaster'}" noDataText="{masterView>/noDataText}" selectionChange="onSelectionChange"  updateFinished="onUpdateFinished">  <infoToolbar>  <Toolbar active="true" id="filterBar" press="onOpenViewSettings" visible="{masterView>/isFilterBarVisible}">  <Title id="filterBarLabel" text="{masterView>/filterBarLabel}"/>  </Toolbar>  </infoToolbar>  <items>  <ObjectListItem icon="{twitterResult>user/profile_image_url}"  intro="{twitterResult>user/name} - {twitterResult>created_at} - {twitterResult>user/location}" press="onSelectionChange"  title="{twitterResult>text}" type="{= ${device>/system/phone} ? 'Active' : 'Inactive'}"></ObjectListItem>  </items>  </List>

 

an example of a tweet looks like this:

 

 

"statuses": [   {  "metadata": {  "iso_language_code": "en",  "result_type": "recent"   },  "created_at": "Thu Jan 21 14:47:27 +0000 2016",  "id": 690183933741310000,  "id_str": "690183933741309954",  "text": "Throwback Thursday    // NYC shoot with elite_e46 for @pbmwmagazine // #meatyflush #bmw #bmwusa… https://t.co/7w1x7293Sf",  "source": "<a href="http://instagram.com" rel="nofollow">Instagram</a>",  "truncated": false,  "in_reply_to_status_id": null,  "in_reply_to_status_id_str": null,  "in_reply_to_user_id": null,  "in_reply_to_user_id_str": null,  "in_reply_to_screen_name": null,  "user": {  "id": 2418867279,  "id_str": "2418867279",  "name": "MeatyFlush",  "screen_name": "MeatyFlush",  "location": "DMV",  "description": "We are a photography collective who's sole purpose is to capture the car scene featuring some of the hottest and greatest automobiles in the DMV.",  "url": "http://t.co/lk0XSiqxNR",  "entities": {  "url": {  "urls": [   {  "url": "http://t.co/lk0XSiqxNR",  "expanded_url": "http://meatyflush.com",  "display_url": "meatyflush.com",  "indices": [  0,  22   ]   }   ]   },  "description": {  "urls": []   }   },  "protected": false,  "followers_count": 57,  "friends_count": 14,  "listed_count": 14,  "created_at": "Tue Mar 18 01:02:57 +0000 2014",  "favourites_count": 19,  "utc_offset": null,  "time_zone": null,  "geo_enabled": false,  "verified": false,  "statuses_count": 1552,  "lang": "en",  "contributors_enabled": false,  "is_translator": false,  "is_translation_enabled": false,  "profile_background_color": "C0DEED",  "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",  "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",  "profile_background_tile": false,  "profile_image_url": "http://pbs.twimg.com/profile_images/519541485772214272/aKA7PMCO_normal.jpeg",  "profile_image_url_https": "https://pbs.twimg.com/profile_images/519541485772214272/aKA7PMCO_normal.jpeg",  "profile_banner_url": "https://pbs.twimg.com/profile_banners/2418867279/1395120295",  "profile_link_color": "0084B4",  "profile_sidebar_border_color": "C0DEED",  "profile_sidebar_fill_color": "DDEEF6",  "profile_text_color": "333333",  "profile_use_background_image": true,  "has_extended_profile": false,  "default_profile": true,  "default_profile_image": false,  "following": false,  "follow_request_sent": false,  "notifications": false   },  "geo": null,  "coordinates": null,  "place": null,  "contributors": null,  "is_quote_status": false,  "retweet_count": 0,  "favorite_count": 0,  "entities": {  "hashtags": [   {  "text": "meatyflush",  "indices": [  70,  81   ]   },   {  "text": "bmw",  "indices": [  82,  86   ]   },   {  "text": "bmwusa",  "indices": [  87,  94   ]   }   ],  "symbols": [],  "user_mentions": [   {  "screen_name": "PBMWmagazine",  "name": "PBMW",  "id": 169887768,  "id_str": "169887768",  "indices": [  53,  66   ]   }   ],  "urls": [   {  "url": "https://t.co/7w1x7293Sf",  "expanded_url": "https://www.instagram.com/p/BAzhLBmPkIE/",  "display_url": "instagram.com/p/BAzhLBmPkIE/",  "indices": [  96,  119   ]   }   ]   },  "favorited": false,  "retweeted": false,  "possibly_sensitive": false,  "lang": "en"   }

 

the output looks like this:

 

Clipboard01.jpg

 

Enjoy!!

 

bye

How to run SAP Web IDE Offline application in Windows 10 ?

$
0
0

Ever wondered how to run your SAP Web IDE application in Windows 10 laptops or desktops.  Hybrid Application Toolkit (HAT) only supports Android and iOS platforms.  The steps below show how you can run the SAP Web IDE application in Windows platforms. Since running an Offline application has a few additional steps, this blog talks about the Offline application. For Online application, some of the steps are not required. I have marked the steps not required for Online applications.  Simply skip those steps for Online applications.

 

 

Installing Visual Studio 2015 Community Edition

          WebIDE1.png

  • Choose the Custom option.  Select HTML/JavaScript (Apache Cordova) under Cross Platform Mobile Development

          WebIDE2.png

  • Complete install

 

Export SAP Web IDE project to local development machine

  • Right click on SAP Web IDE project and click Export

          WebIDE4.png

  • Extract the downloaded zip file

 

Create Apache Cordova Visual Studio project

  • Create a new project in Visual Studio.  Select the option Apache Cordova Apps under JavaScript.

          WebIDE5.png

 

Copy SAP Web IDE project files into Visual Studio project

  • Copy the extracted files from the SAP Web IDE project into the www folder of the newly created Visual Studio project.  Do not delete any files in the www folder, but you can overwrite the files.

          WebIDE6.png

 

Rename .project.json file and any reference to it

  • Rename .project.json file to project.json in Visual Studio
  • Also edit devapp.js file to use project.json instead of .project.json

          WebIDE7.png

 

Edit Index.html file

  • The index.html file gets overwritten by the SAP Web IDE project files.  However, there are 2 lines of code that needs to be restored. Modify index.html to add the following 2 lines of code

 

<scriptsrc="scripts/index.js"></script>

<scriptsrc="scripts/platformOverrides.js"></script>

 

          WebIDE8.png

 

Download SAP UI5 resources and copy them to www folder

          WebIDE9.png

 

Copy datajs file to www folder

 

Add Kapsel plugins to Visual Studio project

  • Open config.xml file in Visual Studio and click on Plugins tab in the left pane
  • Click on Custom tab.  Browse to desired Kapsel plugin and click Add

          WebIDE10.png

  • Note that you will have to add any SAP Kapsel dependencies one by one.  Dependencies available on the public git repository are automatically installed by Visual Studio
  • Note that the OData Kapsel plugins has dependency on certain native Windows libraries. The following section will show you how to add those dependencies

 

Adding references to native Windows libraries (Offline only)

  • Build the solution (do not run).  Select Windows x-64 as the solution platform
  • Close the Visual Studio project
  • Browse to the following folder <Solution folder>\<Solution>\platforms\windows
  • Open the CordovaApp.sln file.  Select x-64 as the solution platform
  • Right click on the CordovaApp.Windows (Windows 8.1) project and add the following references

          WebIDE11.png

  • Add Microsoft Visual C++ Runtime Package for Windows as a reference
  • Add the *.winmd files (add all 3 of them) found in the OData plugin folder as references

          WebIDE12.png

  • Click OK to complete adding the references
  • Your references should now look like this without any warnings or errors

Disabling sap.Xhook (Offline only)

  • This step is necessary to fix a bug with synchronous requests.  Once the bug is fixed in SP11, you do not have to do this step…
  • Edit the file www\dev\devlogon.js and add the following line in openStoreSuccessCalllback function

 

sap.Xhook.disable();

 

          WebIDE15.png

Run the project

  • Select x64 as Solution Platforms and LocalMachine.  Run the project

          WebIDE16.png

 

 

In the next blog, I will show you how to debug the SAP Web IDE application running in Windows platforms.

Simple UI5 application on SAP Web IDE

$
0
0

Hello Friend,


I'm writing this blog post to share my experience on a specific development task on SAP Web IDE. If anybody wants to learn SAP UI5 through Online they can use SAP Web IDE.


Step 1:  Open the SAP WEB IDE URL (SAP Web IDE URL) and login into the your SCN credentials.

0.JPG

Step  2:   Create New project( File- New -  Click on “Project from Template”

3.JPG

Step 3:Select the application under “Template Selection” depending upon the requirement either FIORI, UI5, Smart Template application.

4.JPG

Select the applications under the drop-down as per below screen shot.
5.JPG

So I am selecting “SAP UI5 Application” as per below screen.

Step 4: Search the SAP UI5 under “Search” we will knows the which version we are using this application

6.JPG

Step 5: Select “SAP UI5” application Click on “Next” Button and give the Project Name.

7.JPG

Step 6: Select “View Type” and Change the View Name as per the requirement under “Initial View Details” View Type like XML, Java Script, JSON and HTML

8.JPG

Click on Next and Finish.

9.JPG

10.JPG

Step 7: After creating the application. If you’re not able to see application in left hand side. Then go to View---- Click on “Reset to Default”. Then able to see the applications


Step 8: Created simple form using “JS”. I wrote the in “Simple.View.JS”, “Style.css” and “i18n.properties".

                         Simple.View.JS------ create Simple Form

                         Style.CSS -------------UI Alignment

                         i18n.properties ---------------All Label Name are available under this properties file.


Simple.View.JS

11.JPG

Style.CSS

12.JPG

i18n.properties

13.JPG

Step 9: We have two ways to check the output

           Right click on “Application Name” ---- Run------Run As -------click on “Web Application”.


14.JPG

Output

14.1.JPG

If you want deploy the application ether UI5 ABAP repository, HANA Cloud platform and SAP FIORI Launchpad. Refer below screen shot.

15.JPG


Hope this is help full,


Thank you for reading this blog and let me know in case of any issues.


Regard

Vijay Kalluri


Drag and Drop functionality in sap.m.List

$
0
0

Hi Team,

 

Introduction:

 

In computer graphical user interfaces, drag and drop is a pointing device gesture in which the user selects a virtual object by "grabbing"

it and dragging it to a different location or onto another virtual object.

 

In SAP UI5 control:

 

SAP UI5 has predefined jquery library to develop drag and drop functionality.Few of them are used here.

Drag and drop is a very common feature. It is when you "grab" an object and drag it to a different location.

 

Project Link: http://jsbin.com/qoxuha/edit?html,output

 

 

Code snippet:


$.sap.require('sap.ui.thirdparty.jqueryui.jquery-ui-core');

$.sap.require('sap.ui.thirdparty.jqueryui.jquery-ui-widget');

$.sap.require('sap.ui.thirdparty.jqueryui.jquery-ui-mouse');

$.sap.require('sap.ui.thirdparty.jqueryui.jquery-ui-draggable');

$.sap.require('sap.ui.thirdparty.jqueryui.jquery-ui-sortable');

 

$(function() {

$("#lb1-listUl, #lb2-listUl").sortable({

connectWith : ".ui-sortable"

}).disableSelection();

});

 


Regards,

Karthik A

ABAP Active Record Kick-off Post - SAPUI5 Community Feedback

$
0
0

Inspired by the Ruby on Rails Active Record, I started to work on an idea to replicate the concept of Active Record in SAPUI5. This post it to present that idea to community and get feedback. So comments are welcome.

I published entire project at Github and pull requests are very welcome as well.

Note: I spend some time thinking if it’s fits better here or on ABAP Development community. Then I decide to write two posts. If you want to see the project from ABAP perspective, check this blog, otherwise keep reading.

Motivation

Imagine that you need to retrieve some records for a given sales order type from VBAK table. Later in the program you need to retrieve a set of materials from MARA table. Then some company code details from T001 table. Then deliveries from LIKP table. If you are using SAP Gateway, you need to create a service or entity type for each one of those requests.

In order to avoid to create a new SAP Gateway service or entity type/set for simple retrieval records from SAP tables, the ABAP Active Record give direct access into the SAP tables in a very simple way.

It’s not the goal of this project to replace all programming at back-end, but avoid create new SAP Gateway objects just for some “incidental” table access.

How It Works

Suppose you need to retrieve all prices for flights of Lufthansa (LH) and connection 2402 from SFLIGHT table.

First, in SAPUI5 code create ABAP Active Record object:

var oARModel = new abapActiveRecord.ARModel();

Then, retrieve a data set (JSON) from ABAP Stack, choosing table, fields and filter

var oFlightsTable = oARModel.aarGetEntitySet('SFLIGHT', ["CARRID", "CONNID", "FLDATE", "PRICE"], {carrid: "LH", connid: "2402"});

Done.

Here is the JSON Model returned by aarGetEntitySet method call above:

{"SFLIGHT":[ {"CARRID":"LH","CONNID":"00002402","FLDATE":"08/21/1997","PRICE":"555,00"},

{"CARRID":"LH","CONNID":"00002402","FLDATE":"08/22/1997","PRICE":"590,00"},

{"CARRID":"LH","CONNID":"00002402","FLDATE":"08/25/1997","PRICE":"490,00"},

{"CARRID":"LH","CONNID":"00002402","FLDATE":"08/30/1997","PRICE":"485,00"} ]}

 

Repeat the same procedure for any other SAP table (SPFLI, MAKT, BKPF, T001W etc.). No auto-generate code is necessary. Just call proper methods with proper parameters.

CRUD Methods

It’s also allowed to execute the CRUD (Create, Read, Update and Delete) methods.

Create

Create a record on SFLIGHT table:

oARModel.aarCreate('SFLIGHT', {carrid: "LH", connid: "2402", fldate: "20160119", price: "500.00"});

Read (SELECT)

Retrieve a set of records:

var oFlightsTable = oARModel.aarGetEntitySet('SFLIGHT', ["CARRID", "CONNID", "FLDATE", "PRICE"], {carrid: "LH", connid: "2402"});

The JSON model will be like bellow:

oFlightsTable.getProperty('/')

"{"SFLIGHT":[{"CARRID":"LH","CONNID":"00002402","FLDATE":"08/21/1997","PRICE":"555,00"}, ... ]}"

Read Simple Value (SELECT SINGLE)

Read a single value from a specific record at table SFLIGHT (select single):

var value = oARModel.aarGetEntity("SFLIGHT", "PRICE", {carrid: sap.ui.getCore().byId("carrid").getValue(),connid: sap.ui.getCore().byId("connid").getValue(),fldate: sap.ui.getCore().byId("fldate").getValue()});

Return the actual value of field PRICE in to variable value , "500.00".

Update

Update a record on table SFLIGHT:

oARModel.aarUpdate("SFLIGHT", {carrid: "LH", connid: "2402", fldate: "20160119", price: "350.00"});

New value of PRICE: "350.00".

Delete

Delete a record on table SFLIGHT:

oARModel.aarDelete('SFLIGHT', {carrid: "LH", connid: "2402", fldate: "20160119"});

Under the Hood

In the SAPUI5 side, I extended sap.ui.model.odata.ODataModel class and implemented methods for basic CRUD operations and return data in JSON format.

Those methods basically will parse all parameters in the CRUD methods above and create batch calls to be submitted to SAP Gateway.

The second main responsibility is “translate” the return from SAP Gateway:

<model>SFLIGHT</model>

<field>CARRID</field>

<value>LH</value>

<model>SFLIGHT</model>

<field>CONNID</field>

<value>2402</value>

<model>SFLIGHT</model>

<field>FLDATE</field>

<value>08/21/1997</value>

...

 

To JSON format:

{"SFLIGHT":[ {"CARRID":"LH","CONNID":"00002402","FLDATE":"08/21/1997","PRICE":"555,00"}, {"CARRID":"LH","CONNID":"00002402","FLDATE":"08/22/1997","PRICE":"590,00"}, {"CARRID":"LH","CONNID":"00002402","FLDATE":"08/25/1997","PRICE":"490,00"}, {"CARRID":"LH","CONNID":"00002402","FLDATE":"08/30/1997","PRICE":"485,00"} ]}

Installation

You can find installation instructions in this guide.

Feedback

I started this project to share my idea and the initial proof of concept. I’m not consider ready to be used in production and improvements are needed. However, in the pure open source spirit, I decided to share my idea and receive feedback from the community.


sap.viz.ui5.controls.VizFrame TimeSeries_line Chart

$
0
0

Hello Every one,

Here is an attachment for the working model of timeseries_line Chart .

As VIZ charts are deprecated now we are using VIZFrame Control Charts which provides all the functionalities which VIZCharts and some extra functionalities

Create Smart Template Project.........SAP WEB IDE

$
0
0

Hi All

 

SAP Recently Release SMART TEMPLATE  Project on SAP WEB IDE.

 

its completely Based on Annotation no need to write  Code on JS or XMl etc.

 

SO to Create SMART TEMPLATE Project Following steps are.

 

STEP1

 

Create Account on Cloud Cockpit and open SAP HANA Cloud Platform Cockpit

 

and click on Destnation .

1.PNG

 

STEP 2 . Create NORTWIND Destnation  click here How to use Northwind OData service with SAP Web IDE

 

2.PNG

 

STEP 3

 

Click Services and 1st column click flpportal

3.PNG

then click Application URL

4.PNG

 

After that you will enter  SAP WEB IDE HOME PAGE like this

5.PNG

STEP 4

 

Click NEW ->PROJECT FROM TEMPLATE

 

6.png

 

STEP 5

 

Select SMART TEMPLATE Project

and click on NEXT

7.PNG

STEP 6

 

Enter the Project Name and Title Click on NEXT

 

STEP 7

 

DATA Connection  Click Service URL -> Select Northwind ODATA Services -> Write URI As  Northwind/Northind.svc => Click NEXT

 

8.PNG

 

STEP 8

 

Go your DESKTOP  Create a File name as  "metadata.xml"

put this code inside file

 

<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"

    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData">

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

        <Schema Namespace="NorthwindModel" sap:schema-version="1" xmlns="http://docs.oasis-open.org/odata/ns/edm">

 

        </Schema>

    </edmx:DataServices>

</edmx:Edmx>

 

STEP 9

 

click Add annotation file => select From file system

9.jpg

 

 

STEP 10

 

Browse yr metadata.xml file form Desktop and click OK button

10.PNG

then you will get a file "local_Annotation.xml " will be created

then click Next

11.PNG

STEP 11

 

Chose ODATA Collection and ODATA  Navigation

12.PNG

 

then Click Next Then click finish

 

 

 

NOW YOU HAVE BEEN CREATED SMART TEMPLATE PROJECT.

 

 

NO got At your PROJECT  and  open it

u wil get this  format of your Project

13.PNG

Here annotation folder consist Annotations file which is used for editing or adding some additional controls because we cant write JS or XML code .we can add controls only from Annotations.

 

i18n folder contain some Standard text which is display on output screen you can edit also.

 

localServices folder contains northwind metadata file and mockserver file.

 

for running the project  Select flpSandbox.html and click on Run

 

and you will get this view at output

14.PNG

 

here click on 1st tiles  then you will get OVERVIEW PAGE like this

15.PNG

its is the overview page of smart template

 

i have attached project file.

 

SO its was the HOW TO CREATE SMART Template PROJECT .

 

and  for Editing or adding some controls pls  click here

Adding Controls on Smart template  using Annotations...SAP WEB IDE

 

thank you

 

Virendra

Adding Controls on Smart template using Annotations...SAP WEB IDE

$
0
0

Hi  all

 

i have created a blog

Create Smart Template Project.........SAP WEB IDE

 

Now in Smart template if we want to add some controls like Data Field,Line item , Data point , presentation Variant etc

 

we don't need to write code on JS , XML , HTML etc we can add controls by using Annotation file .

 

 

STEP 1.

16.png

open Annotation folder => right click on annotation.xml

 

here you can open 3 way.

 

code editor - you to wirte code your self .which can be difficult

 

so open file by Annotation Modeler after click this u will get

17.PNG

 

Click on Green icon

 

18.PNG

here you can chose function what you want add on smart template project.

 

 

Example 1 : i want to add on line item  one Action button and one Navigation Button on overview page like this

 

19.png

so to create this select UI.LineItem and click Ok

 

then click Plus Icon on Line Item you will get

 

 

20.PNG

here you have to select controls according to your req.

 

now i select DatafieldforAction and DatafieldForIntentBasedNavigation

now you will see

21.PNG

Now click 1st one Data filed for Action U will get from Right side u have to fill.den

like this

22.PNG

click on apply Save Project

 

Run The Project Again

 

now when i run then project i got my desire output

23.PNG

 

So it was just a example .

 

plz do comment for any controls.which you want add on overview Page or List view Page

 

 

 

Regards

Virendra

Smart Table - Backend and Frontend Example

$
0
0

Hello Fellow SCNers,

 

In this blog, I will demo the usage of Smart Table control including OData Metadata development and Front End application code.

Smart Table uses Vocabulary based annotations in OData.

 

Backend

 

Data Structure and Data preparation



Step 1: Go to SE11 and create a table as shown below.

Table.jpg

Step 2: Populate the data and check.

Data.jpg


Service Creation


Step 3: Import the highlighted vocabulary(ies) in SEGW(Project Builder Transaction). (This is a one time activity)

 

Vocab.jpg

Step 4: Create a Service with Vocabulary Based Annotation as

 

Serv Det 1.jpg

Step 5: Create an Entity - SmartTable and corresponding EntitySet. These are standard steps and I am ignoring them here, though I have attached screenshot of the same.

 

Serv Det 2.jpg

Properties -

Serv Det 3.jpg

Step 6: Import the vocabulary in the Service as -

 

Import Vocab.jpg

Step 7: Create the Line Item Annotation which is the most important one for Smart table as it will help the UI5 framework to create table structure.

Choose the line item column and then click on Create Annotation.


Line Item.jpg

Step 8: Click on 'Append Row/Create'


Line Item 2.jpg

Step 9: Choose the highlighted type for property

 

Line Item 3.jpg

Step 10: One column is created as shown below -


Line Item 4.jpg

Do the above step for all 4 columns.

 

Step 11: Now the service will look like -

 

Proj 1.jpg

Step 12: Implement the Getter for Smart Table Entityset too -


Getter.jpg

Now the metadata should look like below

 

<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData" Version="1.0">

 

 

<edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"Uri="https://<host:port>/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_UI',Version='0001',SAP__Origin='LOCAL')/$value">

 

 

<edmx:Include Namespace="com.sap.vocabularies.UI.v1"/>

 

</edmx:Reference>

 

<edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"Uri="https://<host:port>/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_CORE',Version='0001',SAP__Origin='LOCAL')/$value">

 

 

<edmx:Include Namespace="Org.OData.Core.V1"/>

 

</edmx:Reference>

 

<edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"Uri="https://<host:port>/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMUNICATION',Version='0001',SAP__Origin='LOCAL')/$value">

 

 

<edmx:Include Namespace="com.sap.vocabularies.Communication.v1"/>

 

</edmx:Reference>

 

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

 

 

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

 

 

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

 

 

<Key>

 

 

<PropertyRef Name="Bname"/>

 

</Key>

<Property Name="Bname" Type="Edm.String" Nullable="false" MaxLength="12" sap:label="User"/>

<Property Name="Fullname" Type="Edm.String" Nullable="false" MaxLength="80" sap:label="Complete name"/>

<Property Name="SmtpAddr" Type="Edm.String" Nullable="false" MaxLength="241" sap:label="E-Mail Address"/>

<Property Name="Location" Type="Edm.String" Nullable="false" MaxLength="40" sap:label="Location"/>

</EntityType>

 

<EntityContainer Name="ZSMARTTABLE4_Entities" m:IsDefaultEntityContainer="true">

 

 

<EntitySet Name="SmartTableSet" EntityType="ZSMARTTABLE4.SmartTable" sap:content-version="1"/>

 

</EntityContainer>

 

<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="SmartTable">

 

 

<Annotation Term="com.sap.vocabularies.UI.v1.LineItem">

 

 

<Collection>

 

 

<Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation">

 

 

<PropertyValue Property="Label" String="Location"/>

 

<PropertyValue Property="Target" AnnotationPath="Location"/>

</Record>

<Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation"/>

 

<Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation">

 

 

<PropertyValue Property="Label" String="Location"/>

 

<PropertyValue Property="Target" AnnotationPath="Location"/>

</Record>

<Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation"/>

</Collection>

</Annotation>

</Annotations>

<atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="self" href="<host:port>/sap/opu/odata/sap/ZSMARTTABLE4/$metadata"/>

<atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="latest-version" href="<host:port>/sap/opu/odata/sap/ZSMARTTABLE4/$metadata"/>

</Schema>

</edmx:DataServices>

</edmx:Edmx>

 

Front End Code

 

Step 13: For sake of simplicity I have put the Smart Table in Index.html file and run it.

 

<!DOCTYPE html>

<html><head>

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

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

<title>Smart Table</title>

 

  <script id='sap-ui-bootstrap' type='text/javascript'

src='/sapui5/resources/sap-ui-core.js'

data-sap-ui-theme='sap_bluecrystal'

data-sap-ui-xx-bindingSyntax="complex"

data-sap-ui-libs='sap.ui.commons, sap.m'>

  </script>

 

  <script id="view1" type="sapui5/xmlview">

  <core:View xmlns:core="sap.ui.core" xmlns="sap.m" xmlns:smartFilterBar="sap.ui.comp.smartfilterbar" xmlns:smartTable="sap.ui.comp.smarttable" controllerName="smartTable.controller" class="sapUiSizeCompact">

  <Page id="page" title="Customers">

 

  <smartTable:SmartTable entitySet="SmartTableSet" enableAutoBinding="true"/>

  </Page>

</core:View>

  </script>

 

  <script>

  //Controller

sap.ui.controller("smartTable.controller", {

  onInit: function() {

  var sURL, oModel, oView;

 

  sURL = "<host:port>/sap/opu/odata/sap/ZSMARTTABLE4";

  oModel = new sap.ui.model.odata.v2.ODataModel(sURL, {

  json: true

  });

  oView = this.getView();

oView.setModel(oModel);

  }

  });

 

jQuery.sap.declare("smartTable.Component");

sap.ui.core.UIComponent.extend("smartTable.Component", {

  /**

  * Initialize the application

  *

  * @returns {sap.ui.core.Control} the content

  */

  createContent: function() {

  var app = new sap.m.App({

  initialPage: "idView"

  });

  var oView = sap.ui.xmlview("idView", { viewContent: jQuery("#view1").html() });        

app.addPage(oView);

  return app;

  }

  });

 

  new sap.ui.core.ComponentContainer({

  name : "smartTable"

}).placeAt("content")

 

  </script>

 

  </head>

  <body class='sapUiBody'>

  <div id='content'></div>

  </body>

</html>

 

 

Final Output -

 

Output.jpg

 

PS: You may get some errors like one shown below but it is dependent on the SAPUI5 Version. I have used 1.33.0-SNAPSHOT version but it works on 1.28 also.

 

Error.jpg

 

I would like to thank Santhosh Gowda whose blog gave me inspiration to test this control and Arshdeep Singh for his help.

 

I would request you all to provide feedback and ask questions to enhance everyone's learning.

 

BR,

Ankit Maskara.

Steps to Create Analytic card on overview page using northwind odata service (V3) in web ide.

$
0
0

Hi All,

 

In this blog you will find the steps to create different charts on overview page in web ide using V3 northwind odata service .

 

 

LINE CHART

 

1.Create Account on Cloud Cockpit and open Web IDE.

2. Set the destination in Web IDE.

Capture.PNG

 

 

3. Enable the overview plugin go to Setting -> optional plugin ->select Overview Plugin and save.

 

1.PNG

 

4. Create a new project by selecting new project from template and select overview page template.

 

2.PNG

 

5.Enter Project and click next.

 

3.PNG

 

6. Select Service URL select the northwind odata sercvice and enter URLhttp://services.odata.org/V3/Northwind/Northwind.svc/

 

5.PNG

 

7. Upload any annotations file (.xml ) we will update that file afterward.

 

 

7.PNG

 

8. Enter project Namespace and click next.



8.PNG

 

9. Click on finish.

 

9.PNG

 

 

 

10. Now you can see you project file structure.

 

10.PNG

 

11. If you do not have seperate annotation folder .Create new annotations folder and copy paste local_annotation.xml file in annotations folder .

 

11.PNG

 

12. To create cards right click on the project.Select new ->card

 

 

12.PNG

 

13. Select the data source from existing Datasource.Click next

 

1.PNG

 

14. Select line chart from the card .click Next

 

2.PNG

 

15. Select the entity set Products and give Category name.

 

3.PNG

 

16.Click on finish.

 

4.PNG

 

Check your manifest.json file  .You will get all the information that you have entered while creating cards.

 

 

5.PNG

 

17. open annotation file and copy paste the content of attached localAnnotations_1(2).xml file .

 

18.Right click on the project and run to see ouput.

 

6.PNG

 

Follow the same steps for  Donut and Bubble Chart.

Annotations for other two chart is attached just copy paste the content in your annotation file.



DONUT CHART

 

localAnnotations_1(3).xml file --------DONUT chart annotation


Manifest.json ------Use Entity set category_Sales_for_1997.


7.PNG

 

Output



8.PNG

 

 

BUBBLE CHART


localAnnotations_1(4).xml file --------BUBBLE chart annotation.

Manifest.json ------Use Entity set Invoices


9.PNG


Output


10.PNG

 

 

 

Regards,

Abhishek

Simple way to Navigate between 2 views and passing data from First to Second Page in MVC

$
0
0

I just started UI5, In my learning process I went through lot of blogs and you tube videos after writing my Hello world program

 

Then I started thing of creating 2 views and passing data from first view to second view. I searched in lot but lot people are suggesting advanced controls while navigating like Shell

 

But I thought of using as simple as ( mostly code generated by Eclipse)

 

If any body want to try this example don't just try to copy the code try to understand the concepts so that it will be easy when you are moving ahead in learning UI5 concepts

 

 

Goal :

    I have Page1 which has 3 input fields where I can enter data.

    Once the users enters data submits the data using Button, then it has to move the second Page and need to show the data which we entered in Page1

    In page2 we page Navigation set to back Page1

 

 

Info : Please observe the in line code comments to get more about concepts.

 

 

Project :

 

You can add 2 pages as shown below

 

 

Project.PNG

 

 

index.html

----------------

 

<!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.m,sap.ui.commons"
    data-sap-ui-theme="sap_bluecrystal">
  </script>
  <!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->

  <script>
    sap.ui.localResources("zbu_testing2");
    var app = new sap.m.App({id:"myApp1",initialPage:"idpage11"});

    // Create any no of pages but those should have id
    var page11 = sap.ui.view({
      id:"idpage11",
      viewName:"zbu_testing2.page1",
      type:sap.ui.core.mvc.ViewType.JS});
   
    var page22 = sap.ui.view({
      id:"idpage22",
      viewName:"zbu_testing2.Page2",
      type:sap.ui.core.mvc.ViewType.JS});

    // Add all the pages to the App
    app.addPage(page11)
    app.addPage(page22);
   
    // As we assigned defalut page while creatign the App when we execute it will show
    // page1 by default
   
    app.placeAt("content");
  </script>

</head>
<body class="sapUiBody" role="application">
  <div id="content"></div>
</body>
</html>

 

------------------------------------------------------------------------------------------------------------------------------------------------

 

page1.view.js

------------------

 

In this page I used Layout Matrix as I was showing 3 input fields.

I recommend if you are starter use only one input box and button

If you are ok with Matrix Layout you use

 

this code will be in createContent function

 

  var oLayout = new sap.ui.commons.layout.MatrixLayout();
  oLayout.setLayoutFixed(true);
  oLayout.setColumns(2);
  oLayout.setWidth("500px");
  oLayout.setWidths(["150px","150px"])
 
  //Name
  var oText = new sap.ui.commons.TextView({text:"Enter Your Name :"});
  var oInput = new sap.ui.commons.TextField({id:"input1",value:"?"});
  // Adding row to Layout
  oLayout.createRow(oText,oInput)

  // Age
  var oText = new sap.ui.commons.TextView({text:"Age :"});
  var oInput = new sap.ui.commons.TextField({id:"input2",value:"?"});
  oLayout.createRow(oText,oInput)

  // ***
  var oText = new sap.ui.commons.TextView({text:"***"});
  var oInput = new sap.ui.commons.TextField({id:"input3",value:"?"});
  oLayout.createRow(oText,oInput)

  // Submit Button
  var oButton = new sap.ui.commons.Button("BtnId2",{text:"Submit Details "});

// We are pasing Event while calling funciton in cotroller

  // oController.Navigate means Navigate funciton is available in Controller class

  // if write like this  function(oEvent){Navigate(oEvent)} then Navigate funciton should present locally

  // it means page itself


  oButton.attachPress(function(oEvent){oController.Navigate(oEvent)})

 

  // Create Cell as we need to place button in center with merging two columns to one
  var oCell = new sap.ui.commons.layout.MatrixLayoutCell();
  oCell.setRowSpan(2);
  oCell.addContent(oButton);
  oCell.setHAlign(sap.ui.commons.layout.HAlign.Center);

 

  oLayout.createRow(oCell);

 

  // Change title what ever you want
  // In content add Layout object
  // If you are not using Layout add text and button objects separted by comma ex; [oInput,oButton]
  return new sap.m.Page({
   title: "Home Page",
   content: [ oLayout ]
  });

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

page1.controller.js

 

 

first create Model in OnInit Method

 

In same controller enable OnInit function to create Model

 

onInit: function() {

  this.myModel = new sap.ui.model.json.JSONModel();

},

 

 

OnInit method calls only once in entire application

 

 

 

 

In controller class add the following function at last

 

Navigate:function(oEvent){
var EventID = oEvent.getSource().getId();
//alert("Hello");
//alert(EventID);

// Get the reference of App by using id which is declared in Index page
app = sap.ui.getCore().byId("myApp1");
//alert(app);

//Get the value from Input field
var InputText1 = sap.ui.getCore().byId("input1").getValue();
var InputText2 = sap.ui.getCore().byId("input2").getValue();
var InputText3 = sap.ui.getCore().byId("input3").getValue();
//alert(InputText);

//   var context = oEvent.oSource.getBindingContext();  
   var oView2  = app.getPage("idpage22"); 
//   oView2.setBindingContext(context);

// Get the reference of View 2
//oView2 = sap.ui.getCore().byId("idpage22");
//alert(oView2);

//Now we need to pass the values which are required from Page1 to Page2
// Collect them arrary and assign that array to Model
var myArray = {};
myArray.input1 = InputText1;
myArray.input2 = InputText2;
myArray.input3 = InputText3;

// With Above code Array has values with variables input1,input2 and input3
// for Clarity you can uncomment the following line
//console.log(myArray);

this.myModel.setData(myArray);

sap.ui.getCore().setModel(this.myModel);
//console.log(this.myModel);
app.to(oView2);

//alert(sap.ui.getCore().byId("pg2_btn"));
}

 

-----------------------------------------------------------------------------------------------------------------------------------------

 

similarly add following code to Page2

 

page2.view,js

 

 

  var oLayout = new sap.ui.commons.layout.MatrixLayout();
  oLayout.setColumns(2);
  oLayout.setLayoutFixed(true);
  oLayout.setWidth("400px");
  oLayout.setWidths(["150px","250px"]);
 
 
  var oTextLabel = new sap.ui.commons.TextView({text:"Name :"});
  var oText = new sap.ui.commons.TextView({text:"{/input1}"});
  oLayout.createRow(oTextLabel,oText);
 
  var oTextLabel = new sap.ui.commons.TextView({text:"Age  :"});
  var oText = new sap.ui.commons.TextView({text:"{/input2}"});
  oLayout.createRow(oTextLabel,oText);
 
  var oTextLabel = new sap.ui.commons.TextView({text:"***  :"});
  var oText = new sap.ui.commons.TextView({text:"{/input3}"});
  oLayout.createRow(oTextLabel,oText);

 
  //console.log(sap.ui.getCore().getModel());
  // Here we are adding 1 property and event
  // showNavButton and navButtonPress
   return new sap.m.Page({
   title: "Details",
   showNavButton:true,
   content: [oLayout ],
    navButtonPress: function(oEvent){oController.backToHome(oEvent)}
   
  });

 

---------------------------------------------------------------------------------------------------------------------------------------------

page2.controller.js

 

Add reuired function

 

backToHome : function(oEvent){

  //Getting view object of Home page or First Page

  oView = sap.ui.getCore().byId("idpage11");

  app.to(oView);

}

 

 

--------------------------------------------------------------------------------------------------------------------------------------------

 

 

In nutshell we are capturing all the data from page1 and storing in Array and that array is adding to model.

 

Model is added Core() which can be accessed from 2nd page

 

Thanks

Uma

How to create an OData provider and use it with SAP Web IDE

$
0
0

Introduction

Today I'm going to show you how to create your own OData source and use it with SAP Web IDE.

There is a free to use OData source provided by SAP and for this OData source you also have source code so if you are interested, you can modify and create your own customized OData provider. This OData source is a Java application named ESPM: once built, you can install it inside the HCP and consume its provided data by building apps with the SAP Web IDE tool.

 

Prerequisites

The only prerequisites for this are:

 

1. JAVA JDK installed with JAVA_HOME variable properly defined

2. An account to the HANA Cloud Platform  (you can also use Trial Landscape and this is what we are going to use here)

3. A GIT Client. If you haven't one installed yet, you can download it from http://git-scm.com/downloads according to your workstation's requirements. During the installation pay attention to switch to the option "Use Git from the Windows Command Prompt", otherwise you won't be able to use Git from the Windows shell

02.jpg

 

 

Steps

1. Install Apache Maven

2. Clone the ESPM repository

3. Compile the source code

4. Install the war package in the HCP and create a destination to the new application

5. Test the new OData source by building a test app

6. Import the Java source code in Eclipse

 

 

Let's get started!

1. Install Apache Maven

This could have been listed among the above prerequisites, but since this kind of software is not so commonly installed on every developer's machine I prefer to show here how to download and install Apache Maven.  Apache Maven is a software project management and comprehension tool. Based on the concept of a Project Object Model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information. The latest version at the moment I'm writing is 3.3.9.

01.jpg

  • Once done, unzip the file somewhere on your machine. For example I've extracted it under the path c:\apache-maven
  • Now you need to setup a couple of environment variables:
    • add Maven to the path;
    • define the M2_HOME variable
  • For the first variable, you just need to open the Control Panel\System and Security\System and click on the Advanced system settings link

03.jpg

  • From here, click on the Environment Variables button. Among the System variables, locate the variable "Path" and click on Edit. Just append the string ";c:\apache-maven\bin" at the end of the existing one and click on OK.

04.jpg

  • For the second variable you need to create a new one. Click on the New button just below the system variables, define the following and click on OK:

05.jpg

  • This is what you should see at the end

06.jpg

  • Now if you open the Windows terminal and type the command "mvn -version" you should get the following result:

08.jpg

 

 

2. Clone the ESPM repository

The ESPM repository is located on the SAP Github website. You can access it by clicking on  https://sap.github.io/index.html?sort=asc&filter=featured and then searching for the keyword ESPM.

 

  • Click on the Sample OData Delta-Token-Enabled Web Service link

09.jpg

  • Copy the link to the repository in the clipboard

10.jpg

  • Create a new folder on the C drive (i.e. espy) and run the clone command in this folder through the Windows Command Prompt


git clone https://github.com/SAP/cloud-espm-scenarios.git


You should get something like this

11.jpg

  • The ESPM repository has been successfully cloned on your machine.

 

 

3. Compile the source code

It's time now to compile the source code.

  • Go inside the new folder named "sap_mobile_platform_espm_olingo_services" with the command

 

cd C:\espm\sap_mobile_platform_espm_olingo_services

 

  • Enter the command

 

mvn clean install

 

  • You should get something like this:

13.jpg

  • Looking in the target folder you should find the file ESPM_V1.war. This file will be installed in the HANA Cloud Platform in the next chapter

14.jpg

 

 

4. Install the war package in the HCP and create a destination

16.jpg

  • Browse for the .war file we just created at the previous step and assign it a new name. As a Runtime Name choose Java Web and then click on Deploy

17.jpg

  • The deployment phase takes some time. Once done, click on the Start button to start it immediately

18.jpg

  • The application starts and you can check its status from the HANA Cloud cockpit. Write down or copy in the clipboard the application URL because it will be used to create a destination to this application

19.jpg

  • Click on the Destinations tab and create a new destination with the following parameters:
ParameterValue
NameESPM
TypeHTTP
Description

ESPM

URL<the application URL copied previously>
Proxy TypeInternet
AuthenticationNo Authentication

 

  • Define also the following additional properties:
PropertyValue
TrustAlltrue
WebIDEEnabledtrue
WebIDESystemESPM
WebIDEUsageodata_gen

 

  • This is how the new destination looks like at the end

20.jpg

5. Test the new OData source by building a test app

We can test the new OData provider by creating a test application with SAP Web IDE

  • Open SAP Web IDE
  • From the File menu choose New --> Project from Template. Select for example the SAP Fiori Worklist Application and give a name to the project (i.e. TestESPM)

21.jpg

  • On the Data Connection step, select the Service URL source, select the ESPM destination we created previously, provide the path to the resource (i.e. "/ESPM_V1/api/") and click on the Play button to show the services available. Then click on Next

23.jpg

  • Enter the following details and click on Next

24.jpg

  • Click on Finish
  • Congratulations! You have successfully consumed your own OData source with your new Fiori application

25.jpg

 

 

6. Import the source code in Eclipse

As a final step in this blog, you might want to import the source code in Eclipse so that you can change it and update your .war file. In order to import the source code you need first to generate the Eclipse project containing it.

  • Open a Windows Command Prompt and go to the folder where the top level pom.xml file is located. In our case it should be: "C:\espm\sap_mobile_platform_espm_olingo_services"
  • Once in this folder run the command:

mvn eclipse:celan eclipse:eclipse

  • This will generate the project to import. Now open eclipse and click on File --> Import
  • Choose General --> Existing project into workspace
  • Browse for the folder C:\espm\sap_mobile_platform_espm_olingo_services and import the project. You can now start modifying your Java code.

26.jpg

NOTE: Remember that each time you change the anything in the project, you need to re-generate the .war file and update it inside the HCP


Create Offline application in SAPUI5 (using pouch db)

$
0
0

Hi Team,

 

What is offline application?

 

Offline data refers to data used for data-driven marketing on digital marketing channels and which originates from offline sources.

 

Required plug-in:

 

PouchDB has an asynchronous API, supporting both callbacks and promises.


Implementation steps in SAPUI5:


Step 1: //Add pouch db plug-in API Reference


Refer this api and add this plugin in Index.html.


Step 2: //Create a list or combo box  by using models


Capture.PNG


Step 3: //Add methods to create/update/delete records in offline db


Get Records: db.get(docId, [options], [callback]

Post Records: db.put(doc, [docId], [docRev], [options], [callback])

Delete Records: db.remove(docId, docRev, [options], [callback])


   

Now your offline db is ready to use.

 

Capture.PNG

 

code snippet:

 

View:

 

 

 

  //JSON Model- Client Side Model

 

 

  var checkBoxData = [{

   "options" : "Bangalore"

  },

                    {

   "options" : "Chennai"

  },

                    {

   "options" : "Hyd"

  },

                    {

   "options" : "Kerala"

  }];

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

  var checkBox = new sap.m.CheckBox({

                id : "idCheckBox",

                text : "{checkBoxData>options}"

                });

  var vbox = new sap.m.VBox("idVbox",{

   items : {

     path : "checkBoxData>/",

     template : checkBox

   }

  });

 

 

  vbox.setModel(jsonModel,"checkBoxData");

  var Button = new sap.m.Button({

   text : "Store Offline Data",

   type : "Accept",

   press : oController.handleGetRecords

  });

  var Button1 = new sap.m.Button({

   text : "Get Offline Data",

   type : "Reject",

   press : oController.handleGetOfflineData

  });

  var Button2 = new sap.m.Button({

   text : "Update  Offline Data",

   type : "Accept",

   press : oController.handleUpdateOfflineData

  });

 

  var Button3 = new sap.m.Button({

   text : "Get All Offline Data",

   type : "Reject",

   press : oController.handleGetAllRecords

  });

  var Button4 = new sap.m.Button({

   text : "Delete  Offline Data",

   type : "Accept",

   press : oController.handleDestroyData

  });

  return new sap.m.Page({

  title: "Offline Application",

  content: [

            vbox,Button,Button3,Button4

  ]

  });

 

Controller:

 

//Create DB

var db = new PouchDB('offline_kar_storage');

var structure;

sap.ui.controller("offlineproject.LandingPage", {

  handleGetRecords : function(oEvent){

 

 

     var vboxItem = sap.ui.getCore().byId("idVbox").getItems();

     var SelectedText=[];

   

     jQuery.each(vboxItem,function(a,b){

       var sbool = b.getSelected();

       if(sbool){

          // SelectedText += b.getText() + ", \n";

       var subStructure = {

      "subArea" : b.getText()

       };

       SelectedText.push(subStructure);

       };

     });

      structure = [{

      _id: 'mydoc123',

      myArea : SelectedText

     }];

     this.getParent().getParent().getController().handleStoreDeepStructure();

  },

  handleStoreDeepStructure : function(){

  //Adding a record

  db.bulkDocs(structure, function(err, response) { if (err) {  return alert(err); }// handle response

    alert("Data stored in offline db");

  });

  },

  handleGetOfflineData : function(){

  db.get("mydoc123", function (err, doc) {

  debugger;

         alert("Get Record Object is ready to access");

  });

  },

 

  handleGetAllRecords : function(){

  var options = {};

  options.include_docs = true;

  options.attachments = true;

 

  db.allDocs(options, function(error, response) {

     var row = response.rows; // Calls an addrow() function

 

 

     row.map(function(f) {

       if (f) {

         debugger;

         alert("All-Doc Object is ready to access");

       }

     });

     debugger;

   });

  },

  handleUpdateOfflineData : function(){

  //Update a record

  db.get('mydoc123', function(err, doc) {

   if (err) { return alert(err); }

   db.put(structure._rev = doc._rev, function(err, response) {

     if (err) { return alert(err); }

     alert(response);

     // handle response

   });

  });

  },

  handleDestroyData : function(){db.get('mydoc123', function(err, doc) {

  debugger;

   if (err) { return console.log(err); }

   doc._deleted = true;

   db.put(doc, function(err, response) {

     if (err) { return alert(err); }

     // handle response

     alert("Data removed from offline db");

   });

  });}

});

 

 

Regards,

Karthik A





"Check, please!" or Dynamic Properties in JSONModel

$
0
0

WebDynpro Java has a nice feature called calculated context attributes which I missed a lot in WDA and now in SAP(Open)UI5. Very often we have to perform a data manipulation on UI side to produce "derivatives" - data not directly available from data source but required to the end user. Another example where calculation on the fly is required is the calculation driven by by user input,

 

Wait, there is concept  of formatter or expression binding in SAPUI5, you might say! Yes, and they work perfectly fine for simple data manipulation within model. By simple I mean - every part of calculation should be explicitly declared and only attributes could be used, like example from here:

 

https://sapui5.netweaver.ondemand.com/sdk/#docs/guide/07e4b920f5734fd78fdaa236f26236d8.html

 

oTxt.bindValue({  parts: [   {path: "/firstName", type: new sap.ui.model.type.String()},   {path: "/lastName", type: new sap.ui.model.type.String()},   {path: "/amount", type: new sap.ui.model.type.Float()},   {path: "/currency", type: new sap.ui.model.type.String()}   ],  formatter: function(firstName, lastName, amount, currency){ // all parameters are strings   if (firstName && lastName) {   return "Dear " + firstName + " " + lastName + ". Your current balance is: " + amount + " " + currency;    } else {   return null;   }   }});

all 4 parameters must be declared even though they all are coming from the same context.

 

An by within the model means you have to define at least one part for the formatter even that part is not needed.

 

Those limitations are relatively easy to overcome by dynamic properties declared in JSONModel. What is a dynamic property? It is the property defined by calling Object.defineProperty ( Object.defineProperty() - JavaScript | MDN ).

 

Why do I call them dynamic? Because you can define getter and setter functions! JavaScript functional nature meets JavaBeans.

 

Example 1: From version 1.28 there is a control sap.m.MessagePopover available and recommended to use by Fiori Design Guidelines ( https://experience.sap.com/fiori-design/ui-components/message-popover/ ). That control is usually "opened by" some other control, mostly by buttons. So, if there are no active messages in our message manager we would hide that button to prevent users confusion about errors. Another nice addition to that would be - display icon which corresponds to the highest severity in message manager e.g. if there are errors - error icon, if there are just warnings - warning icon and so on. To implement those requirement we would define 2 dynamic properties messagePopoverVisible and messagePopoverButonIcon:

 

var messagePopoverModelObject = {};
Object.defineProperty(messagePopoverModelObject, "messagePopoverVisible", {  get : function() {  var data = sap.ui.getCore().getMessageManager().getMessageModel().getData();  return data && data.length !== 0;  }
});
Object.defineProperty(messagePopoverModelObject, "messagePopoverButonIcon", {  get : function() {  var data = sap.ui.getCore().getMessageManager().getMessageModel().getData();  var hasSeverity = function(severity) {  return function(element, index, array) {  return (element.type == severity);  };  };  if (data && jQuery.isArray(data)) {  if (data.some(hasSeverity("Error"))) {  return "sap-icon://alert";  }  if (data.some(hasSeverity("Warning"))) {  return "sap-icon://alert";  }  }  return "sap-icon://sys-enter";  }
});
this.getView().setModel(new JSONModel(messagePopoverModelObject), "messagePopoverModel");

now with those properties defined we can use them in the binding:

 

<Button id="MessagePopoverButton" press="handleMessagePopoverPress" visible="{messagePopover>/messagePopoverVisible}" type="Emphasized" icon="{messagePopover>/messagePopoverButonIcon}"/>

 

Note: MessageManage model could be set for the button control and visibility could be bound via expression binding: "{=$(messageManagerModel>/).length!=0}" but I personally prefer those kind of validation to have in JavaScript - easier to debug and understand.

 

Example 2: Abap has no boolean type, so if we need to map a true value to 'X' and vice verse we can use a dynamic property as it has both, setter and getter (another way to implement - Simple type implementation with formatValue and parseValue).

$.each([ "DisabilityIndicator", "StudentIndicator", "MedicareIndicator" ], function(i, entityName) {  Object.defineProperty(dataObject, entityName + "Boolean", {  get : function() {  return (this[entityName] === "X");  },  set : function(value) {  this[entityName] = (value ? "X" : " ");  }  });
});

This example ( from ESS Dependents application) creates dynamically a corresponding value holder which could be used for mapping:

 

<CheckBox selected="{DisabilityIndicatorBoolean}"/>

 

 

Example 3: Very common scenario in business application where we have a header object and items (sales order, PO, shopping cart and so on). Lets say we need to calculate a balance : balance = header amount - sum( item price * item quantity ) The most obvious way would be to implement a method in controller but the problem is - we have to assign a change event handler to every input field involved in calculation (dynamically or even worse - statically). Instead, we would define a dynamic property where we implement a calculation logic in the getter method. The beauty of this approach is that if the static property (amount or qty) from the target model is bound to the UI control, two way binding (default from JSONModel) will cause checkUpdate method execution and as  a result - execution of dynamic property getter (of course only if it is bound to UI control's property, like Text's text) AND we have an access to object's subobject, like items:

 

Object.defineProperty(itemsModel, "Balance", {  get: function () {  var balance = 0.00;  var itemsAmount = 0.00;  $.each(this.Items, function (i, item) {  if (!isNaN(parseFloat(item.Amount)) && !isNaN(parseFloat(item.Qty))) {  itemsAmount = itemsAmount + parseFloat(item.Amount) * parseFloat(item.Qty);  }  });  balance = this.header.Amount - itemsAmount;  return balance;  }
});

 

and of course as it is a model property we can use it in binding:

 

<Toolbar id="BalanceBar">  <content>  <ToolbarSpacer/>  <Label text="{i18n>BALANCE}"></Label>  <ToolbarSpacer width="20px"/>  <Text text="{ parts : [ 'itemsModel>/Balance' ], formatter: '.formatAmount' }"></Text>  </content></Toolbar>

 

 

 

 

Limitation - if the dynamic property is declared on the object which should be used in arrays (tables, list etc.) some sort of "cloning" logic should be implemented.

 

checkUpdate() should be called if data is changed indirectly and affects the calculation logic.

 

Disclaimer: Those techniques obviously not the only available to implement above mentioned requirements but just give developer more options to consider.

Use SAP Web IDE Templates for Rapid Fiori App Development

$
0
0

One of the unique features of SAP Web IDE is its collection of project templates. Sure, any IDE has project templates which allow you to generate pre-defined projects as a starting point. But, SAP Web IDE project templates are a bit different and allow you to achieve a lot more, using the same concept. You can even create your own templates if needed.

 

In this blog post, I would like to introduce you to each one of the different templates SAP Web IDE has to offer.


There are four main entry points to use the templates. All of them are accessible via the Welcome Page or the menu entry File>New.


Welcome Page:

31-01-2016 13-41-09.png

File>New:

31-01-2016 13-41-55.png

Project from Template

This is the most used entry point. These templates generate full-blown SAP Fiori applications based on the OData service you select. You can customize the binding of the data fields from the service to the UI controls before generating the application. The selected service should be compliant with OData version 2.0.

 

There are also additional templates such as the SAPUI5 Application (an empty SAPUI5 project) and even SAP Web IDE plugin project.

 

Note that in some of the templates there are multiple versions available. These templates have an Available Versions drop down list for selecting the version you need. By default, the recommended version is selected. More information about the steps required to create a project from a template is available here.

 

Project from Sample Application

You can create a project based on a collection of Fiori sample applications, developed using Fiori and SAPUI5 best practices. These apps use mock data at runtime so they work out-of-the-box without an existing OData service and do not require any further customization. It’s recommended to use these sample applications to learn the best practices and guidelines of a Fiori application. You would need to read and agree to the license agreement displayed on the Confirmation wizard step.

 

Quick Start with Layout Editor

Want to quickly use the Layout Editor for a new project or just for testing? This entry point creates an empty Fiori project with a single view (already bound to mock data) and automatically opens the Layout Editor for editing this view. No further customization is needed. More information can be found here.

 

Extension Project

This template allows you to create your own extension of an existing Fiori application and include any customization you might want to add. You can extend applications hosted on SAP ABAP UI5 Repository, SAPHANA Cloud Platform or even your SAP Web IDE workspace. Once generated, you can use the Extensibility Pane to extend the application.

 

 

In this post, I will share with you details for the templates available in the Project from Template entry point (except for the Empty Plugin template which probably belongs to another blog post).

 


SAP Fiori Master-Detail Application

31-01-2016 14-09-31.png

Previously called SAPUI5 Master-Detail Application. This is a full-blown project template for the split-screen layout application pattern based on Fiori guidelines and best practices. A working example of such an application can be found on SAPUI5 demo apps page.

 

On the left pane, you get a list of items. When you select an item from this list, its details are displayed on the right pane. There, you can also trigger related actions and review additional related items, if they exist.

 

There are several versions available for this template. If you want to work with older SAPUI5 versions, select the appropriate version from the Available Versions drop down list. The last two versions are deprecated. They work with SAPUI5 1.26 and are delivered for backwards compatibility (they were previously available as separate templates). If you deploy your apps to SAP HANA Cloud Platform, most of the time you will be using the latest version (which is the recommended one).

31-01-2016 16-12-57.png

After selecting the template, move on to the next wizard step where you will enter a name for your project.

 

Data Connection Step

The Data Connection step is common to all templates which require an OData service and allows you to customize the binding of data fields to the UI controls on the next step.


31-01-2016 16-22-26.png

You have 4 options:

  • Service Catalog
    For OData services exposed via the SAP Gateway service catalog. Each system is defined by your account administrator as an SAP HANA Cloud Platform destination. You can search for services and select the one you would like to use.


  • Workspace
    You can use an existing metadata.xml file (metadata file of an OData service) from your SAP Web IDE workspace. You don’t need a real service connection in order to generate the application but you would need to work with mock data when running the application (or define a real service URL).


  • File System
    Instead of selecting the metadata.xml from your workspace (see Workspace section above), you can upload an existing metadata.xml from your file system to SAP Web IDE.

  • Service URL
    You can type in the URL to your OData service (the system should be defined by the administrator of your account as an SAP HANA Cloud Platform destination).

 

Template Customization Step

The Template Customization step is common to all templates which allow additional customization before generation, including data binding for the OData service. Some fields are required and some are optional. In order to understand the customization options, click on the thumbnail on the right to enlarge the sample application screenshot.


31-01-2016 16-55-04.png

When selecting the data binding values, the options provided are based on your previous selections. For example, if you selected FlightCollection as the Object Collection, you will only get fields from Flight Collection for the Object Collection ID, Object Title etc.

 

More detailed information of the template and its generated code can be found here.


CRUD Master-Detail Application

31-01-2016 14-22-41.png

This template is based on the SAP Fiori Master-Detail Application template (see above) and adds create/update/delete capabilities to the generated application (if supported by the selected OData service). The applications contains an Add button, Edit form (to create or update an item), Save, and Delete buttons.

 

The generated form includes client-side input validation and formatting based on the metadata of the OData service (for example, type check, length, mandatory fields etc.). You can freely modify the form based on your requirements.

 

For more information about this template, refer to SAP Fiori Master-Detail Application template section above.

 

SAP Fiori Worklist Application

Previously called SAPUI5 Worklist Application. This is a full-blown project template for the worklist pattern based on Fiori guidelines and best practices. A working example of such an application can be found on the SAPUI5 demo apps page.

 

The application displays a list of items to be processed by the user and usually involves reviewing details of a list item and taking action.

 

There are several versions available for this template. If you want to work with older versions of SAPUI5, select the appropriate version in the Available Versions drop down list. The last version displayed has been deprecated. It works with SAPUI5 1.26 and is delivered for backwards compatibility (it was previously available as a separate template). If you deploy your apps to SAP HANA Cloud Platform, most of the time you will be using the latest version (which is the recommended one).

31-01-2016 17-32-25.png

The steps required to create an application from this template are similar to the other templates described above.


More detailed information of the template and its generated code can be found here.

 

Smart Template Application

This is a unique template. It’s based on a new paradigm by SAPUI5 where most of the logic and UI patterns are already defined by SAPUI5 Smart Template components. The application code contains a minimal set of files for configuration and definition of the components needed, including the OData service. These components act as runtime templates which get rendered (generated) when the app is running. The input at runtime is the OData service metadata, its annotations, and the data itself.

 

You won’t be able to use this template without proper metadata and annotations.

 

This project template uses 2 types of Smart Template views: List Report and Object Page. They are both based on the Fiori Design guidelines. The generated application will use the List Report as the first page and the Object Page as the second. Based on the OData service being used, the second page might contain also a navigation to an additional Object Page.

 

01-02-2016 09-59-06.png

01-02-2016 09-59-48.png

The steps required to create an application from this template are similar to the other templates described above except from an additional Annotation Selection step. This steps shows the annotations which exist for the selected service. You can add additional annotations files and change the order they will be loaded.

 

01-02-2016 09-41-32.png

Note that the Template Customization step only asks for an ODatacollection and OData navigationattribute as most of the customization is derived from the annotations.

 

More detailed information of the template and its generated code can be found here.

 

SAPUI5 Application

This is a simple template which allows you to create a new SAPUI5 project with an optional first view. The generated application doesn’t have any data binding so you don’t need an OData service or a metadata.xml file for generation.

 

You can select any type of SAPUI5 view. Note that you will be able to use the Layout Editor only for XML views.

 

01-02-2016 10-16-05.png

 

Master-Detail with Photos

This master-detail template is intended for a very specific scenario and probably won’t be suitable for other scenarios. In addition, the OData service must expose a specific schema which is required by the application. The result is a hybrid mobile application with offline support.

 

For more advanced development of hybrid mobile applications using SAP Web IDE, it is highly recommended to enable the external Hybrid App Toolkit plugin and use it instead.

 

Using SAP Mobile Secure, you can package the project as a native application and deploy it to mobile devices.


More information about hybrid application can be found here.



This completes the list of templates I wanted to show you!

 

Note that activating optional plugins can add additional templates to your arsenal. Make sure you check them as well. I hope you now have more understanding of the different project templates SAP Web IDE has to offer. Good luck with your next Fiori application development!

 

Feel free to comment and ask questions.

How to make your OData entities work with the Fiori Overview Page and Cards leveraging the new SAP Web IDE annotation modeler

$
0
0

Inspired by Anil Bavaraju's excellent blog on how to Create your first SAP Fiori Overview Page, I set-off to create exactly this. Fortunately, I discovered, that SAP have moved on since Anil’s blog, and especially the creation of the local annotation XML file is now supported by the SAP Web IDE annotation modeller. Also, there is a graphical interface to the manifest.json file now, and as a consequence no need to edit this manually any longer either.

 

Therefore I will describe the basic steps to create a Fiori Overview Page with a table Card only very briefly, and will focus on how to create the annotation file with new SAP Web IDE annotation modeller and how to adjust the manifst.json within Web IDE respectively.

 

  1. To start with, if you hadn’t yet, you would have to activate the Overview Page Plugin:

    Optional Plugins.png
  2. Next, if you hadn’t yet, you would have to create a destination for the Northwind OData service:
    Northwind OData Service.png
  3. With the above in the bag, we can now create an Overview Page Application:
    Template Selection.png
  4. I specify the project name as zovp, since I am going to deploy this to my NetWeaver Gateway Fiori Launch Pad in a later blog:
    Basic Information.png
  5. We then specify the connection to the OData service as http://services.odata.org/V3/Northwind/Northwind.svc/. As a result, all respective collections are displayed and we are especially interested in the Employees collection:
    Data Connection.png
  6. Next, we are asked, to specify an Annotation File. Please provide the following annotation XML shell file here:

 

<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"

               xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData">

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

                             <Schema Namespace="NorthwindModel" sap:schema-version="1" xmlns="http://docs.oasis-open.org/odata/ns/edm">

                                            <Annotations Target="NorthwindModel.Employee" xmlns="http://docs.oasis-open.org/odata/ns/edm">

                                                           <Annotation Term="UI.LineItem">

                                                           </Annotation>

                                            </Annotations>

                             </Schema>

               </edmx:DataServices>

</edmx:Edmx>

 

Since we will be using the SAP Web IDE annotation modeller to detail this later:Annotation Selection.png

  1. To continue, we have to specify some template customizations options:
    Template Customization.png
  2. That is all and we can confirm and finish:
    Confirmation.png
  3. Now we have to correct the local annotations file location in the manifest.json configuration file, which we can copy from the metadata.xml file location, i.e. we replace annotations/ witch localService/NorthwindModel/:
    Services.png
  4. With that, we can open the Annotation Structure in the Annotation Modeller:
    Innovation Structure.png
  5. In the Annotation Modeller we add the fields as we would like them to be displayed on the Card:
    Annotation Structure.png
  6. Next, we add a New Card with Using the existing Data source:
    New Card.png
  7. As a Card format, we chose Table:
    Table.png
  8. And then confirm some customizations:
    Card Customization.png

  9. With that we are done, and rewarded with a working SAP Fiori Overview Page with an Employee Card:

    Employees Overview.png

  10. In my upcoming blogs, I will show you how to deploy this Fiori Overview Page to an on premise Fiori Launch Pad as well as to transform the Catalogue Service Fiori app from my previous blogs into a Fiori Card.

Manage Smart Template (List View and Object View ) using Annotations file...

$
0
0

Hi

 

I have already Explained  Create Smart Template Project.........SAP WEB IDE

 

and adding some basic Controls Adding Controls on Smart template  using Annotations...SAP WEB IDE

 

Now Manage Smart Template (List View and Object View ) using Annotations file

 

Flow of Smart Template

 

12234.png

this explained flow of Smart template ..

 

When We RUN SMART TEMPLATE we got this output page

 

1.PNG

 

After click 1'st tiles we got this view

 

2.PNG

in this view it show simple table if we want to make a grid table  like this

 

9.png

just Add this Code at manifest.json

14.jpg

if we want to Add some controls at Line items like DataFieldForAction , DataFieldWithURL

then

use this Code at annotations/localAnnotations_1.xml


7.PNG

 

if we want to make Some Custom Filter Elements like this

16.png

use this Code at annotations/localAnnotations_1.xml


<Annotation Term="UI.SelectionFields">

<Collection>

<PropertyPath>flightDetails</PropertyPath>

<PropertyPath>PRICE</PropertyPath>

<PropertyPath>CURRENCY</PropertyPath>

</Collection>

</Annotation>

 

 

If we want to add a column  counter  at line item like this

8.PNG

use this Code at annotations/localAnnotations_1.xml

 

<Annotation Term="UI.HeaderInfo">

  <Record>

  <PropertyValue Property="Description">

  <Record Type="UI.Datafield">

  <PropertyValue Property="Value" Path="CURRENCY"/>

  </Record>

  </PropertyValue>

  <PropertyValue Property="Title">

  <Record Type="UI.DataField">

  <PropertyValue Property="Value" String="Flight Name"/>

  </Record>

  </PropertyValue>

  <PropertyValue Property="TypeName" String="Flight Object Page"/>

  <PropertyValue Property="TypeNamePlural" String="DOCUMENTS"/>

  <PropertyValue Property="TypeImageUrl" String="Hello"/>

  <PropertyValue Property="ImageUrl" String="http://www.laptop-computer-comparison.com/image-files/sony-vaio-pink-laptop.jpg"/>

  </Record>

  </Annotation>

 

if we want to Create one more tiles like this

 

11.png

go Overview Page at

 

10.png

 

So we have almost Controls Deploy at OverView Page

 

Now Come List View of Smart Template


this is the view of List View

12.jpg

 

select any column and click Show Details you will get list view

 

before that

at first Copy this code and paste at

annotations/localAnnotations_1.xml then you will be able to see List view

 

 

 

<Annotation Term="UI.Identification">
<Collection>
<Record Type="UI.DataFieldForAction">

                               <PropertyValue Property="Label" String="ACTION"/>

                          <PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

                       <Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

                  <PropertyValue Property="Action" String="CheckFlightAvailability"/>

                </Record>

  <Record Type="UI.DataField">

                  <PropertyValue Property="Label" String="FLIGHT DETAILS"/>

                <PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

                           <Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

                           <PropertyValue Path="flightDetails" Property="Value"/>

                </Record>

<Record Type="UI.DataField">

               <PropertyValue Property="Label" String="FLIGHT CURRENCY"/>

                <PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

                           <Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

                           <PropertyValue Path="CURRENCY" Property="Value"/>

                </Record>

<Record Type="UI.DataField">

                  <PropertyValue Property="Label" String="FLIGHT TYPE"/>

                <PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

                           <Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

                           <PropertyValue Path="PLANETYPE" Property="Value"/>

                </Record>

<Record Type="UI.DataField">

                  <PropertyValue Property="Label" String="FLIGHT DATE"/>

                <PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

                           <Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

                           <PropertyValue Path="fldate" Property="Value"/>

                </Record>

</Collection>
</Annotation>

 

 

to create these element

17.png

annotations/localAnnotations_1.xml then you will be able to see  view

 

<Annotation Term="UI.HeaderInfo">

  <Record>

  <PropertyValue Property="Description">

  <Record Type="UI.Datafield">

  <PropertyValue Property="Value" Path="CURRENCY"/>

  </Record>

  </PropertyValue>

  <PropertyValue Property="Title">

  <Record Type="UI.DataField">

  <PropertyValue Property="Value" String="Flight Name"/>

  </Record>

  </PropertyValue>

  <PropertyValue Property="TypeName" String="Flight Object Page"/>

<PropertyValue Property="TypeNamePlural" String="DOCUMENTS"/>

  <PropertyValue Property="TypeImageUrl" String="Hello"/>

  <PropertyValue Property="ImageUrl" String="http://www.laptop-computer-comparison.com/image-files/sony-vaio-pink-laptop.jpg"/>

  </Record>

  </Annotation>

<Annotation Qualifier="hello" Term="UI.DataPoint">
<Record>
<PropertyValue Path="PLANETYPE" Property="Value"/>
<PropertyValue Property="Title" String="Flight ID"/>
</Record>
</Annotation>
<Annotation Qualifier="hello1" Term="UI.DataPoint">
<Record>
<PropertyValue Path="fldate" Property="Value"/>
<PropertyValue Property="Title" String="Flight Name"/>
</Record>
</Annotation>
</Annotation>

 

To Create this

18.png

annotations/localAnnotations_1.xml then you will be able to see  view


<Annotation Term="UI.Facets">

<Collection>

<Record Type="UI.CollectionFacet">

<PropertyValue Property="ID" String="GeneralInformation"/>

<PropertyValue Property="Label" String="{@i18n&gt;@GeneralInfoFacetLabel}"/>

<PropertyValue Property="Facets">

<Collection>

<Record Type="UI.ReferenceFacet">

<PropertyValue Property="Label" String="GeneralInformation1"/>

<PropertyValue AnnotationPath="@UI.Identification" Property="Target"/>

</Record>

<Record Type="UI.ReferenceFacet">

<PropertyValue Property="Label" String="GeneralInformation2"/>

<PropertyValue AnnotationPath="@UI.LineItem" Property="Target"/>

</Record>

<Record Type="UI.ReferenceFacet">

<PropertyValue Property="Label" String="GeneralInformation3"/>

<PropertyValue AnnotationPath="@UI.FieldGroup#generalinformation" Property="Target"/>

</Record>

 

</Collection>

</PropertyValue>

</Record>

<Record Type="UI.ReferenceFacet">

<PropertyValue Property="Label" String="{@i18n&gt;@SecondFacetLabel}"/>

<PropertyValue AnnotationPath="flightBookings/@UI.LineItem" Property="Target"/>

</Record>

<Record Type="UI.ReferenceFacet">

<PropertyValue Property="Label" String="Basic Information"/>

<PropertyValue AnnotationPath="CarrierToFlight/@UI.Identification" Property="Target"/>

</Record>

 

</Collection>

</Annotation>

 

 

 

To create this

19.png


annotations/localAnnotations_1.xml then you will be able to see  view



 

<Annotation Term="UI.Identification">

<Collection>

<Record Type="UI.DataFieldForAction">

<PropertyValue Property="Label" String="ACTION"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Property="Action" String="CheckFlightAvailability"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="FLIGHT DETAILS"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="flightDetails" Property="Value"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="FLIGHT CURRENCY"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="CURRENCY" Property="Value"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="FLIGHT TYPE"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="PLANETYPE" Property="Value"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="FLIGHT DATE"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="fldate" Property="Value"/>

</Record>

</Collection>

</Annotation>

 

 

 

<Annotation Term="CarrierToFlight/@UI.Identification">

<Record>

<PropertyValue Property="Data">

<Collection>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="PRICE"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="PRICE" Property="Value"/>

</Record>

</Collection>

</PropertyValue>

</Record>

</Annotation>

 

 

 

 

<Annotation Term="UI.LineItem">

<Collection>

<Record Type="UI.DataFieldForAction">

<PropertyValue Property="Label" String="ACTION"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Property="Action" String="CheckFlightAvailability"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="FLIGHT DETAILS"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="flightDetails" Property="Value"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="DATE"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="fldate" Property="Value"/>

</Record>

<Record Type="UI.DataField">

<PropertyValue Property="Label" String="PRICE"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Neutral"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Path="PRICE" Property="Value"/>

</Record>

<Record Type="UI.DataFieldForAction">

<PropertyValue Property="Label" String="ACTION_1"/>

<PropertyValue Property="Criticality" String="UI.CriticalityType/Negative"/>

<Annotation EnumMember="UI.ImportanceType/High" Term="UI.Importance"/>

<PropertyValue Property="Action" String="GetFlightDetails"/>

</Record>

</Collection>

</Annotation>

 

So it was some Custom Controls .which you can Add in List view

 

now click EDIT button then you are able to see a massage Notification tab




20.png

 

USE THIS ANNOTATIONS CODE For SMART TEMPLATE

 

 

please do comment if you have any Problem in these controls

 

 

Thanks & Regards

Virendra

Viewing all 789 articles
Browse latest View live




Latest Images