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

Comparison between UI5 and Angular with Bootstrap

$
0
0

Hi to all,

 

in the last years I worked a lot with Angular (https://angularjs.org/) for my JavaScripts and Bootstrap (http://getbootstrap.com/) for layout and some nice components. These two were a combination, which worked really help together for me. In fact, there are even many additional libraries, which provide assistance in combining these two frameworks. So while Angular can handle the application architecture and can control the data flow, bootstrap provides a nice starting point for user interaction and styling. As of now, I will treat Angular and Bootstrap as one unit to compare with UI5.

 

Everything is just my point of view and I'm still pretty new to UI5. If you have a different opinion about anything here, i'd love to hear from you. And because I really like lists and tables, lets start with one, comparing different parts/features. I gave everything up to three stars:

 

 

FeatureUI5Angular / Bootstrap
Databinding (one-way, two-way)******
Modules******
Predefined Compontents (Layout, Tables, Forms, Buttons, ...)****
Internationalisation******
Routing******
Testing* (not sure yet)***
Support for different Data (REST, XML, JSON, OData,...)******
Customizable****
Learning Curve****

 

As you can see, basically both ways work fine for me. That's why I will focus on the differences that matter to me. As far as I can see, concerning predefined components/widgets/whatever UI5 is the strongest JS-library I've ever seen. Bootstrap also covers the basic needs, like tables, lists, datepicker, grid-layout, etc., but with UI5 I can build tons of apps without ever having the need for my own custom component.

Testing is a big topic for me and I'm still not sure, which is a good way to go in regards to UI5-testing. I tried out QUnit-Tests and they worked well. I'm still not sure about how to test certain areas or what is the right thing to test. On the other hand, I know there is good support for mocking data. Angular has a well-build testing library to mock and test everything I ever needed. It integrates great with testrunners and testframework, e.g. Karma and Jasmine, and can be also be run in a Continuos Integration Environment like Jenkins. Maybe UI5 is much more advanced in testing and I will learn this soon.

Customizing is a different story. Angular and bootstrap can be customized really, really good. Adding custom styles and functions, wrapping directives, integrating parts of it with your own code, etc. is easy. With UI5 its also possible to customize and e.g. extend predefined components. I think the strong point of UI5 (and Fiori) is, that it gives you a way how your app should work out-of-the-box. If you or your customer has some special wishes how something should look or feel, you have to jump out of this box and build (nearly) from scratch. (opinions from more experiences developers is greatly welcome )

The learning curve in UI5 is really low. Getting into it and expanding my knowledge was, after a dumb start, really great. Angular on the other hand has a light start and soon you hit a wall. Going over this wall takes time and patience and afterwards its getting fun again.

 

Finally, I think Angular and Bootstrap are there to help you develop your way, while UI5 is showing you its own shiny way.


How To Create the offline Fiori CRM App Part 4

$
0
0

1. Create the Connection at HCP a

2. Create the Connection at HCC if you use the HCC a

3. Prepare your Application at the HCPms a

4. Get an SAP Mobile Secure Account a

5. Create an Android Signing ID a

6. Get you SAP Mobile Secure Cloudusername and password a

7. Download the packager

8. Prepare the appconfig

9. Package the App

10. Create the Cordova App

11. Download it from your SAP Mobile Secure Account and run it

 

 

7. Download the packager


Prerequisite: you have installed npm, node.js.

In this particular case I have: npm version 2.7.4, node version v0.12.2.

 

Download the latest version of the packager which is included in the Kapsel SDK

https://help.hana.ondemand.com/webide_hat/frameset.htm?d2865598e67f4ddabc79e5943352b0a1.html

031.png

 

 

Unzip this to a folder. The final folder should look like here:

032.png

 

 

 

Create a folder when you will execute the packager (here: PackagedApp).

The sources will be downloaded to it and the app will be generated.

032.png

 

 

8. Prepare the appconfig

 

Copy the appConfig.js file to your work directory (example folder “PackagesApp”)

(I've attached my appconfig to this blog)

 

Adapt it:

 

Enter the appID and appName which you define at step 3

 

 

Enter your SigningID(step 5)

 

 

Your HCPms URL

 

 

Choose which Apps you want to download

 

 

[…]

fiori_client_appConfig = {

    "appID": "com.sap.mycontact",

    "appName": "MyContacts",

    "appVersion": "0.1",

    "bundleID": "com.sap.mycontact",

    "androidSigningID": "b6XXXXXXXXXXXXXXc8",

 

 

[..]

"fioriURL": "https://hcpms-<yourD-User>trial.hanatrial.ondemand.com",

"fioriURLIsSMP": true,

 

 

"certificate": "",

 

 

"autoSelectSingleCert": false,

 

"passcodePolicy":  {

        "expirationDays":"0",

        "hasDigits":"false",

        "hasLowerCaseLetters":"false",

        "hasSpecialLetters":"false",

        "hasUpperCaseLetters":"false",

        "defaultAllowed":"true",

        "lockTimeout":"300",

        "minLength":"8",

        "minUniqueChars":"0",

        "retryLimit":"10"

    },

 

 

"prepackaged" : true,

 

"offline": true,

 

"singleApp" : "",

 

    "applications": [{

                    "id": "cus.crm.mycontacts",

                    "intent": "ContactPerson-MyContacts",

                    "title": "My Contacts",

                    "url": "/sap/bc/ui5_ui5/sap/crm_mycont"

                    }, {

      "id": "cus.crm.myaccounts",

                    "intent": "Account-MyAccounts",

                    "title": "My Accounts",

                    "url": "/sap/bc/ui5_ui5/sap/crm_myaccounts"

                    }, {

                    "id": "sap.cus.crm.lib.reuse",

                    "url": "/sap/bc/ui5_ui5/sap/crm_lib_reuse/sap/cus/crm/lib/reuse",

                    "reuse": true,

                    "scenario": true

                    }]

};

 

[..]

 

 

 

 

Your folder structure might look like this:

034.png

 

Open terminal and do following commands to prepare the packager:

cd H:\Desktop\FioriApps\CRM\smp-plugins\apps\packager



 

Run the following commands (If this is your first use with this packager version):

 

npm install

npm config set proxy <protocol>:://<proxyhost>:<proxyport>

npm config set https-proxy <protocol>:://<proxyhost>:<proxyport>

 


9. Package the App

 

 

Do following commands to create a package.

This will download the sources (sapui5 and application) from the given server

 

Note: On mac the packager will need executable permissions which can be added by running with the bin directory: sudo chmod 755 packager

 

cd H:\Desktop\FioriApps\CRM\PackagedApp

node ../smp-plugins/apps/packager/bin/packager --config appConfig.js --targetDir CRM --host cimg1.wdf.sap.corp --port 50081 --https --force --cleanAppCache --user <CRM-username> --password <CRM-password>

 

035.png

 

Now you should have downloaded sources with the applications and sapui5. This should be your folder structure

036.png

 

With this structure you can create a cordova app.

 

 

 

10. Create the Cordova App

 

http://help.sap.com/saphelp_smp3010sdkmfadev/helpdata/en/ca/b7a87eba614c6b84f70bb9f0bfd59d/content.htm

 

 

This command creates a package, reading for uploading and building, on the cloud build server.

 

node ../smp-plugins/apps/packager/bin/packager --config appConfig.js --targetDir CRM --cloudHost portal.next.sapmobilesecure.com --cloudUser <yoursapmobilesecureuser> --cloudPassword <yoursapmobilesecurepassword> --cloudProxy proxy.wdf.sap.corp:8080 createpackage

037.png

 

This command uploads the assets that have been downloaded from the Fiori front-end server to the cloud build server, including the splash screen definitions and icons that represent the application on the device home screen.

 

node ../smp-plugins/apps/packager/bin/packager --config appConfig.js --targetDir CRM --cloudHost portal.next.sapmobilesecure.com --cloudUser <yoursapmobilesecureuser> --cloudPassword <yoursapmobilesecurepassword> --cloudProxy proxy.wdf.sap.corp:8080 uploadpackage

 

038.png

 

 

This command initiates the build on the SAP Mobile Secure cloud build server.

 

node ../smp-plugins/apps/packager/bin/packager --config appConfig.js --targetDir CRM --cloudHost portal.next.sapmobilesecure.com --cloudUser <yoursapmobilesecureuser> --cloudPassword <yoursapmobilesecurepassword> --cloudProxy proxy.wdf.sap.corp:8080 startbuild

 

039.png

 

 

Use this command during a build to check the build status.

 

node ../smp-plugins/apps/packager/bin/packager --config appConfig.js --targetDir CRM --cloudHost portal.next.sapmobilesecure.com --cloudUser <yoursapmobilesecureuser> --cloudPassword <yoursapmobilesecurepassword> --cloudProxy proxy.wdf.sap.corp:8080 status

 

040.png

 

 

11. Download it from your SAP Mobile Secure Account and run it

 

After this your app will be created and you will be notified via e-mail. You can download this app directly using the link in the e-mail.

 

041.png

 

After the Installing open the App, enter your Fiori Username and Password.

Have fun with you offline app

 

042.png

 

043.png

 

Note: In the packaged app after store initialization the Launchpad is shown but the apps are not displayed? Go to your downloaded App folder (here: H:\Desktop\FioriApps\CRM\PackagedApp) and in the ushellconfig.js change "isDefault: false" to "isDefaultGroup: true".

How To Create the offline Fiori CRM App Part 3

$
0
0

1. Create the Connection at HCP a

2. Create the Connection at HCC if you use the HCC a

3. Prepare your Application at the HCPms a

4. Get an SAP Mobile Secure Account

5. Create an Android Signing ID

6. Get you SAP Mobile Secure Cloudusername and password

7. Download the packager

8. Prepare the appconfig

9. Package the App

10. Create the Cordova App

11. Download it from your SAP Mobile Secure Account and run it

 

 

4. Get an SAP Mobile Secure Account


Go to https://portal.sapmobilesecure.com/free_trial.php

If you have an Account click on “Login” (at the top right) and go to the next step

011.png

 

 

If not fill out the form:

012.png

 

You will get two emails, click on Activate now when you get the second mail with “Your System is Ready!”

013.png

014.png

 

5. Create an Android Signing ID


Open the cmd window and enter the following line and press enter

 

keytool -genkey -v -keystore cp-release-key.keystore -alias MyApps -keyalg RSA -keysize 2048 -validity 10000


Change your keystore name and your alias to what you want


Answer the questions and enter the passwords

015.png

 

 

 

 

Go to your Mobile Secure and click Account --> Signing Profile

016.png

 

Click on New Profile and choose your Platform Type (here: Android) and click OK

017.png

018.png

 

Enter your Name, Password and your Alias and choose your KesyStore File (which you find in this folder where you have run the keytool command!) and click OK

019.png

 

To find now your SigningID go to your new Signing Profile and open it. The SigningID you will find in the URL. You will need this ID later!

020.png

 

6. Get you SAP Mobile Secure Cloudusername and password


Click on the Icon next to your Name and choose My Profile

021.png

 

 

 

Click on Generate Password

022.png

 

 

 

Download this File. You will need your Username and Password later!

 

If you forgot it you can regenerate a new password

023.png

 


How To Create the offline Fiori CRM App Part 2

$
0
0

1. Create the Connection at HCP

2. Create the Connection at HCC if you use the HCC

3. Prepare your Application at the HCPms

4. Get an SAP Mobile Secure Account

5. Create an Android Signing ID

6. Get you SAP Mobile Secure Cloudusername and password

7. Download the packager

8. Prepare the appconfig

9. Package the App

10. Create the Cordova App

11. Download it from your SAP Mobile Secure Account and run it

 

 

1. Create the Connection at HCP

 

Login to your HCP and go to Destinations and create a new Destination.

 

008.png

For more information about it  look here: Setup your SAP Web IDE on HANA Cloud Platform Part 1

 

 

2. Create the Connection at HCC if you use the HCC

 

If you have to use the HANA Cloud Connector enter here your information about your Backend an dyour virtuel system.

 

009.png

For more information about it look here: Setup your SAP Web IDE on HANA Cloud Platform Part 1

 

3. Prepare your Application at the HCPms

 

At the HCP Cockpit click on Services

Scroll down to Mobile Services

Click on Development & Operations

 

Note: if you use this the first time, you have to enable it.

 

001.png

 

Click on Go to Service

002.png

 

 

Your HCPms will launched

 

On the Left Side click on Account Configuration

003.png

 

enter the following Authentication settings and click Save


SCIM Type: HCPms SCIM

 


004.png

 

At the left click on the Applications tile and create a new Application

 

Enter the following Data and click Save

 

Application ID: com.sap.mycontact

Name: My Contacts

Type: Hybrid

Security Configuration: Basic

005.png

 

Open this Application and scroll down at the Information Tab

 

 

Enter the following SCIM Configuration Settings and click Save:


Check Override Global HCPms SCIM Configuration


URL: in order to provide app specific URL (pointing to the ABAB Service document, protected by basic auth) ideally a simple service like http://<server:port>/sap/bc/ping


Proxy Type: OnPremise (if you have to use the CloudConnector) or Internet (without CloudConnector)

 

 

006.png

 

 

go to the BackEnd Tab

 

Enter the following Data and click Save:


BackEnd URL: http://<server>:<port>

Proxy Type: OnPremise

Authetnication Type: Basic Authentication

Rewrite Mode: Rewrite URL on Back End

Check Via HCP App

 

007.png

How To Create the offline Fiori CRM App Part 1

$
0
0

Since October 2015 the first two CRM Fiori Apps are available as offline-enabled Apps: MyAccounts and MyContacts.

 

See here: http://scn.sap.com/community/crm/sales/blog/2015/10/09/using-crm-fiori-apps-offline

 

More informations about Packaging Fiori Applications - Architecture and Life Cycle Management

Capture.png

 

 

Prerequisites for my scenario:

- SAP Fiori 1.0 for SAP CRM 7.0 EHP3, SP10 (wave 10)

- HCPms (it's also possible with SMP)

- (HCC)

- SAP Mobile Secure

- latest version of the packager which is included in the Kapsel SDK

- npm, node.js (here: npm version 2.7.4, node version v0.12.2)

 

Steps:

 

Capture2.png

 

1. Create the Connection at SCC (SAP HANA Cloud Connector) if you use the SCC

2. Create the Connection at HCP

3. Prepare your Application at the HCPms

4. Get an SAP Mobile Secure Account

5. Create an Android Signing ID

6. Get you SAP Mobile Secure Cloudusername and password

7. Download the packager

8. Prepare the appconfig

9. Package the App

10. Create the Cordova App

11. Download it from your SAP Mobile Secure Account and run it

My Ultimate SAP Web IDE Walkthrough

$
0
0

Two weeks ago I presented SAP Web IDE at SAPPHIRE 2016 in Orlando. It was a great event and SAP Web IDE got lots of attention.

 

For my session, I prepared a walkthrough video for the "must-know" features of SAP Web IDE. I thought it would be a good idea to share this video also on SCN.


Note that you can follow along and run the demos on your own free trial account.


Feel free to comment or ask me anything.


(Click on the video title below if you want to watch the full screen version on YouTube)


Table of Contents

00:00     Introduction

00:23     On-Boarding

02:10     SAP Web IDE Welcome Screen

02:40     Run Sample App

06:00     Create Master-Detail App & Use the Code Editor

13:20     Working with the Layout Editor

17:00     Deploy to SAPUI5 ABAP Repository & SAP HANA Cloud Platform

22:30     Extend Existing App (Add/Remove UI Controls)


Breadcrumbs in SAPUI5

$
0
0

Hi,

 

After a long time, found some time to share something which I have worked on.

Recently, I had a requirement which demanded me to have navigation using a breadcrumb. Just a brief description of breadcrumb is as follows:

"A breadcrumb is a link/button(or a series of them) which displays each page viewed by a visitor of a website in the order the pages were viewed".

Something as shown in the figure:                     


breadcrumb1.png

 

 

In one of the recent releases SAP has releases a control called breadcrumb. But that did not go well my projects requirement mainly because of the look and feel. As this how it looked:

breadcrumb1.png

 

 

So, just thought of trying my hand in designing the breadcrumb look alike using sap.m.SegmentedButton wrapped in a custom css.

Segmented Button normally looks like:

breadcrumb1.png

 

 

Following is the code for implementing it.

View.xml

<mvc:View controllerName="BreadCrumbsDemo.controller.View1" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"

  xmlns="sap.m">

   <App>

    <pages>

     <Page title="{i18n>title}">

        <content>

         <HBox class="breadCrumbs" width="100%" alignItems="Center">

           <SegmentedButton class="sapUiSmallMarginBottom" width="100%" height="100%">

             <items>

               <SegmentedButtonItem text="View1"/>

               <SegmentedButtonItem text="View2"/>

               <SegmentedButtonItem text="View3"/>

             </items>

          </SegmentedButton>

        </HBox>

      </content>

     </Page>

    </pages>

   </App>

</mvc:View>


 

style.css

.breadCrumbs> .sapMFlexItem ul li {

    width: 25.3333333333333% !important;

    display: block;

    float: left;

    height: 48px;

    background: #85c1e9;

    text-align: center;

    padding: 0px 40px 0 40px;

    position: relative;

    margin: 0 10px 0 0;

    font-size: 20px;

    text-decoration: none;

    color: #fff;

}

.breadCrumbs> .sapMFlexItem ul li:first-child {

   z-index:3;

}

.breadCrumbs> .sapMFlexItem ul li:nth-child(2) {

   z-index:2;

}

.breadCrumbs> .sapMFlexItem ul li:nth-child(3) {

   z-index:1;

}

.breadCrumbs> .sapMFlexItem ul li:last-child {

   background: #2e86c1 !important;

    color: #000;

}

.breadCrumbs> .sapMFlexItem ul li:last-child:after {

  border-left: 40px solid #2e86c1 !important;

}

.breadCrumbs> .sapMFlexItem ul li:before {

    content: "";

    border-top: 24px solid transparent;

    border-bottom: 24px solid transparent;

    border-left: 40px solid #e6e6e6;

    position: absolute;

    left: 0;

    top: 0;

    padding: 0px 40px 0 80px;

}

.breadCrumbs> .sapMFlexItem ul li:after {

    content: "";

    border-top: 40px solid red;

    border-bottom: 40px solid red;

    border-left: 40px solid blue;

    position: absolute;

    right: -40px;

    top: 0;

    border-top: 24px solid transparent;

    border-bottom: 24px solid transparent;

    border-left: 40px solid #85c1e9;

}

.breadCrumbs> .sapMFlexItem {

    width: 100%;

    background:#e6e6e6;

}

.breadCrumbs .sapMSegB .sapMSegBBtn {

    list-style: none;

    text-overflow: ellipsis;

    overflow: initial;

    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);

    text-align: center;

    cursor: pointer;

    vertical-align: text-bottom;

    box-sizing: border-box;

    display: inline-block;

    border:none;

}

.breadCrumbs .sapMSegBBtn.sapMSegBBtnFocusable.sapMSegBBtnSel + .sapMSegBBtn {

border-left: none;

}

 

Ultimately, this is what you have.

 

breadcrumb1.png

Could always be better used with much better css.

SAP Web IDE does not allow to manage App folders in groups

$
0
0

SAP Web IDE cloud connectivity requires project folder direct below root node “Workspace”

 

In the HANA Cloud Platform cockpit I’ve setup a connection to the demo Gateway system. Next, in SAP Web IDE I created a new App project folder. As I prefer a manageable overview of all Apps (to be) developed in Web IDE, I created that App Folder in a subfolder beneath the Workplace folder:

2nd level project folder in Web IDE.png

This however gives problems within Web IDE wrt setting up the cloud connectivity.

 

Issue 1

neo-app.json generation is not available; that is, the menu option (New / Cloud Connectivity Configuration) is disabled on the project folder level:

neo-app generation not available.png

It is only enabled for folders that are direct below root node 'Workplace'.


This issue/shortcoming can be pragmatic resolved by generated the neo-app.json file on a temporary project folder that is direct located below 'Workplace', and copy + paste it in the 2nd level project folder.

 

Issue 2

At runtime, the destination to the consumed OData service is not correct resolved, and data cannot be consumed. Via F12 I observe an HTTP 503 error on connecting to the REST service destination:

Connection destination not available.png

I duplicated the project folder direct below 'workplace' (via Web IDE export + import commands), and without any code nor configuration changes ran the App from this location. And now the HANA dispatcher does handle the request, and the accessed Gateway service returns data:

Gateway service available.png

 

 

I compared the urls generated from Web IDE to the service destination in the 2 situation. The only difference is in the 'webidetesting<number>' part. Apparently there is some "magic" in Web IDE that reserves a dispatching url in HCP for service destinations, and that 'magic' is dependent on the project folder located direct below 'workplace'.

 

I considered as workaround to modify the 2nd level project in manifest.json and have it use the absolute connecting url to service:

Setup absolute path to datasource destination.png

 

However, that setup runs into a cross-domain issue, and is thus neither working:

Cross-Domain issue to absolute url.png

 

The only resolution for this is to comply to the 'implicit rule' of Web IDE, and place the project folder thus direct below root node "Workplace". With the drawback that you loose the option to structure and classify your projects / Apps folders, and all need to be administrated at the same level as sibling nodes. I would rather be able to make in Web IDE visual groups of project / Apps folders per customer and / or functionality, e.g. for HR, Finance, Marketing. Perhaps in a next version of Web IDE?

 

 

 



Hybrid UI5 App - Cordova plugin version management in WebIDE

$
0
0

Hi all,

 

Introduction

 

I've been working on a Hybrid Mobile App based on Cordova. Therefore I've used the WebIDE and the Hybrid App Toolkit for my developments.

 

 

Problem description

 

During the developments I had the need to use a cordova plugin, "cordova-sqlite-storage":

 

https://www.npmjs.com/package/cordova-sqlite-storage

 

I didn't just need this plugin, I needed a specific version.

 

On your local pc it's easy to add a version when you're adding a plugin to your cordova project. You can use the following command:

 

cordova plugin add <plugin[@<version>]

 

I'm using the SAP WebIDE which executes all the commands for you. This makes it all very easy to generate your cordova project with all the required plugins. But it also makes it difficult to manipulate and control the cordova project. This is how I was able to add the version to a cordova plugin from in the SAP Web IDE.

 

The Solution

 

Add a cordova plugin

 

Go to the "Project Settings":

plugin1.png

"Device Configuration" (Only available if it's a mobile project) ==> Plugins ==> Custom ==> Add or Remove

 

plugin2.png

 

Search for your plugin. The first thing I've tried was adding the version at this point. But as you can see... Error, not possible.

 

plugin3.png

 

 

Because that didn't work out, I just added the plugin without a version:

 

Plugin name ==> "+" ==> "OK" ==> You'll see the plugin in the list of custom Cordova plugins

plugin4.png

 

Add the version to the cordova plugin

 

For adding the version to the cordova plugin go to the ".project.json" file:

 

plugin5.png

 

Search for your plugin and add "@" behind the name of the plugin together with the version number:

 

==> "registry": "<plugin name>@<version number>"

plugin 6.png

 

The next time that you deploy the Hybrid app to the "Hybrid App Toolkit" it will use the version that you've defined in the configuration.

 

Hope it can help you and save some research

 

Kind reagards,

Wouter

TreeTable in Fiori(Web IDE) for multi level categorization of CRM WebUI

$
0
0


I would like to show tree table in Fiori(Web IDE) using UI5 SDK (sap.ui.table.TreeTable) for multi level categorization of CRM WebUI.

 

Multi level categorization in CRM WebUI

Multi Level Categorization in CRM WebUI.jpg

do not.jpg

    On previous project, Fiori/UI5 Architecture designed as shown below using multiple Entity types with Navigation, Entity Sets, Function Imports and Select DropDown;


    [Select DropDown in Fiori]

 

     <Select id="category1Select" change="onCategory1Change"></Select>

     <Select id="category2Select" change="onCategory2Change"></Select>

     <Select id="category3Select" change="onCategory3Change"></Select>

     <Select id="category4Select" change="onCategory4Change"></Select>

     <Select id="category5Select" change="onCategory5Change"></Select>

     ..

     <Select id="categoryNSelect" change="onCategoryNChange"></Select>

select dropdown.jpg

 

   [SEGW]

entity types.jpg

  Category 1 ->(Navigation)-> Category 2 ->(Navigation)-> Category 3 ->(Navigation)-> Category 4 ->(Navigation)-> Category 5 …->(Navigation)-> Category N

 

  It is NOT a good design(solution).

 

  We DONOT need to create multiple Entity Types with Navigation

  We DONOTneed to create multiple Entity Sets for each Category level

  We DONOTneed to create multiple Select DropDown for each category level

  We DONOTneed to create javascript for each category changes to populate child categories in each category level

 

do.jpg

   Here is a simple design(solution).


   I have created below;

     - 1 Structure

     - 1 Entity Type

     - 1 Entity Set

     - 1 Function Imports

     - 1 Execute Action for function import in class DPC_EXT

     - 1 Tree.Table in View.xml

     - javascript to read category OData, transform and populate in Controller.js

   

     Structure 

     structure.jpg

     [SEGW]

     segw.jpg

     Entity Type 

     Entity type.jpg

     Entity Set 

     EntitySet.jpg

     Function Import 

     Function Import.jpg

     Function Import Para.jpg

     Execute Action in class DPC_EXT to get Multi Level Categorization entities

     se24.jpg

 

     [/IWFND/GW_CLIENT]


     /sap/opu/odata/sap/ZMY_CATEGORY_SCHEMA_SRV/GetAllCategory?SchemaID='CATEGORY_SCHEMA_TASKS'&Level=' '&$format=json


     NB: If you want to get only certain level, just pass Level='1' , Level='2'  or Level='10'


 

     [View.xml in Fiori(Web IDE)]


     <table:TreeTable              id="TreeTable"

                                             rows="…"

                                             enableSelectAll="false"

                                             expandFirstLevel="true">             

     <table:toolbar>

     <m:Toolbar>

     <m:Button text="Toggle" press="onexpandTreeItem"/>

     <m:Button text="ExpandAll" press="onexpandTreeItem"/>

     <m:Button text="CollapseAll" press="oncollapseTreeItem"/>

     <m:Button text="Clear" press="onclearSelectionTreeItem"/>

     </m:Toolbar>               

     </table:toolbar>

     <table:columns>

                    <table:Column width="10rem">

     <Label text="ID"/>

     </table:Column>

     <table:Column width="15rem">

     <Label text="Description"/>

     </table:Column>

               </table:columns>

     </table:TreeTable>

 

     [Controller.js in Fiori(Web IDE)]

    

     onInit: function() {

      // reading OData

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

     treeModel.loadData("/sap/opu/odata/sap/ZMY_CATEGORY_SCHEMA_SRV/GetAllCategory?SchemaID='CATEGORY_SCHEMA_TASKS'&Level='

                                   '&$format=json", null, false );

     this.getView().setModel(treeModel, "treemodel");

 

     // transformation : Reference from Mike Dole's transformation logic

     http://scn.sap.com/community/developer-center/front-end/blog/2016/05/29/as-easy-as-one-two-tree-simple-mapping-of-tree-table-to-json-model

     var deeptreeData = this.treetransformTreeData(data);

     this.treesetModelData(deeptreeData);

      },


     ontoggleTreeItem: function() {},

     onexpandAllTreeItem: function() {},

     oncollapseAllTreeItem: function() {},

     onclearSelectionTreeItem: function() {

          var oTreeTable = this.getView().byId("TreeTable");

          oTreeTable.clearSelection();

     }

 

     Finally, Here is a TreeTable in Fiori(Web IDE) for multi level categorization of CRM WebUI;

  webide.jpg

     Choose one of category and click the 'Submit' button and then populate selected CategoryGuid!!!

 

    

Setup your SAP Web IDE on HANA Cloud Platform Part 6

$
0
0

In previous Blogs I've shown you how you can set up your SAP Web IDE on Hana Cloud.

 

 

 

part 1

  • Opening SAP Web IDE for the first time
  • Entering the Git User Settings
part 2
  • Installing and configuring the HANA Cloud Connector
part 3
  • Connecting to the remote system
part 4
  • Test the SAP Web IDE
part 5this part
  • Deploy your application to the ABAP Repository
  • Test your application at the ABAP system
  • Import your application from SAP Gateway to SAP Web IDE

We have now configured and tested our SAP Web IDE on HANA Cloud.In the this part I will show you how you can deploy your application to the ABAP Repository.

 

Deploy the application to the ABAP Repository

Go back to SAP Web IDE. You may want to close other open tabs and windows.Select the project, right-click and select Deploy> Deploy to SAPUI5 ABAP Repository27.pngFor the Deployment Options, Select GM6 system and if authentication is needed provide user ID/Pwd. KeepDeploy a new application selected and click Next48.pngEnter a name, e.g.  Z_TimeApproval (the name needs to start with Z), enter any description and clickBrowse. Note:  In Package field, $TMP is defaulted by the system if your system only supports local object creation. Click Next49.pngClick Finish to deploy your application to the SAPUI5 ABAP Repository50.png
Wait for the successful feedback. Click on OK. You have successfully deployed your app to the ABAP repository
51.png52.png

Test your application at the ABAP system

Go to SAP Logon and logon to the GM6 system.53.pngEnter the transaction code SE8054.pngClick on Repository Browser. Choose BSP_Application and enter the first letters of your uploaded application name (here: Z_TIME). The system will show you your application. Double Click on it.55.png56.pngClick on the arrow in front of your application, choose Pages with Flow Logic, and open it. Here you can see one file:index.html. Right click on it and choose Test. This will open your default browser with your application. (Your complete Source code of your Application you can find under PageFragments.)57.png58.png

Import your application from SAP Gateway to SAP Web IDE

Click File >Import> Application from SAPUI5 ABAP RepositoryUpdate: you have not to create the folder anymore, this happens automatically28.pngSelect the system where the app had been deployed to.Search for the app, e.g. Z_TimeApprovalSelect the app and click OK.29.PNGA message indicates the import has finished.30.PNG31.pngRun the application and verify the application is running

  1. Select the file index.html of the application
  2. Click on the Run

32.PNG

If authentication is required, enter your User Name and PW for your SAP Gateway system.The Application Preview is started, the application is loading and data is fetched from the OData Service.


The Application will also start in Full Size Mode, if you want to change this, look at part 4.

78.PNG

 

 

 

More Web IDE stuff published by Technology RIG

 

 

See you

Claudi

Compare Event handling mechanism: SAPUI5 and Angular

$
0
0

Recently I am studying Angular in my spare time. And I would like to write down here what I have learned about Angular, comparing its design with UI5. In this blog I will only focus on event handling topic.

 

I have already explained how I do self study on UI5 event handling stuff in this blog, and Andreas Kunz has given very thorough comments on the design idea behind the native event and semantic event, you should NOT miss those comment

 

UI5 event handling

Let's quickly review what UI5 developers should do if they need to listen to an event. Still use button as example:

 

Just call function attachPress and pass in our event handling function as argument:

 

clipboard1.png

The button instance itself does not own the function attachPress:

clipboard2.png

Instead, it is provided by the node in the button instance's prototype chain, EventProvider.

clipboard3.png

When attachPress is called:

clipboard4.png

When we click button in UI:

clipboard5.png

clipboard6.png

This is very clear. Now let's move to Angular.

Angular event handling

You can find a sample Angular application from this url. It is written based on Angular 1.2.18.

clipboard1.png

clipboard2.png

When I first study this application, the attribute "ng-click="sortField = 'name'"" seems to me a complete magic: how could a fragment of code in html node attribute executed?

 

I am sure it is "ng-click" which achieves Angular's specific way of event handling, so I tried to figure it out by debugging.

 

Angular framework has its own initialization and bootstrap phase, just the same idea as UI5. During its bootstrap, Angular will traverse the html DOM tree ( line 964, compile function ) and parse the html element node recursively. If an attribute with Angular namespace "ng" is detected within an element node, the detected attribute is called "directive" in Angular and some special logic will be applied on that node, in function "applyDirectivesToNode".

clipboard1.png


Here below is how event registration is done by Angular for us:

clipboard2.png

Let's confirm our assumption. I click hyperlink in UI: the native event "click" is passed to the wrapper function fn in line 15330.

clipboard3.png

The wrapper function contains the logic to execute "sortField = 'name'" specified in html source code.

Its core is implemented via the assign function:

clipboard4.png

Finally, scope obj ( you can consider scope as "Model" in UI5 at this moment ) has attribute sortField which has been assigned with a new value "name", this is how "sortField = 'name'" is executed.

clipboard5.png

clipboard6.png

Hope this blog can help you gain a very basic understanding about Angular event handling

SAPUI5 Table: How to create different control templates in one column

$
0
0

Hello All,

 

Now a days, customer requirements are being so 'Custom'. One of the scenarios that one of my former colleague had was 'In sap.ui.table.Table (Grid Table), how can we create different control templates based on a model property?'

 

First I had thought, that it is going to be easy, if we use 'Factory function' on bindAggregation method. Since I had used the same earlier to make it work on sap.m.Table (Responsive Table).


If I go through the code, that was implemented for Responsive table:

Model data that I had:

[{            "ProductId": "1239102",            "Name": "Power Projector 4713",            "Weight": 34,            "Control": "C",            "Availability": "Available"          }, {            "ProductId": "2212-121-828",            "Name": "Gladiator MX",            "Weight": 324,            "Control": "M",            "Availability": ""          }, {            "ProductId": "K47322.1",            "Name": "Hurricane GX",            "Weight": 54,            "Control": "C",            "Availability": "Out of Stock"          }, {            "ProductId": "22134T",            "Name": "Webcam",            "Weight": 198,            "Control": "P",            "Availability": ""          }....
........]

And my XML View would be:

     <Table id="idProductsTable"               mode="SingleSelectMaster"              growing="true"              growingThreshold="5"              selectionChange="onSelectionChange"              updateFinished="onUpdateFinished"              items="{                           path: '/',                           factory: 'demo.FactoryDefinition.factory'                      }">                <columns>                  <Column>                    <Label text="ID" />                  </Column>                  <Column>                    <Label text="Product" />                  </Column>                  <Column>                    <Label text="Weight" />                  </Column>                  <Column>                    <Label text="Availability" />                  </Column>                </columns>       </Table>

In the XML view code, you can see the 'items' has a binding path and also a factory function defined with namespace where the file is present.

Factory Function --> demo.FactoryDefinition.factory

 

    //Factory Definition    sap.ui.define([      'sap/m/ColumnListItem',      'sap/ui/core/Item',      'sap/m/Text',      'sap/m/Input',      'sap/m/ComboBox',      'sap/m/MultiComboBox'    ], function(ColumnListItem, Item, Text, Input, ComboBox, MultiComboBox) {      "use strict";      var FactoryDefinition = {        factory: function(id, context) {          var oTemplate = new Item({            text: "{Text}"          });         var oContext = context.getProperty("Control");          if (oContext == "C") {            return new ColumnListItem({              cells: [new Text({                  text: "{ProductId}"                }),                new Text({                  text: "{Name}"                }),                new Text({                  text: "{Weight}"                }),                new Input({                  value: "{Availability}"                })              ]            })          } else if (oContext == "P") {            return new ColumnListItem({              cells: [new Text({                  text: "{ProductId}"                }),                new Text({                  text: "{Name}"                }),                new Text({                  text: "{Weight}"                }),                new ComboBox({                  width: "100%",                  selectedKey: "{Availability}"                }).bindAggregation("items", "/oValues", oTemplate)              ]            })          } else if (oContext == "M") {            return new ColumnListItem({              cells: [new sap.m.Text({                  text: "{ProductId}"                }),                new Text({                  text: "{Name}"                }),                new Text({                  text: "{Weight}"                }),                new MultiComboBox({                  selectedKeys: ["{Availability}"]                }).bindAggregation("items", "/oValues", oTemplate)              ]            })          }        }      };      return FactoryDefinition;    }, /* bExport= */ true);

'context' argument inside the factory function holds the data context where you can read the property values. For our requirement, we need to read through the 'Control' property, check what value is present and depending on that we need to create the column list item template with required cells.

 

If 'Control' property value is 'C' --> Input

If 'Control' property value is 'P' --> ComboBox

If 'Control' property value is 'M' --> MultiComboBox

 

Factory function is a pretty good concept that one can follow not only for table but for list, IconTabBar etc.

 

Full working demo of Responsive Table having different control templates:Plunker - ResponsiveTable

 

Now the interesting thing is that this piece of code, I thought it would work for Grid table i.e., sap.ui.table.Table as well, but it didn't (Strange though!). I am not sure where I had gone wrong.


This is what I tried using 'rows' aggregation: Plunker - Grid Table (Not Working) though I am able to see a scrollbar is loaded with paginator (that means the rows binding works) but no values, I tried to check the binding for control templates, they are fine but no values loaded.


It doesn't seem to work, then I have tried to check an alternative and I found one. I used a flag to toggle the visibility of different controls placed in horizontal layout.


So in one column, I created a Horizontal Layout as template where I placed three controls, which are Input / ComboBox / MultiComboBox. Now I used a formatter on 'visible' property to toggle the visibility and fetch the output as expected.


Full working demo of Grid Table having different control templates: Plunker - Grid Table (Working)

 

But, if anyone has a solution using factory function for Grid Table (sap.ui.table.Table). Please share / respond to this thread: Factory function problem: sap.ui.table.Table

 

So, this is it! I hope this would be helpful who might have similar requirement in future.

Thank you and have a great day ahead!.

 

Regards,

Sai Vellanki.

SAP Web IDE - Technical FAQs

$
0
0

TechnicalFAQ-banner2.png

 

 

SAP Web IDE is a powerful, extensible, cloud-based integrated development tool that simplifies end-to-end application development for

SAP Fiori and SAPUI5 apps. It lets you rapidly design, build, and deploy SAP Fiori web applications based on SAPUI5.

 

This document contains the list of technical FAQs for SAP Web IDE.

 

There is also a list of the general FAQs.

 

For more information on SAP Web IDE, visit our SCN page.

Input: How to highlight suggestion items

$
0
0

Hello All,

 

Input control is where the user can enter data. It has some good built-in features like setting the type, suggestion items pop-up, value help dialog etc.

 

I remember there was a question on SCN few months back about how to highlight input suggestion items. I had provided a solution for it, but that seems to fail during string comparison and also finding list pop-up id dynamically.


So, I have to re-built the code to overcome above issues.

My JSON Model would be:

          var aData = [{            "ProductId": "1239102",            "Name": "Power Projector 4713",            "Category": "Projector"          }, {            "ProductId": "2212-121-828",            "Name": "Power Tag",            "Category": "Graphics Card"          }, {            "ProductId": "K47322.1",            "Name": "Webcam Smaill",            "Category": "Graphics Card"          }, {            "ProductId": "22134T",            "Name": "Webcam",            "Category": "Accessory"          }, {            "ProductId": "P1239823",            "Name": "Monitor Locking Cable",            "Category": "Accessory"          }, {            "ProductId": "214-121-828",            "Name": "Laptop Case",            "Category": "Accessory"          }, {            "ProductId": "215-121-828",            "Name": "Laptop Small",            "Category": "Accessory"          }, {            "ProductId": "XKP-312548",            "Name": "USB Stick 16 GByte",            "Category": "Accessory"          }, {            "ProductId": "KTZ-12012.V2",            "Name": "Deskjet Super Highspeed",            "Category": "Printer"          }, {            "ProductId": "KTZ-12012.V2",            "Name": "Deskjet Super1",            "Category": "Printer"          }, {            "ProductId": "KTZ-12012.V2",            "Name": "Deskjet Super2",            "Category": "Printer"          }];

And the XML view code:

<mvc:View height="100%"    controllerName="demo.InputPage"    xmlns:l="sap.ui.layout"    xmlns:model="sap.ui.model"    xmlns:core="sap.ui.core"    xmlns:mvc="sap.ui.core.mvc"    xmlns="sap.m">      <Input id="oInput"          showSuggestion="true"          showValueHelp="false"          suggest="onSuggest"          suggestionItems="{                            path: '/'                            }">        <core:Item text="{Name}" key="{ProductId}" />      </Input></mvc:View>

Now according to my JSON Model, when user types in the name, input suggestion would pop-up highlighting the characters that are typed.

To do that, I hear the suggest event of Input, where I can fetch the value that is entered and compare it with value that is shown on pop-up.

 

Here is the code, which does highlighting:

onSuggest: function(oEvent) {    var oValue = oEvent.getParameter("suggestValue");    var that = this;    jQuery.sap.delayedCall(100, null, function() {        that.highlight(oValue);    });
},
highlight: function(text) {    var oInput = this.getView().byId("oInput");    var oList = oInput._oList;  //Get Input List popup    var inputText = oList.$().find('.sapMSLITitleOnly');  //Find the title that needs to be highlighted    var oItems = oList.getItems();    $.each(inputText, function(i, value) {       var innerHTML = inputText[i].textContent;   //Get the title content       var oTitle = oItems[i].getTitle();    //Get Items title       var index = innerHTML.indexOf(oTitle);    //Compare and find the title index        if (index >= 0) {          innerHTML = innerHTML.substring(0, index) + "<span class='highlight'>" + innerHTML.substring(index, index + text.length) + "</span>" + innerHTML.substring(index + text.length);          inputText[i].innerHTML = innerHTML;    }
});
}

Interesting part was getting the index when we compare it with a string with case-sensitive.

Consider my first value in model, which is 'Power Projector 4713', when user types 'P' which is in caps, it works fine. If user types 'p' which is in small case then it doesn't find the index and returns '-1'.

 

To overcome above issue, I fetch list pop-up aggregation 'items' where I get the normal text using item getTitle() method and compare it with Input pop-up item title. Now it gives me the index where I can successfully highlight the pop-up text.

'Highlight' style class has been used for highlighting text:

    .highlight {      background-color: #ffff66;    }

Working demo of Highlight Input Suggestion Items: Plunker - Input Suggestion Items (Highlight)

 

Working Snip:

Capture.gif

 

Thanks for reading my blog, have a nice day!

 

Regards,

Sai Vellanki.


Custom Control: Highlightable Text

$
0
0

Inspired by Sai's blog Input: How to highlight suggestion items

 

It is common that we need to highlight text in table, list and other container controls. And we do not wish to iterate through all the items to highlight the text.

One way to handle this is to use a custom control and a model. The former is responsible for highlighting the text and the latter is responsible for informing the control what is the text to highlight.

 

Here is the JSBIN

JS Bin - Collaborative JavaScript Debugging

 

As an enhancement, we can alter this control to do underlining or/and handle regular expression for highlighting text.

 

Thanks

-D

SAPUI5 Table: Dynamic Creation based on CSV data

$
0
0

Hello All,

 

'CSV' is a simple format used to store tabular data, such as spreadsheet or database. Data in the CSV format can be imported.

 

Now, in our case we have the data placed in CSV format. Using sap.ui.unified.Uploader, we can upload 'CSV' document and has an ability to restrict the file type using 'setFileType' method.

 

Once the document is uploaded, we can convert it to JSON format by parsing through CSV data and store the JSON data into a model.

 

        handleUpload: function(oEvent) {          var that = this;          var oFile = oEvent.getParameter("files")[0];          if (oFile && window.FileReader) {            var reader = new FileReader();            reader.onload = function(evt) {              var strCSV = evt.target.result; //string in CSV               that.csvJSON(strCSV);            };            reader.readAsText(oFile);          }        },        csvJSON: function(csv) {          var lines = csv.split("\n");          var result = [];          var headers = lines[0].split(",");          for (var i = 1; i < lines.length; i++) {            var obj = {};            var currentline = lines[i].split(",");            for (var j = 0; j < headers.length; j++) {              obj[headers[j]] = currentline[j];            }            result.push(obj);          }          var oStringResult = JSON.stringify(result);          var oFinalResult = JSON.parse(oStringResult.replace(/\\r/g, ""));          //return result; //JavaScript object          sap.ui.getCore().getModel().setProperty("/", oFinalResult);          this.generateTable();        }

From above code Table data is ready. Now, we will have to fetch the column name labels. To fetch key names from model, we can use following method:

          var oModel = sap.ui.getCore().getModel();          var oModelData = oModel.getProperty("/");          var oColumns = Object.keys(oModelData[0]);

Store the key names into different property on same model and create the template that need to be used for 'columns' aggregation.

          var oColumnNames = [];          $.each(oColumns, function(i, value) {            oColumnNames.push({              Text: oColumns[i]            });          });          oModel.setProperty("/columnNames", oColumnNames);          var oTemplate = new Column({            header: new Label({              text: "{Text}"            })          });

For 'items' aggregation we can use the default binding path which has data and create the template that need to be used:

          var oItemTemplate = new ColumnListItem();          var oTableHeaders = oTable.getColumns();          $.each(oTableHeaders, function(j, value) {            var oHeaderName = oTableHeaders[j].getHeader().getText();            oItemTemplate.addCell(new Text({              text: "{" + oHeaderName + "}"            }));          });

Now getting it to all together, bind 'columns' / 'items' aggregation with respective binding paths and templates.

Finally, table gets generated based on CSV data. In result, no need to re-code if you want to use different CSV documents. You can just upload and read it.

 

Full working demo of Dynamic Table creation based on CSV data:Plunker

Working Snip:

Capture.gif

 

Thanks for reading my blog, have a great day.


Regards,

Sai Vellanki.

Cross Application Navigation between SAPUI5 applications

$
0
0

At SAP Inside Track Hamburg 2016 together with Remo Bettin we demonstrated during a short lightning talk how to do Cross Application Navigation between different applications on the Fiori Launchpad.

 

While this topic is covered in SAPUI5 help it is still not so easy to implement it. Therefore we built a small demo application in order to demonstrate how to use it.

 

Based on the entities of the Northwind OData Service we created four separate SAPUI5 Applications, one for orders, others for the corresponding customers and suppliers of the orders shown in the Orders app. The last application we used is based on the categories entity of the Northwind service.


All these applications are added to the Fiori Launchpad in the HANA Cloud Platform (which is named flpnwc there and available as a subscription in the HCP account).

Bildschirmfoto 2016-06-15 um 22.03.16.png

Picture 1: Fiori Launchpad in HCP showing the applications

 

In order to be able to use cross app navigation all applications need to be assigned to intents. The intent consists of a semantic object and an action on this object. For our applications we used the entity name as semantic object and all applications use the "display" action to display some data. The semantic object is declared in the manifest.json from the SAPUI5 app.

 

Bildschirmfoto 2016-06-20 um 15.26.11.png

Picture 2: Navigation properties in manifest.json

 

Once an application is reached it uses inner app navigation to find the correct route to a view.

The following example shows the routes in the supplier app. Here to navigate to a supplier detail we use a route "Suppliers/5" in order to open the object view and show details of supplier with ID 5.

 

Bildschirmfoto 2016-06-20 um 15.23.49.png

Picture 3: Routes in manifest.json

 

In order to navigate from one application to another in the Fiori Launchpad (FLP) we need to implement some code at the following locations:

 

1. The starting point of our CrossApp-Navigation is pressing on the supplier column in the Orders app. There we added the onPressSupplier-event in the column of the detail view where the supplier is shown

 

 

onPressSupplier: function(oEvent) {  var supplier = oEvent.getSource().getBindingContext().getProperty("Product/SupplierID"); // read SupplierID from OData path Product/SupplierID  var oCrossAppNavigator = sap.ushell.Container.getService("CrossApplicationNavigation"); // get a handle on the global XAppNav service  var hash = (oCrossAppNavigator && oCrossAppNavigator.hrefForExternal({  target: {  semanticObject: "Supplier",  action: "display"  },  params: {  "supplierID": supplier  }  })) || ""; // generate the Hash to display a Supplier  oCrossAppNavigator.toExternal({  target: {  shellHash: hash  }  }); // navigate to Supplier application  }

2. In the onInit-Event of the Master view of the Suppliers App we attach the event _onMasterMatched:


this.getRouter().getRoute("master").attachPatternMatched(this._onMasterMatched, this);

3. In the _onMasterMatched we read the Startup parameters where we get the Supplier ID:


_onMasterMatched :  function() {  var supplierID;  var startupParams = this.getOwnerComponent().getComponentData().startupParameters; // get Startup params from Owner Component  if ((startupParams.supplierID && startupParams.supplierID[0])) {  this.getRouter().navTo("object", {  supplierID: startupParams.supplierID[0]  // read Supplier ID. Every parameter is placed in an array therefore [0] holds the value  }, true);  } else {  this.getOwnerComponent().oListSelector.oWhenListLoadingIsDone.then(  function(mParams) {  if (mParams.list.getMode() === "None") {  return;  }  supplierID = mParams.firstListitem.getBindingContext().getProperty("SupplierID");  this.getRouter().navTo("object", {  supplierID: supplierID  }, true);  }.bind(this),  function(mParams) {  if (mParams.error) {  return;  }  this.getRouter().getTargets().display("detailNoObjectsAvailable");  }.bind(this)  );  }


Demonstration

Based on the entities of the Northwind OData Service we created four separate SAPUI5 Applications. In the Orders application you see a Master-Detail navigation for selecting an order and displaying the corresponding order details.


We select one order in the left master view and after that click on Customer "Vins et alcools Chevalier" with CustomerID "VINET":

Bildschirmfoto 2016-06-15 um 22.10.32.png

 

This creates the link "#Customer-display?customerID=VINET&/Customers/VINET".

The action "display" in the application with semantic object "Customer" is invoked.

 

The startup parameter is "customerID=VINET". This invokes the inner app navigation in the Customer app resolving in the URL fragment "/Customers/VINET" which is the route to the object view and shows the details view of customer "Vins et alcools Chevalier".

 

Bildschirmfoto 2016-06-15 um 22.11.26.png

 

Similar routing happens when clicking on the supplier in the orders app:

Bildschirmfoto 2016-06-15 um 22.12.02.png

 

Question

When using the sap.ushell.services.CrossApplicationNavigation.toExternal() method you can optionally provide a component (the root component of the application). Unfortunately in the help you can't find a hint for what this could be used. Maybe somebody knows the intent of this parameter?

 

Hopefully this blog post will be of some help for your implementation of Cross application navigation. In case you still have questions I would be happy to answer them if possible.

 

Cheers,

 

Mark

My Journey to UI5 - Part 1

$
0
0

A little preamble

 

I’m writing this document more for my help in keep track of my success and, even more, my errors, following Fiori’s master rule “fall first, fall often”.

I’m using a real case from my company to try UI5: it’s a bit scaring since if things will not sort out well, it will be a real problem!

This will not be a pure technical blog, but a more descriptive one, with links over links to the sources I used.

The tech parts will follow in later entries.

 

My background

When I read about UI5, I was scared. Literally.

It has been almost 12 years since I developed anything for the web (in early 2Ks I worked with PHP) and surely I do not remember the last time I worked with JavaScript!

So it has been mandatory and useful get the bases to avoid running around like a drunken chicken trying to understand what a single row of code does.

There are a bunch of sources where you can learn and refine your JS skill:

  1. https://developer.mozilla.org/en-US/Learn/JavaScript
  2. http://javascriptissexy.com/how-to-learn-javascript-properly/
  3. http://www.w3schools.com/js/
  4. https://www.codecademy.com/
  5. https://mva.microsoft.com/training-topics/web-development#!level=100&jobf=Developer&lang=1033

 

I focused on Codeacademy (I heard a lot of stories about it and I was curious to try it out) and JavascriptIsSexy (hot name!).

I know the choice is not brain-guided, but it ended up with me understanding the basics and the core concepts of JavaScript so I’m pretty satisfied.

I encourage everyone to try out as many tutorials and site as possible to find which methodology and style fit better for herself.

 

Learn UI5’s basics

I was aware about the difference between OpenUI5 and SAPUI5 and, even if in a far away future my company will probably require to switch to OpenUI5, I sticked as starting point with SAPUI5 due the larger (and more familiar to me) community on SCN.

So I downloaded Eclipse ADT with all the option except the one for SAP Hana (we are on 7.31) and then… well, where I start from?

 

The best way I found out to learn something about UI5 has been following the tutorial "Walkthrough" https://sapui5.netweaver.ondemand.com/#docs/guide/3da5f4be63264db99f2e5b04c5e853db.html

And with “following the tutorial” I mean, following it step by step, deleting everything and trying to redo it by myself, adding or removing the pieces just to try.

This procedure (“fall first, fall often”, do you remember?) reminded me when I was a child and play with Lego: the first couple of times I followed the instructions, then I always tried to build my galleon or my spaceship just “guessing” the right way.
I do not need to say how many times I failed and throw everything away (yes, I’m still talking about my first app), but I think that’s the best way to catch up with the mechanisms of something.

It has been hard, really hard due my steamy temper, discovering that my ABAP skill were useless in this world and that I keep crushing and crashing against silly things I never ever cared about (because with common SAPGUI and ABAP objects/FM we many nice features out of the box while with UI5 you have to think about them).

But they really were? No, as you'll find out in later blogs if you find interesting following them, exactly the opposite.

 

O Data, OData, wherefore art thou OData?

Even if you can build a standalone app without any connection with SAP, we all know that we HAVE to communicate with SAP, reading and writing data, so, when I somehow mastered the basic concepts of MVC and UI5, I moved to study how SAP can generate an OData service.

After a bit of googling, I found this guide (maybe not so recent since it’s from 2012) which is written really well by Bertram Ganz and Bernhard Siewert

http://sapassets.edgesuite.net/sapcom/docs/2012/11/44779e8c-5b7c-0010-82c7-eda71af511fa.pdf

If you, like me, are new to OData Services, follow this guide and in a couple of hours you’ll have your Service ready and running.

Another guide, a bit more recent, I used a lot is http://scn.sap.com/docs/DOC-61821 from  Mohamed Meeran

 

Both of the guides rely on FMs to manage the data retrieval and update and, even if there is nothing wrong with them, I looked for something more… nice: http://www.abap-developers.com/2014/07/simple-openui5-application-i-how-to-create-odata-model-using-segw/

http://scn.sap.com/people/peter.marcely’s guide showed me how to bypass the FM and to use directly the classes generated for the Services.

I found it better, since I got less objects to manage (a dictionary structure and the classes) and I stick with OOP which is always nice in my opinion.

 

I got the ropes now, and all the tools available for my first app: I got my Lego’s pieces, all scattered around, a full set of instructions and a monster headache because I do not know from where to start…

 


Understand extend function in Component.js in Fiori application

$
0
0

For every Fiori application we have Component.js, and there is a function extend() call. See one example below.

What is the purpose of this function call and what functionality would it achieve?

clipboard1.png

In order to understand the logic of extend, it is necessary to understand prototype concept in JavaScript.  Let's have a look at some more simple example.

 

See this simple html source code:

<html><script>
function Animal(name) {
this.sName = name;
console.log("constructor in Animal");
}
Animal.prototype.speak = function() {    console.log("My name is " + this.sName);
};
function Cat(name) {    Animal.call(this, name);    console.log("constructor in cat");
}
Cat.prototype = new Animal();
var animal = new Animal("Jerry");
animal.speak();
var cat = new Cat('Tom');
cat.speak();
console.log("cat is animal?" + ( cat instanceof Animal ));
console.log("cat is Cat?" + ( cat instanceof Cat ));
console.log(cat.constructor);</script></html>

I use prototype inheritance to achieve the class inheritance logic which is commonly used in other language like Java.

cat instanceof Animal and cat instanceof Cat both return true as expected.

 

There are two flaws of this inheritance solution:

1. every variable created by function constructor has one attribute __proto__, which points to the prototype object of its constructor. This could be verified by the fact that statement "cat.__proto__ === Cat.prototype " returns true.

In this example, you can find there are actually duplicate attribute sName, one in cat itself and the other one in its __prototype__.

clipboard2.png

2. in above code line 17, I try to build the inheritance relationship from Animal to Cat. Here a new instance of Animal is created. Suppose in productive code if we have a complex implementation of Animal, this initialization could consume unnecessary resource and memory to finish.

 

So another approach is used:

 

<html><script>
Function.prototype.extend = function(parent) {
function dummy() {};
dummy.prototype = parent.prototype;
this.prototype = new dummy();
this.prototype.constructor = this;
}
function Animal(name) {
this.sName = name;
console.log("constructor in Animal");
}
Animal.prototype.speak = function() {    console.log("My name is " + this.sName);
};
function Cat(name) {
Animal.call(this, name);
};
Cat.extend(Animal);
var cat = new Cat("Jerry");
cat.speak();
console.log("cat is Cat?" + (cat instanceof Cat));
console.log("cat is Animal?" + (cat instanceof Animal));
console.log(cat.constructor);</script></html>

Both flaws in first approach are avoided:

 

1. No duplicate attribute "sName" in prototype chain now.

2. The initialization of a new instance of Animal when trying to build prototype chain is avoided. Instead here I use a very light weighted, dummy function as a bridge to connect Animal and Cat. The trick is done among lines 5 ~ 8 below. Once done, every variable created by constructor Cat has its __proto__ points to Animal.

clipboard3.png

Now we have already enough knowledge to understand the extend() call done in Componnet.js in Fiori application.

 

1. extend call will call Metadata.createClass.

clipboard4.png

2. In Metadata.createClass, the essential idea of line 333 is just exactly the same as the code in my second prototype inheritance approach:

 

function dummy() {};

 

dummy.prototype = parent.prototype;

this.prototype = new dummy();

 

clipboard5.png

a. within jQuery.sap.newObject, a dummy object will be created:

clipboard6.png

b. here the argument oPrototype is the prototype of sap.ca.scfld.md.ComponentBase:

clipboard7.png

Once prototype chain is built, the function call jQuery.sap.setObject is called to expose cus.crm.opportunity.Component as a global JavaScript object:

clipboard8.png

Finally these below are what we have got:

 

1. we can directly access cus.crm.opportunity.Component in JavaScript code or console thanks to jQuery.sap.setObject call.

clipboard9.png

2. The prototype chain from sap.ca.scfld.md.ComponentBase to cus.crm.opportunity.Component is built, which could be confirmed by the picture below:

clipboard10.png

Now when I enter the context of my application, I can get the instance of this component via this(controller reference).getOwnerComponent().

 

From the belowing two test statement in console, I can ensure that the prototype chain is built:

 

1. ownComponent.__proto__.__proto__.constructor === sap.ca.scfld.md.ComponentBase returns true

2. ownComponent.hasOwnProperty("getMetadata") returns false and ownComponent.__proto__.__proto__.hasOwnProperty("getMetadata") returns true.

clipboard11.png

clipboard12.png


from returned metadata, we can find all the metadata information defined in the application and passed from extend call:

clipboard13.png

Viewing all 789 articles
Browse latest View live




Latest Images