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

JSHint: Static code checks for JavaScript - Live as you type and during a maven build!

$
0
0

Introduction


JavaScript is a dynamically typed language and has many pitfalls. Therefore, static code checks are of great use - for beginners as well as for experienced developers. Literature is full of advice how to do things right and what to avoid (see Douglas Crockford: JavaScript: The Good Parts, David Flanagan: JavaScript: The Definitive Guide,Marijn Haverbeke: Eloquent JavaScript Second Edition). Fortunately, there are various tools available for checking your code automatically. Recently, JSHint has become the most popular because of its flexibility and integration into editors and toolsets.

 

Ideally, static code checks should be done at two levels:

  • During build time to ensure that the build breaks if your code contains errors, flaws, or some of the "bad parts" (as Douglas Crockford puts it)
  • During development while you type so you don't get frustrated by a build failing 10 times in a row because of trailing whitespace
  • Those two checks should be in sync to avoid double maintenance

 

This article is part of a series of articles about Test-Driven Development and JavaScript in which also the second topic will be covered in depth. Press 'like' on the overview blog post to stay tuned and get updates about more topics around software engineering with SAPUI5 and JavaScript!

 

Scope of this article


This article assumes you are building your project with maven and use eclipse to write your JavaScript. If your backend is implemented in Java, maven is one of the most popular ways to manage your dependencies and automate your build. However, checking your code as you type in eclipse is completely independent of your build process. JSHint can be integrated into other build processes as well (e.g. using Grunt).

 

Why JSHint?


JSHint started out as a fork of the very opinionated JSLint. One of its main advantages is that it is configurable via an external configuration file called .jshintrc. Furthermore, it offers a better configurability than JSLint, i.e. you can decide which checks are important for your project. It can be integrated easily into many editors such as eclipse, WebStorm/IntelliJ, and Sublime as well as build tools such as maven and grunt.

 

Live Checks in eclipse as you type


Go to the eclipse marketplace via Help --> Marketplace and search for 'JSHint' and install the plugin jshint-eclipse. Create a .jshintrc file in the root folder of your project. A detailed explanation of JSHint configuration options can be found at the JSHint Options Reference. Here is the configuration file we use in our project as some starting point:

 

{    "bitwise" : true,    "camelcase" : false,    "curly" : true,    "eqeqeq" : true,    "es3" : true,    "forin" : true,    "immed" : true,    "latedef" : "nofunc",    "newcap" : true,    "noarg" : true,    "noempty" : true,    "nonew" : true,    "plusplus" : false,    "quotmark" : false,    "undef" : true,    "unused" : "vars",    "strict" : false,    "trailing" : true,    "maxlen" : false,    "laxbreak" : true,    "globals" : {        "window" : false,        "document" : false,        "jQuery" : false,        "sap" : false,        "cockpit" : false,        "URI" : false,        "getCurrentAccount" : false,        "setTimeout" : false    }
}

To enable checks in eclipse go to Window --> Preferences --> JSHint --> Configuration and import the .jshintrc file in your project root.

 

jshint_configuration.png

 

Now right click on your project in the project explorer, choose properties --> JSHint and enable checks for all files you like. In our project, we don't check test files at the moment, so we have a check for all *.js files in src/main/js and all subdirectories. Save your changes.

 

activate_jshint2.png

 

Now it is time to see if JSHint works! Add a new file in src/main/js and paste the following code

 

function thisIsNeverUsed(){
 if (1 == 0)  console.log(" 1 is never equal 0")  switch (something) {  case 1:   console.log("it is 1");  default:   break;  }
 return true;
 var somethingElse = 3;
}

After saving the file you should end up with a nice set of JSHint errors, similar to mine.

 

jshint_errors.png

 

Keep the file in your project and resist the urge of correcting the mistakes - we'll need it in the next section!

 

Integrating JSHint checks into your maven build


While integration into eclipse is something which really helps you during development, there is only one way to ensure that certain error don't make it into the codebase: The build must fail. With maven, you can use the jshint-maven-plugin (formerly called jshint-mojo) to use the same .jshintrc file for checking your javascript code during the build. Copy the following to the <plugins> section of your pom.xml

<plugin><groupId>com.cj.jshintmojo</groupId><artifactId>jshint-maven-plugin</artifactId><version>1.3.0</version><executions>  <execution>   <goals>    <goal>lint</goal>   </goals>  </execution></executions><configuration>  <directories>   <directory>src/main/js</directory>  </directories>  <failOnError>true</failOnError>  <reportFile>${project.build.directory}/jslint.xml</reportFile>  <reporter>jslint</reporter>  <!-- assuming that the .jshintrc file is on the same level as the pom.xml -->  <configFile>.jshintrc</configFile></configuration></plugin>

Try to build your project with mvn clean verify and it should fail with the same errors which you saw in eclipse.

maven_errors.png

 

Disabling plugin execution during eclipse builds

 

As of now, you have two JSHint checks configured: One by an eclipse plugin, another one in your pom.xml. The maven integration of eclipse, called m2eclipse, tries to interpret everything in your pom.xml and act accordingly. However, you don't need to do the same checks twice, so you should disable the execution of the jshint-maven-plugin during an eclipse build. Paste the following snippet into the pluginManagement section of your pom.xml

<plugin><groupId>org.eclipse.m2e</groupId><artifactId>lifecycle-mapping</artifactId><version>1.0.0</version><configuration>  <lifecycleMappingMetadata>   <pluginExecutions>    <pluginExecution>     <pluginExecutionFilter>      <groupId>com.cj.jshintmojo</groupId>      <artifactId>jshint-maven-plugin</artifactId>      <versionRange>[1.3,)</versionRange>      <goals>       <goal>lint</goal>      </goals>     </pluginExecutionFilter>     <action>      <ignore />     </action>    </pluginExecution>   </pluginExecutions>  </lifecycleMappingMetadata></configuration></plugin>

Interpreting JSHint Output

 

If you're unsure how to interpret JSHint's output, this might be a good resource for you: JSLint Error Explanations - Making Your Feelings Better

Conclusion


In this article, I described how you can use a combination of JSHint, the JSHint eclipse plugin, and jshint-maven-plugin

  • to have live static code checks in eclipse while you write JavaScript code
  • to have your build fail when someone tries to commit code that JSHint doesn't like

 

Now it's your turn: Write some clean code!

 

This article is part of a series of articles about Test-Driven Development and JavaScript in which also the second topic will be covered in depth. Press 'like' on the overview blog post to stay tuned and get updates about more topics around software engineering with SAPUI5 and JavaScript!


Your Fiori launchpage is not limited to SAP Standard

$
0
0

Lately, I've been messing about quite a lot with SAPUI5, NetWeaver Gateway and the SAP Fiori Suite. I haven't had much time to write any of it down, seeing as I've recently taken up a new role and I'm not yet used to all aspects. But as I'm waiting for a customer's BW system to finish a couple of loads, I find myself with some free time on my hands to note down some of my findings.

 

Fiori Perception

Part of my new role includes presales. I spend quite some time with customers explaining the new UI strategy of SAP. Internally, I also do a little bit of coaching and knowledge sharing. There as well, a lot of colleagues have questions about Fiori and what it can mean to them. Both functionally and technically. One of the remarks that keeps coming back is: "Which applications are available? Oh, but those don't fit all our needs."

 

Often times, customers have quite some WebDynpro Applications, SAPGui screens and custom workflows in their system. Obviously, SAP is not going to foresee Fiori applications to replace your own custom code. So many customers and colleagues think that Fiori is not the right fit for them.

 

It's not just a suite

Fiori is the name for the SAP Standard suite, which includes the launchpage. But all the technologies used are at your disposal to make something out of it. There are tons of funky stuff you can do.

  • Copy a standard Fiori application and change it to your needs (beware, no updates)
  • Enhance an existing/standard Fiori application for minor changes
  • Create your own custom Fiori application (it sounds more daunting than it is)
  • Add new tiles to the launchpage which refer to
    • (custom) Fiori applications
    • WebDynpro screens
    • Screen-persona's (webgui url)
    • the web version of the business client
    • Internet pagesfiori role.png

 

It's an opportunity

When talking about creating your own launchpages, you actually have a great opportunity to rethink the roles you're assigning to people. The standard Fiori Launchpage requires a role, in which the first level contains an authorization to a certain Tile Catalog, which in turn contains the applications for that catalog.

So the role refers to one, or more catalogs (important, the catalog entry must be on the root level of the role, not in a subfolder). The catalog contains one or multiple groups. Every group can contain one, or multiple Tiles. 1 tile maps to one URL, or Application.

In the very same role you can also include the authorization objects required on SAP side for the functional execution. (PO Creation, Company code authorization etc..)

 

Clearly, this is a very different way of creating roles, as opposed to transactions.

 

Your own tiles

So you may want to create your own tiles, which you can include on custom Launchpages. The first thing to do is launch your Fiori URL, and replace the "Home.html" by "admin/admin.html". There, you can create new catalogs, groups and tiles.

fiori catalogs.png

Every tile requires a URL, or an object based navigation towards its application. No-one ever claimed that it has to be a Fiori applicaiton. It could just as well be a WebDynpro, a third party web-app, a WebGui url, a BSP page...

(PS: all Fiori apps are stored on the backend as BSP applications.)

(PPS: I'm hoping that the next version of Abap In Eclipse will have support to edit BSP views and mimes directly, So  don't have to up and download all the time)

 

When you've gone through the entire process, you'll end up with some extra tiles on your home screen. In this example, I've added a tile towards my own custom Fiori application, called "myHome" (an app for Real Estate):

fiori launchpage.png

Custom Fiori apps

Lots of customers will look at the standard Fiori apps and say: "Well, we can't use that, because we do it differently"

Have no fear. The standard apps in the Fiori suite are the basic versions. They'll do what they promise, but nothing is stopping you from enhancing and extending it to suit your exact needs.

 

You can even go as far as to create a fully functioning custom Fiori application. They can even be quite extensive.

custom-fiori.png

Theming

SAP is quite proud of their Theme Designer, but to this date, I haven't actually succeeded in adapting a theme properly, and publishing it back to our ERP backend. I find it much easier to foresee my own CSS file (small) which overrides some of the standard theme settings, and refer to that CSS file from the index.html.

 

There's a nice little trick in CSS. If you add the notion !important to a line in CSS, it will have priority over all other possible settings. Comes in handy.

 

 

Aww, I notice the BW system has finally finished loading, so I'll keep it at this for now and maybe next time, I'll let you have a look under the hood.

Neptune and test program in SAP

$
0
0

Hello all,

 

In this blog I'll explain what Neptune is and a little program as example

 

 

Neptune is a development environment by Neptune software. It provides the most efficient and secure way to make any SAP functionality seamlessy available in user friendly interfaces on phone, tablet and desktop. It's the only solution on the market that directly leverages SAP's own source code ABAP, calles Neptune Application Designer.

With this solution, a program can be used on thousands of end users, while maintaining the highest security requirements.

 

Before you can use Neptune in SAP, you first need to install the software into your Netweaver system.Then with the transaction '/O/NEPTUNE/Designer' you can start the layout. You can easily create the layout to drag & drop the components you want.


Some possibilities & information:

  • Creating a mobile or a desktop application
  • You can choose a library (SAPUI5, WIJMO, jQuery, jQuery & Wijmo and Custom).
  • JavaScript and jQuery can be used as an action for a component (when clicked on a button, ... ).
  • To change the layout, you can use CSS.
  • ABAP code can be used as backend code (to get data from tables and show them) with ajax.




Example of a desktop Neptune application.

 

The application show twoo rows, one to give carrid, and one to show an internal table in a html table. When the application runs, all the values from SFLIGHT are showed in tha table, and all the different carrids are showed in a dropdown. The table changed, if you select another carrid from the dropdown.

 

 

First, create a application  in transaction '/O/NEPTUNE/Designer'. Fill in the title, description and class (if you are going to use ABAP code).

overview.PNG

 

Select library for the application:

overview2.PNG

 

 

After thesetting, development can be started (in Designer).

design.PNG

 

 

This is my design, it's based on matrix layout with twoo rows (one for selecting the carrid and one to show the internal table). Each column of the table is binded to a field from the internal table (in the textfield). If we run this, the table and dropdown are empty. So now they must be filled.

 

 

To fill the dropdown with all the different carrids, in the class (that is filled in the settings), there must be an internal table in the attributes. This internal table must be filled through a method.

 

The table changed when a button is clicked, to run javascript code on this button.

button.PNG

 

A method in the class is called through the ajax id.

 

method /NEPTUNE/IF_NAD_SERVER~HANDLE_ON_AJAX.   CASE ajax_id.     WHEN 'GET_ALL'.       call METHOD get_sflight                     EXPORTING im_ajax = ajax_value.     WHEN 'GET_CARRID'.       CALL METHOD get_carrid.     WHEN 'GET_CONNID'.       CALL METHOD get_connid.   ENDCASE.
endmethod.


When the ajax id is 'GET_ALL', the method 'GET_SFLIGHT' is called. When a carrid is selected, values are selected for that carrid.


method GET_SFLIGHT.   IF im_ajax is NOT INITIAL.     z_carr = im_ajax .     SELECT *       INTO TABLE ZIT_SFLIGHT       FROM sflight       WHERE carrid eq z_carr       ORDER BY connid ASCENDING.   ELSE.     SELECT *     INTO TABLE ZIT_SFLIGHT     FROM sflight.   ENDIF.
endmethod.


The ajax id is set in the general settings of the table, also like the model source.

table.PNG


When ajax id is 'GET_CARRID', the method 'GET_CARRID' is called (to show all the different carrids in the dropdown).


method GET_CARRID.   SELECT DISTINCT carrid     INTO CORRESPONDING FIELDS OF TABLE  ZIT_carrid     FROM sflight.
endmethod.


The ajax id is filled in the general settings of the dropdown, also like the model source (what you wanted to set down in de component) and the value and label field.


dropdown.PNG



Output:

run1.PNG

 

run1.PNG



Kind regards,

Pieter Lemaire

Full table search and sort at Client-side in OpenUI5 with UnderscoreJS

$
0
0

Hi all,

 

In this blog, I'll talk about OpenUI5, OData services and data manipulation with UnderscoreJS.

 

Server-side data manipulation

When you are using OData services while working with OpenUI5, you will notice that OpenUI5 will send multiple requests to your OData service. It will send a request when you want to sort your data, it will send a request when you search through your data and so on... . It will send a request for almost every action on your data. This is good when your services are fast enough to handle all the requests and you'll have to write less Javascript.

 

Why not client-side?

But why not sorting and searching through your data at client side? Manipulating your data at client side will reduce your requests to your backend, it will reduce logic in your backend and most devices will be able to handle this! Just be careful when working with lots amount of data.

 

Javascript vs ABAP?

Okey, I agree, when you've always worked in ABAP, ABAP will be much easier. But Javascript has, besides OpenUI5, many different libraries which you can use with OpenUI5. These libraries can make Javascript much easier, even easier than ABAP ! (maybe a little optimistic ) One of the many libraries that I prefer for data manipulation at client-side is UnderscoreJS.

 

UnderscoreJS

Underscore is a JavaScript library that provides a whole mess of useful functional programming helpers without extending any built-in objects. It’s the answer to the question: “If I sit down in front of a blank HTML page, and want to start being productive immediately, what do I need?” … and the tie to go along with jQuery's tux andBackbone's suspenders.

Underscore provides 80-odd functions that support both the usual functional suspects:map, select, invoke— as well as more specialized helpers: function binding, javascript templating, deep equality testing, and so on. It delegates to built-in functions, if present, so modern browsers will use the native implementations of forEach, map,reduce, filter, every, some and indexOf.

Basically UnderscoreJS provides multiple Javascript helper functions. With UnderscoreJS your code will look more understandable and you will be able to do more with less code.

For more information about UnderscoreJS:

 

http://underscorejs.org/

 

Basic Example

 

Create an basic SAPUI5 Application with one view

Download UnderscoreJS and add it to your project

underscore.png

Include the underscorejs library to your index.html

loadunderscore.png

In this example I'm going to work with a public OData service:

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

 

More specifically the collection Customers.

http://services.odata.org/Northwind/Northwind.svc/Customers

 

Design the view

In our view, I just add a table with the following parts

  • Toolbar
    • Button to count the rows: "Count rows"
    • Button to sort the table by country: "Sort by Country"
    • Textifeld to search over the full table
  • 6 Columns
    • CustomerID
    • CompanyName
    • ContactName
    • ContactTitle
    • Country
    • City

This table is connected to the model "WorkModel".

createContent : function(oController) {      var oTable = new sap.ui.table.Table({            title: "Table Example",            visibleRowCount: 7,            firstVisibleRow: 3,            selectionMode: sap.ui.table.SelectionMode.Single,            toolbar: new sap.ui.commons.Toolbar({items: [                new sap.ui.commons.Button({text: "Count rows", press: oController.getCount}),                new sap.ui.commons.Button({text: "Sort Country", press: oController.sortByCountry}),                new sap.ui.commons.TextField({id:"search",liveChange:oController.find})            ]})      });      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "CustomerID"}),            template: new sap.ui.commons.TextView({text:"{WorkModel>CustomerID}"})      }));      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "CompanyName"}),            template: new sap.ui.commons.TextView({text: "{WorkModel>CompanyName}"})      }));      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "ContactName"}),            template: new sap.ui.commons.TextView({text:"{WorkModel>ContactName}"})      }));      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "ContactTitle"}),            template: new sap.ui.commons.TextView({text:"{WorkModel>ContactTitle}"})      }));      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "Country"}),            template: new sap.ui.commons.TextView({text:"{WorkModel>Country}"})      }));      oTable.addColumn(new sap.ui.table.Column({            label: new sap.ui.commons.Label({text: "City"}),            template: new sap.ui.commons.TextView({text:"{WorkModel>City}"})      }));      oTable.bindRows("WorkModel>/");      return oTable;  }

 

Controller of the view

In the controller I'm going to use UnderscoreJS for counting, sorting and for searching.

 

In the init of the controller I will do the following:

  1. Create OData model by using the url of the service
  2. Create two empty JSON models
    1. One to have always the original list, so I can always search on the full data ("OriginalModel")
    2. A second one for the view, which I will use for the sort, count and to show the result of the search ("WorkModel")
  3. Read the "/Customers" from the OData model
    1. Put the result in the JSON model for the original list ("OriginalModel")
    2. Sort the result
    3. Put the sorted result in the second JSON model for the view ("WorkModel")

The JSON models are required for client-side data manipulation. With the OData model we cannot change the data without sending a request to the backend because of the bindings.

 

onInit: function() {      var sServiceUrl ="http://services.odata.org/Northwind/Northwind.svc";        var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl);      var oModelJson = new sap.ui.model.json.JSONModel();      var OriginalModel = new sap.ui.model.json.JSONModel();      oModel.read("/Customers", null, null, null, function(data, oResponse){            OriginalModel.setData(data.results);            sap.ui.getCore().setModel(OriginalModel, "OriginalModel");            var data = _.sortBy(data.results,function(value){                return value.name;            });            oModelJson.setData(data);            sap.ui.getCore().setModel(oModelJson, "WorkModel");      }, null );  }

With UnderscoreJS we can easily do a count on the JSON model which is used in the view ("WorkedModel")

 

getCount: function(){      var model = sap.ui.getCore().getModel("WorkModel");      var count = _.countBy(model.getData(), function(value) {            return 'all';      });      alert(count.all);  },

Also for the sort I'm using an UnderscoreJS function.

  1. Get the "WorkModel"
  2. Change the data using UnderscoreJS
  3. Set the "WorkModel" with the new data

 

sortByCountry: function(){      var model = sap.ui.getCore().getModel("WorkModel");      var data = _.sortBy(model.getData(),function(value){            return value.Country;      });      model.setData(data);      sap.ui.getCore().setModel(model,"WorkModel");  }

Full Table search

In this case we start from the "OriginalModel" to search over all records. Otherwise the seconde search will be incorrect.

 

For the search I will use mutliple UnderscoreJS functions.

I start with using the filter function to get only the records that meet the search term.

To find out which records that meet the searchterm, I use some other UnderscoreJS function in the filter function.

  • I use a combination of chain, map, properties and filter for concatenating all field values as one string seperated by spaces.

 

var fields = [      'CompanyName',      'CustomerID',      'ContactName',      'ContactTitle',      'Country',      'City'  ];  var concat = _.chain(fields)                          .map(function(field) { return _.property(field)(item); })                          .filter(function(result) { return result !== undefined && result !== null })                          .value()                          .join(' ');

 

  • After that I loop over all the different words in the searchterm and return every record that contains all the searchterms.

 

return _.every(search.split(' '), function(searchTerm) {  return concat.indexOf(searchTerm) >= 0;
});

Full code will look like this. I filter on the "OriginalModel" and set the "WorkModel"

 

find: function(oEvent){      var search = oEvent.getParameter("liveValue");      var model = sap.ui.getCore().getModel("OriginalModel");      var FilteredData = _.filter(model.getData(),function(item){            try{                var fields = [                      'CompanyName',                      'CustomerID',                      'ContactName',                      'ContactTitle',                      'Country',                      'City'                  ];                var concat = _.chain(fields)                                          .map(function(field) { return _.property(field)(item); })                                          .filter(function(result) { return result !== undefined && result !== null })                                          .value()                                          .join(' ');                return _.every(search.split(' '), function(searchTerm) {                      return concat.indexOf(searchTerm) >= 0;                    });            } catch(e) {                throw e;            }      });      var oModelJson = new sap.ui.model.json.JSONModel();      oModelJson.setData(FilteredData);      sap.ui.getCore().setModel(oModelJson,"WorkModel");
}

 

Result

Table with the originial data of the OData service

fulltable.png

Sorted on country

sort.png

Full table search  ( Country and ContactTitle )

search.png

Count

count.png

Testing

For testing, I've started chrome with:  --disable-web-security

chrome.png

Conclusion

This is one of the advantages of Javascript. It gives you freedom to use other libraries and frameworks. I think this is a great example of other libraries in combination with OpenUI5. But there are a lot more libraries and frameworks! With Javascript almost everything is possible!

 

You can find the full project on github: https://github.com/lemaiwo/OpenUI5-and-UnderscoreJS

 

I've also added the index and the view to the attachments

 

Kind regards,

Wouter

SAPUI5 Dialog(with BusinessCard) As XML Fragment along With Controller

$
0
0

Note: This blog is in regard of XML View and XML Fragment(for a Dialog control with BusinessCard as aggregation)


Problem :

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

 

Fragments:

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

 

Create A Fragment for a Dialog control:


save following fragmet as "myFragment.fragment.xml"

(in my case i had store this in 'view' folder)

 

<Dialog      xmlns= "sap.ui.commons" xmlns:b="sap.suite.ui.commons" xmlns:m="sap.m" stretch="true" showHeader="true" >  <buttons>      <Button id="btnInFragment" text="Close" press="doSomething"/>  </buttons>  <content>      <b:BusinessCard id="businessCard" secondTitle="Associate Consultant" iconPath="images/aa.jpg">  <b:content>  <m:VBox>  <m:items>      <m:Text id="txtJobTitle" text=""></m:Text>      <m:Text id="txtEmail" ></m:Text>      <m:Text id="txtPhone" text="(+91)-12345676544"></m:Text>  </m:items>  </m:VBox>  </b:content>  <b:firstTitle>      <m:Text id="txtFirstTitle" text="David Beckham"></m:Text>  </b:firstTitle>  </b:BusinessCard>  </content></Dialog>

 

Instantiate The Fragment & Open Fragment Dialog:

 

var oDialogFragment = sap.ui.xmlfragment("view.myFragment",this.getView().getController());
oDialogFragment.open();

Explanation:

We can provide control methods to the fragment control.For this we need to give the instance of the view which instantiating the fragment. This is acheived with following:

"this.getView().getController()"

 

Accessing Fragmet UI Controls Using IDs:

We can access the controls created in Fragment by their IDs as follows and implement their methods:

 

sap.ui.getCore().byId("txtFirstTitle").setText("Name Surname");
sap.ui.getCore().byId("txtJobTitle").setText("Consultant");

 

We can reuse the Fragment UI any time any where now.

Hope this will help in your Work.

 

Regards,

Rauf

How To Guide: SAPUI5 & Netweaver Gateway CodeJam Antwerp

$
0
0

This Guide explains how to build a simple SAPUI5 application, as it was shown in the CodeJam at Antwerp on Feb 20th 2014.

 

 

Creating the SAPUI5 Application

 

  1. Create a new SAPUI5 project by right clicking in the "Project Explorer" and selecting "New" --> "Project..."
    17-02-2014 08-12-35.png
  2. In the New Project Dialog select "Application Project" in the "SAPUI5 Application Development" folder.
    17-02-2014 08-13-53.png
  3. Name the project, select "Mobile" as "Target Device" and check "Create an Initial View". Then click on "Next >"
    17-02-2014 08-15-35.png
  4. Create the initial view. In our example we name it "App". We choose "XML" as "Development Paradigm". Then click on "Finish"
    17-02-2014 08-18-14.png
  5. Let's have a short look at our applications file structure. There are three important files. The "index.html" which is the HTML page which displays the application. An "App.view.xml" which is an XML file which describes the view and the "App.controller.js" which implements the views logic.
    17-02-2014 08-22-02.png
  6. To test your application you can always right click on the project and select: "Run As" --> "Web App Preview"

 

 

App View

 

The App view should contain a split app, which contains a list on the left hand side (to display the products) and a navigation container on the right hand sind (to display details). Therefore we edit the index.html and App.view.xml as shown below.

 

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"  data-sap-ui-theme="sap_bluecrystal">  </script>  <script>  //Define subfolder which includes the applications files  sap.ui.localResources("codejamapplication");  //Instantiate the view  var app = sap.ui.view({id:"productsApp", viewName:"codejamapplication.App", type:sap.ui.core.mvc.ViewType.XML});  // to avoid scrollbars on desktop the root view must be set to block display  app.setDisplayBlock(true);  app.placeAt("content");  </script>  </head>  <body class="sapUiBody" role="application">  <div id="content"></div>  </body></html>

App.view.xml

 

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"  xmlns="sap.m" controllerName="codejamapplication.App" xmlns:html="http://www.w3.org/1999/xhtml">  <Shell title="Product Explorer">       <SplitApp>            <masterPages>                 <Page title="Products">                      <List></List>                 </Page>            </masterPages>            <detailPages>                 <NavContainer id="navContainer"></NavContainer>            </detailPages>       </SplitApp>  </Shell></core:View>

Routing

 

To enable routing within the application you need to create an application router. We place this in the javascript section of the index.html file (the same <script> section, in which the view is initialized. In this router we define two routes for the product details and the supplier details. Additionally we define a configuration object which sets default values for all routes. To automate the navigation in the nav container we use the RouteMatchedHandler.

 

jQuery.sap.require("sap.ui.core.routing.Router");
jQuery.sap.require("sap.m.routing.RouteMatchedHandler");
var oRouter = new sap.ui.core.routing.Router({     product: {          pattern: "product/{id}",          view: "Product",  },  supplier: {  pattern: "supplier/{id}",  view: "Supplier"  }  }, {  targetControl: "navContainer",  targetAggregation: "pages",  targetParent: "productsApp",  viewType: "XML",  viewPath: "codejamapplication",  clearTarget: false  });  var oRouteHandler = new sap.m.routing.RouteMatchedHandler(oRouter);  oRouter.register("router");
oRouter.initialize();

The oRouter.initialize() should be done after the application view has been placed on the screen (app.placeAt("content")) All the other code needs to be executed before the app view is initialized.

Model

 

To connect your application to the backend, you have to define a Model. We do this in the index.html file:

 

var oModel = new sap.ui.model.odata.ODataModel("http://54.224.71.58:50000/sap/opu/odata/sap/ZGWSAMPLE_SRV");  sap.ui.getCore().setModel(oModel);

This definition should be placed before the lines where the application view is instantiated.

 

Service URLs need to have the same host as the application. Else the requests are blocked by the browser for security reasons. To overcome this you can use the SAPUI5 proxy servlet, which is enabled by default for all SAPUI5 Application projects. You can write the url like

 

new sap.ui.model.odata.ODataModel("proxy/http/54.224.71.58:50000/sap/opu/odata/sap/ZGWSAMPLE_SRV");

 

Products and Supplier View

 

To display the details we defined two routes for which we need to define the views.

 

To use all the bindings which are define din this view, you have to enable the extended binding syntax. This can be done by adding "data-sap-ui-xx-bindingSyntax="complex" " to the bootstrap script tag.

 

 

Supplier.view.xml

 

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"  xmlns="sap.m" controllerName="codejamapplication.Supplier" xmlns:html="http://www.w3.org/1999/xhtml">  <Page title="{CompanyName}" showNavButton="true" navButtonPress="handleNavBack">  <content>  <ObjectHeader title="{CompanyName}" number="Phone: {PhoneNumber}"  numberUnit="{EmailAddress}">  <attributes>  <ObjectAttribute text="{Description}" />  <ObjectAttribute text="{Category}" />  </attributes>  </ObjectHeader>  </content>  </Page></core:View>

Product.view.xml

 

<core:View xmlns:core="sap.ui.core" xmlns:form="sap.ui.layout.Form"  xmlns="sap.m" controllerName="codejamapplication.Product" xmlns:html="http://www.w3.org/1999/xhtml">  <Page title="{Name}">  <content>  <ObjectHeader title="{ProductId}" number="{Price}"  numberUnit="{CurrencyCode}">  <attributes>  <ObjectAttribute text="{Description}" />  <ObjectAttribute text="Category: {Category}" />  <ObjectAttribute text="Supplier: {SupplierName}" press="showSupplier" active="true"></ObjectAttribute>  </attributes>  </ObjectHeader>  </content>  </Page></core:View>

In this coding you also see the data binding syntax. You can write the entities properties in curly braces. You can also define complex binding structures like mixing strings and bindings. To enable this, you have to add an additional attribute to the bootstrap in the index.html file.

 

We also still miss the databinding in the App.view.xml which is shown below.

 

<core:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"  xmlns="sap.m" controllerName="codejamapplication.App" xmlns:html="http://www.w3.org/1999/xhtml">  <Shell title="Product Explorer">  <SplitApp>  <masterPages>  <Page title="Products">  <List items="{/ProductCollection}">  <items>  <StandardListItem title="{Name}" description="{Description}" type="Active" press="selectProduct"></StandardListItem>  </items>  </List>  </Page>  </masterPages>  <detailPages>  <NavContainer id="navContainer"></NavContainer>  </detailPages>  </SplitApp>  </Shell></core:View>

We have now created all the views, that we need for our application. We still miss the logic.

 

Controllers

 

To logic of the application in imiplemented in the controllers. Here we handle the navigation and data binding.

 

App.controller.js

 

sap.ui.controller("codejamapplication.App", {  onInit: function() {  this.oRouter = sap.ui.core.routing.Router.getRouter("router");  },  selectProduct: function(oEvent) {  var oBindingContext = oEvent.getSource().getBindingContext();  this.oRouter.navTo("product", { id: oBindingContext.getProperty("ProductId") });  }
});

Product.controller.js

 

sap.ui.controller("codejamapplication.Product", {  onInit: function() {  this.oRouter = sap.ui.core.routing.Router.getRouter("router");  this.oRouter.attachRouteMatched(function(oEvent) {  var sRoute = oEvent.getParameter("name"),  oView = oEvent.getParameter("view");  if (sRoute === "product") {  oView.setBusyIndicatorDelay(0);  oView.setBusy(true);  sap.ui.getCore().getModel().createBindingContext("/ProductCollection('" + oEvent.getParameter('arguments').id + "')", function(oContext) {  oView.setBindingContext(oContext);  oView.setBusy(false);  });  }  });  },  showSupplier: function(oEvent) {  var oBindingContext = oEvent.getSource().getBindingContext();  this.oRouter.navTo("supplier", { id: oBindingContext.getProperty("SupplierId") });  }
});

Supplier.controller.js

 

sap.ui.controller("codejamapplication.Supplier", {  onInit: function() {  this.oRouter = sap.ui.core.routing.Router.getRouter("router");  this.oRouter.attachRouteMatched(function(oEvent) {  var sRoute = oEvent.getParameter("name"),  oView = oEvent.getParameter("view");  if (sRoute === "supplier") {  oView.setBusyIndicatorDelay(0);  oView.setBusy(true);  sap.ui.getCore().getModel().createBindingContext("/BusinessPartnerCollection('" + oEvent.getParameter('arguments').id + "')", function(oContext) {  oView.setBindingContext(oContext);  oView.setBusy(false);  });  }  });  },  handleNavBack: function() {  var oHistory = sap.ui.core.routing.History.getInstance();  if (oHistory.getPreviousHash()) {  window.history.go(-1);  }  }
});

Reduce / Minimize SAPUI5 JS code with YUI Compressor

$
0
0

Motivation

 

In production environments, mobile devices, etc. reduce size of our JS code is a must in order get a better usability, lower wait time when there is a poor bandwidth.

 

Another reason which we need to reduce code is to "protect" non free code (for example a private B2C, B2E, B2B portal).

A good example could be YUI Compressor. This tool, developed by Yahoo Team, reduces / compresses JS code:


YUI Compressor

 

 

Step by step

 

1. Download YUI Compressor tool fromYUI Compressor

 

2. Use YUI on console. In this example (JS Bin - Collaborative JavaScript Debugging) we reduce this JS example:


Open a console and execute this command (-v in order to see WARNINGs or ERRORs, -o is the output file parameter)

 

java -jar yuicompressor-2.4.8.jar -v myview.view.js -o myview.view-min.js

yuimin0.png

 

This is the original code:

 

 

sap.ui.jsfragment("fragment.Table", {  createContent : function(oController) {      //Obtain data from controller    var aData = oController.fragmentInitData.data;      //Create an instance of the table control    var oTable = new sap.ui.table.Table( {      title : oController.fragmentInitData.title, //Obtain title from controller      visibleRowCount : 7    });      //Obtain column definition from controller    for ( var i = 0; i < oController.fragmentInitData.columns.length; i++) {      var template;          //Define the columns and the control templates to be used      if (oController.fragmentInitData.columns[i].type == "Text")        template = new sap.ui.commons.TextView()        .bindProperty(          "text",          oController.fragmentInitData.columns[i].bindingPath);      else if (oController.fragmentInitData.columns[i].type == "Rating")        template = new sap.ui.commons.RatingIndicator()        .bindProperty(          "value",          oController.fragmentInitData.columns[i].bindingPath);      else if (oController.fragmentInitData.columns[i].type == "Checkbox")        template = new sap.ui.commons.CheckBox()        .bindProperty(          "checked",          oController.fragmentInitData.columns[i].bindingPath);          if (template !== undefined) {        oTable        .addColumn(new sap.ui.table.Column(          {            label : new sap.ui.commons.Label(              {                text : oController.fragmentInitData.columns[i].title              }),            template : template,            sortProperty : oController.fragmentInitData.columns[i].bindingPath,            filterProperty : oController.fragmentInitData.columns[i].bindingPath,            width : "200px"          }));      }    }      var oModel = new sap.ui.model.json.JSONModel();    oModel.setData( {      modelData : aData    });      oTable.setModel(oModel);    oTable.bindRows("/modelData");      //Initially sort the table    oTable.sort(oTable.getColumns()[0]);      //Bring the table onto the UI    return oTable;  }
});
sap.ui.controller("view.FragmentsExample", {});
sap.ui.jsview("view.FragmentsExample", {  /** Specifies the Controller belonging to this View.  * In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.  * @memberOf view.FragmentsExample  */  getControllerName : function() {    return "view.FragmentsExample";  },  /** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.  * Since the Controller is given to this method, its event handlers can be attached right away.  * @memberOf view.FragmentsExample  */  createContent : function(oController) {      //Define some sample data    var aData = createSampleData();      //Define fragment init data    oController.fragmentInitData = {      title : "This is a Table Fragment Example",      data : aData,      columns : [ {        title : 'Last Name',        bindingPath : 'lastName',        type : "Text"      }, {        title : 'Name',        bindingPath : 'lastName',        type : "Text"      }, {        title : 'Selected',        bindingPath : 'checked',        type : "Checkbox"      }, {        title : 'Rating',        bindingPath : 'rating',        type : "Rating"      } ]    };      //Instantiate fragment.Table with this init data "oController.fragmentInitData"    var table1 = sap.ui.jsfragment("fragment.Table", oController);      //Define some sample data again    var aData2 = createSampleData();      //Define fragment init data. Different init data this time (different title and less columns).    oController.fragmentInitData = {      title : "This is a Table Fragment Example 2",      data : aData,      columns : [ {        title : 'Last Name',        bindingPath : 'lastName',        type : "Text"      }, {        title : 'Name',        bindingPath : 'lastName',        type : "Text"      } ]    };      //Instantiate fragment.Table with this init data "oController.fragmentInitData"    var table2 = sap.ui.jsfragment("fragment.Table", oController);      var oDivider1 = new sap.ui.commons.HorizontalDivider("divider1");    oDivider1.setHeight(sap.ui.commons.HorizontalDividerHeight.Large);      //Present data into VerticalLayout    var oLayout = new sap.ui.layout.VerticalLayout( {      content : [ table1, oDivider1, table2 ]    });      return oLayout;  }
});
/**  * Returns some sample data  */
function createSampleData() {  return [ {    lastName : "Dente",    name : "Al",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 4  }, {    lastName : "Friese",    name : "Andy",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person2.gif",    gender : "male",    rating : 2  }, {    lastName : "Mann",    name : "Anita",    checked : false,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 3  }, {    lastName : "Schutt",    name : "Doris",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 4  }, {    lastName : "Open",    name : "Doris",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 2  }, {    lastName : "Dewit",    name : "Kenya",    checked : false,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 3  }, {    lastName : "Zar",    name : "Lou",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 1  }, {    lastName : "Burr",    name : "Tim",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person2.gif",    gender : "male",    rating : 2  }, {    lastName : "Hughes",    name : "Tish",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 5  }, {    lastName : "Lester",    name : "Mo",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 3  }, {    lastName : "Case",    name : "Justin",    checked : false,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 3  }, {    lastName : "Time",    name : "Justin",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 4  }, {    lastName : "Barr",    name : "Gaye",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 2  }, {    lastName : "Poole",    name : "Gene",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person2.gif",    gender : "male",    rating : 1  }, {    lastName : "Ander",    name : "Corey",    checked : false,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 5  }, {    lastName : "Early",    name : "Brighton",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 3  }, {    lastName : "Noring",    name : "Constance",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 4  }, {    lastName : "Haas",    name : "Jack",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "male",    rating : 2  }, {    lastName : "Tress",    name : "Matt",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person2.gif",    gender : "male",    rating : 4  }, {    lastName : "Turner",    name : "Paige",    checked : true,    linkText : "www.sap.com",    href : "http://www.sap.com",    src : "images/person1.gif",    gender : "female",    rating : 3  } ];
}
var view = sap.ui.view( {  id : "FragmentsExample",  viewName : "view.FragmentsExample",  type : sap.ui.core.mvc.ViewType.JS
});
view.placeAt("content");

 

3. A minimized file is created (we can see how size is reduced from 9k to 5k, WoW):

 

yuimin.png

 

JS Bin - Collaborative JavaScript Debugging

 

 

sap.ui.jsfragment("fragment.Table",{createContent:function(c){var b=c.fragmentInitData.data;var a=new sap.ui.table.Table({title:c.fragmentInitData.title,visibleRowCount:7});for(var d=0;d<c.fragmentInitData.columns.length;d++){var e;if(c.fragmentInitData.columns[d].type=="Text"){e=new sap.ui.commons.TextView().bindProperty("text",c.fragmentInitData.columns[d].bindingPath)}else{if(c.fragmentInitData.columns[d].type=="Rating"){e=new sap.ui.commons.RatingIndicator().bindProperty("value",c.fragmentInitData.columns[d].bindingPath)}else{if(c.fragmentInitData.columns[d].type=="Checkbox"){e=new sap.ui.commons.CheckBox().bindProperty("checked",c.fragmentInitData.columns[d].bindingPath)}}}if(e!==undefined){a.addColumn(new sap.ui.table.Column({label:new sap.ui.commons.Label({text:c.fragmentInitData.columns[d].title}),template:e,sortProperty:c.fragmentInitData.columns[d].bindingPath,filterProperty:c.fragmentInitData.columns[d].bindingPath,width:"200px"}))}}var f=new sap.ui.model.json.JSONModel();f.setData({modelData:b});a.setModel(f);a.bindRows("/modelData");a.sort(a.getColumns()[0]);return a}});sap.ui.controller("view.FragmentsExample",{});sap.ui.jsview("view.FragmentsExample",{getControllerName:function(){return"view.FragmentsExample"},createContent:function(c){var b=createSampleData();c.fragmentInitData={title:"This is a Table Fragment Example",data:b,columns:[{title:"Last Name",bindingPath:"lastName",type:"Text"},{title:"Name",bindingPath:"lastName",type:"Text"},{title:"Selected",bindingPath:"checked",type:"Checkbox"},{title:"Rating",bindingPath:"rating",type:"Rating"}]};var d=sap.ui.jsfragment("fragment.Table",c);var g=createSampleData();c.fragmentInitData={title:"This is a Table Fragment Example 2",data:b,columns:[{title:"Last Name",bindingPath:"lastName",type:"Text"},{title:"Name",bindingPath:"lastName",type:"Text"}]};var a=sap.ui.jsfragment("fragment.Table",c);var e=new sap.ui.commons.HorizontalDivider("divider1");e.setHeight(sap.ui.commons.HorizontalDividerHeight.Large);var f=new sap.ui.layout.VerticalLayout({content:[d,e,a]});return f}});function createSampleData(){return[{lastName:"Dente",name:"Al",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:4},{lastName:"Friese",name:"Andy",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person2.gif",gender:"male",rating:2},{lastName:"Mann",name:"Anita",checked:false,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:3},{lastName:"Schutt",name:"Doris",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:4},{lastName:"Open",name:"Doris",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:2},{lastName:"Dewit",name:"Kenya",checked:false,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:3},{lastName:"Zar",name:"Lou",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:1},{lastName:"Burr",name:"Tim",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person2.gif",gender:"male",rating:2},{lastName:"Hughes",name:"Tish",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:5},{lastName:"Lester",name:"Mo",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:3},{lastName:"Case",name:"Justin",checked:false,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:3},{lastName:"Time",name:"Justin",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:4},{lastName:"Barr",name:"Gaye",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:2},{lastName:"Poole",name:"Gene",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person2.gif",gender:"male",rating:1},{lastName:"Ander",name:"Corey",checked:false,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:5},{lastName:"Early",name:"Brighton",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:3},{lastName:"Noring",name:"Constance",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:4},{lastName:"Haas",name:"Jack",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"male",rating:2},{lastName:"Tress",name:"Matt",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person2.gif",gender:"male",rating:4},{lastName:"Turner",name:"Paige",checked:true,linkText:"www.sap.com",href:"http://www.sap.com",src:"images/person1.gif",gender:"female",rating:3}]}var view=sap.ui.view({id:"FragmentsExample",viewName:"view.FragmentsExample",type:sap.ui.core.mvc.ViewType.JS});view.placeAt("content");

 

 

4. Let's use new minimized file:

 

yuimin2.png

 

 

 

 

Enjoy!

Cheers

ABAP Icon Explorer - SAPUI5 application

$
0
0

In sapui5 application, we can use various icons to beautify its look and feel. On SAPUI5 demokit, you can find Icon Explorer which has around 500+ icons which you can use in your application. you can also see various icons at SAPUI5 SDK - Demo Kit

 

There was blog on ABAP Icon Library by Patrick Wenger where it is mentioned that

Dealing with web frontends, the need of a consistant icon library is crucial. Of course you can use the icons of the SAPUI5 library. But besides this, every SAP ABAP stack also hosts an nice icon library. You can use the following url to have a look at the icons:

 

http://[HOST][PORT]/sap/bc/bsp/sap/it00/mime_sap_icons.htm

 

So I was thinking can we have sapui5 application which will show all icons from SAP NW AS ABAP? Apart from icons from  Icon Explorer if someone is interested to display icons from backed system, there should be some application which will provide those icons. These icons will be best suitable for desktop based ui5 application. Users will be familiar with these icons as those are being used in almost all SAP transactions!

 

for example, see these buttons with some backend icons!

abap_icon.jpg

Source at ABAP Icons on Buttons

 

In this blog, I will provide demo of an ABAP Icon explorer UI5 application which will display various icons from ABAP Application server.

 

first I created simple function module to capture icon data as below,

 

FUNCTION z_test_mime_list.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  EXPORTING
*"     REFERENCE(MIME_TAB) TYPE  ZMIME_T
*"----------------------------------------------------------------------   DATA: icon_tab TYPE STANDARD TABLE OF icon,         icont_tab TYPE STANDARD TABLE OF icont,         wa_icon LIKE LINE OF  icon_tab,         wa_icont_tab LIKE LINE OF icont_tab,         ls_mime TYPE zmime_s,         url TYPE string.   SELECT * FROM icon INTO TABLE icon_tab .   IF icon_tab[] IS NOT INITIAL.     SELECT  * FROM icont       INTO TABLE icont_tab       FOR ALL ENTRIES IN icon_tab       WHERE langu = sy-langu       AND id = icon_tab-id.   ENDIF.   LOOP AT icon_tab INTO wa_icon.     IF wa_icon-internal IS NOT INITIAL.       READ TABLE icont_tab INTO wa_icont_tab WITH  KEY id = wa_icon-id.       IF sy-subrc = 0.         REPLACE ALL OCCURRENCES OF '@' IN wa_icon-internal WITH ''.         CONCATENATE 's_' wa_icon-internal '.gif' INTO url.         CONCATENATE '/sap/public/bc/icons/' url INTO url.  "You can append absolute path with host and port name as well         ls_mime-name = wa_icon-name.         ls_mime-url = url.         ls_mime-shorttext = wa_icont_tab-shorttext.         APPEND ls_mime TO mime_tab.       ENDIF.     ENDIF.   ENDLOOP.
ENDFUNCTION.

I am exporting table type ZMIME_T which refers to structure ZMIME_S with fields NAME, URL and SHORTTEXT of type string. Then I created simple GW service as below,

abap_icon1.jpg

and redefined method MIMESET_GET_ENTITYSET of generated class ZCL_ZTESTMIME_DPC_EXT as below,

 

METHOD mimeset_get_entityset.   DATA: ls_entity LIKE LINE OF et_entityset,         lt_mime_tab TYPE zmime_t,         ls_mime_tab TYPE zmime_s.   CALL FUNCTION 'Z_TEST_MIME_LIST'     IMPORTING       mime_tab = lt_mime_tab.   LOOP AT lt_mime_tab INTO ls_mime_tab.     MOVE-CORRESPONDING ls_mime_tab TO ls_entity.     APPEND ls_entity TO et_entityset.   ENDLOOP.
ENDMETHOD.

With this code, I am able to get relative URLs to all icons from ABAP stack. I developed simple UI5 application to consume this GW service and was able to explore all icons. But I was thinking how to make this available to all to explore icon library. For that, first i downloaded the OData service response in JSON format and then appended SAP demo system host name https://sapes1.sapdevcenter.com/ to relative URL exposed from my OData service. I created local json file and used in my demo application. you can see the demo application at ABAP Icon Explorer SAPUI5 Application

 

Below is the output screen of the application. I used DataSet UI element to display icons.

abap_icon2.jpg

 

There is option to search icons based on ShortText. So if you wan to see icons which contain description as "material", you can search it as shown below,

 

abap_icon3.jpg

 

I hope you will explore ABAP Icons and will use it in your application. Just do not forget to replace SAP Demo system host name with your SAP system host name in real productive applications!

 

Please let me know your views, comments. Happy exploring ABAP Icons!


SAPUI5, EP 7.0 Deployment and iView Creation

$
0
0

Overview:

 

This blog is intended to people / customers who are implementing SAP Portal solutions and have not yet upgraded their systems to latest and greatest but wish to have their applications developed based on SAPUI5. I have been seeing few questions on forums people asking how to build SAPUI5 applications and deploy them to the SAP EP 7.0. Also, how do we create iViews based on these deployments as there are no templates available to create SAPUI5 iViews as in newer versions like Portal 7.3 and even versions like SAP EP7.01 SP30 and above.

 

Solution:

 

I am going to show just a basic example of how to create a Web application project in SAP IDE 7.0, add the project into an EAR application, deploy them to the server and create iViews in Portal.

 

1) Open your NWDS and create a Web Module Project. (File > New > Web Module Project)

 

Web Module Project.png

2) In the WebContent Folder Create a html file and name it as index.html

 

HTML File.png

3) Build your SAPUI5 code into the html file. I have all my code in here but MVC pattern is also supported just in case you need to have the view, controllers, models separately.

index.png

<!DOCTYPE html>  <html><head>      <meta http-equiv='X-UA-Compatible' content='IE=edge' />      <title>Hello World</title>        <script id='sap-ui-bootstrap'         src='https://openui5.hana.ondemand.com/resources/sap-ui-core.js'          data-sap-ui-theme='sap_bluecrystal'          data-sap-ui-libs='sap.ui.commons'></script>     <script>      var btn = new sap.ui.commons.Button({        text:'Hello: Deply Me to EP 7.0',        press: function() {            alert("Successfully Deployed to EP 7.0!")        }    });    btn.placeAt('content');  </script></head><body class='sapUiBody'>    <div id='content'></div></body></html>

4) Create a New EAR Project.

EAR Project.png

EAR Project Name.png

5) Add the Modules to the EAR Project.

Add Modules.png

Add Modules 1.png

6) Generate the Archive Files.

Generate Archive.png

7) Deploy them to the SAP J2EE Engine.

Deploy 1.png

8) Run the application in a browser with the following URL https://<hostname>:<Port>/<WebModuleProjectName>/index.html

Run.png

9) Go to your Enterprise Portal and create a New iView from Template

Create New iView.png

10) Select the URL iView and give the URL of the application you deployed.

URL.png

11) Finish the iView creation and open the iView details. You can define a http system and then use them as a prefix instead of giving the full URL that way when you transport to different environments you do not end up doing manual activities to change the URL to point to the particular server.

HTTP SYSTEM.png

 

12) Preview the created iView.

 

Preview from Portal.png

 

That's it !!! We have deployed SAPUI5 to SAP EP 7.0 Application Server. Enjoy

OPENUI5/SAPUI5 on a Memory Stick in less than 12 Simple Steps (and Eclipse in 2 Steps)

$
0
0

After John post on running SAPUI5 SDK with node.js, UI5 SDK on Node.js, the next step was to see if this could run on a memory stick and be used anywhere.  Which is great for carrying your own sandbox/POC or even as John suggests to send as a business card

 

For the below example I thought I would use the OpenUI5 build, so the memory stick had open source only on it.

 

John Blog goes more into detail than mine, so please read that first to understand the steps below in more detail.

 

Step 1) Install node.js node.js, click the link and click Install.

Step 2) Get yourself the latest build of OpenUI5 SDK from OpenUI5 - Download or the SAPUI5 SDK

Step 3) Get a Memory stick and insert into your machine

Step 4) Create a base folder called openui5 on the memory stick.

Step 5) unzip and copy the OpenUI5/SAPUI5 SDK folder and contents to the openui5 folderNB for me I renamed this to the version so you can have more than one SDK installed, as John suggests in his post.

Step 6) Copy the contents of your nodejs folder, not the folder, to the openui5 folder.

Step 7) start the command prompt and navigate to your openui5 folder.

Step 8) type and execute ./npm install expressjs

Step 9) type and execute ./npm install open

Step 10) create the static_server.js file and save in openui5 folder

 

var express = require('express'),  open = require('open');  app = express(),  port = process.env.PORT || 8888,  openui5 = '/openui5'  url = 'http://localhost:' + port + openui5,    year = 60 * 60 * 24 * 365 * 1000;
// Use compress middleware to gzip content
app.use(express.compress());
//set default mime type to xml for ".library" files
express.static.mime.default_type = "text/xml";
// Serve up content directory showing hidden (leading dot) files
app.use(openui5,express.static(__dirname, { maxAge: year, hidden: true }));
// enable directory listening
app.use(openui5,express.directory(__dirname));
app.listen(port);
open(url); //open in default browser
console.log("Static file server running at\n  => " + url + " \nCTRL + C to shutdown")

Your openui5 folder should now look like this

openui5.JPG

Step 11) Start the command prompt and navigate to the openui5 folder and type ./node static_server 

 

Your server should now start and you can run this memory stick on machines without node.js or OpenUI5/SAPUI5 SDK installed.

 

Next Steps lets get Eclipse running on that memory stick as well.

 

Step 1) Download and unzip Eclispe to your memory stick.

Step 2) Download the correct Java Runtime and copy to the Eclipse folder as JRE.

 

Eclipse.JPG

Eclipse is now ready to run from the memory stick as well, a bit slow to start but performance good once loaded.

 

Martin

Introducing the Yeoman generator for OpenUI5

$
0
0

When building a web application there are allot of mundane tasks that you do over and over with each one. Tasks such as scaffolding out the basic outline of your app (index.html, UI5 bootstrap...), setting up best practices (automatic linting of your source files, a test framework, live-reloading...), plus much more…

 

Welcome Yeoman! An open source scaffolding toolset for modern web applications.

Yeoman allows you to scaffold the basic boilerplate tasks for building a new application. It is based on the concept of generators where each generator allows you to scaffold out the boilerplate and build tools for a basic webapp; an angular.js app and many many other apps based on various javascript frameworks...

...and now we have a generator for OpenUI5 applications.

 

The OpenUI5 generator enables you to quickly scaffold out the basics for an UI5 application based on a couple of different templates. It also sets up the build environment with live-reloading; watching source files for changes and linting with JSHint as well as testing. Not only that but with one command you can launch the applications in a local web server.


This is how it looks:

yoExample.png

 

This is what it creates (among others):

image02.png

Getting Started

Yeoman and the OpenUI5 generator are based on Node.js. So first of all, if you don’t have Node.js installed, you must install that now (don’t worry, it’s straight forward). Node also comes with a package manager for installing components/applications called npm. As soon as

 

npm --version

 

on your terminal returns something like 1.3.21, you’re good to go.

How to Install Yeoman

With npm, the installation of yeoman is a piece of cake. Just type

 

npm install -g yo

 

into your terminal. You can find more details on the Yeoman homepage.

How to Install the Generator

Installing the openui5 generator is just as simple. Just type

 

npm install -g generator-openui5

 

into your terminal and let npm do the magic. You can find more information here.

How to Create an application

The short version

Just run

 

yo openui5
grunt serve

 

in your terminal. After you provided the information the generator needs and some package resolution work, you should see the generated application in your default browser served from your local machine.

The little longer version

Run Yeoman with

 

yo
yo --help

 

at the command line. To get an overview of the sub-generators a generator provides, just type yo --help.  This will give you a list of the sub-generators of every generator.

Starting yo without any arguments, it will give you a list of installed generators - select OpenUI5 to scaffold an OpenUI5 application. As a shortcut you can directly run the generator with

 

yo openui5

 

(which starts the default sub-generator app).

 

The OpenUI5 generator will ask a series of questions so as to scaffold an appropriate application to get you started. Questions such as:

 

  • What is the name of your application? - The name is simply used as the <title> element in the generated index.html file as well as being used in the generated readme and package.json files.
  • A description for the application? - This is used in the readme and package.json as above.
  • Author name?
  • A GitHub repository (if any) for the application? - Used in the package.json file.
  • Licence Type? - Choose a licence type for your application (if any).
  • Application type? - This is where we choose what architecture you want for your generated application. The different options are described further below. If a Fiori-type application is chosen then an additional component namespace must be entered.
  • OpenUI5 library location? - You can choose whether or not you want to use the OpenUI5 libraries managed by Bower or choose another location (which defaults to: https://openui5.netweaver.ondemand.com/resources/sap-ui-core.js).
  • Local Server Port? - This is the localhost port you will serve the application from during development. Defaulting to 8080.
  • Live-reload? - Enable live-reloading of the browser when your development files change.

 

After you’ve gone through the above prompts the generator will scaffold out your boilerplate application and begin to download any dependencies. Dependency management is handled with bower and npm and you will see a flash of terminal output as each dependency and sub-dependency module is download, cached and version checked.

Of these dependencies only the bower OpenUI5 repository is required by your actual application (if you chose to use the bower repository). The rest are required by the build tools that are being setup for your to enable: a local http server with proxy capabilities; watching files; live-reloading; linting your code and so on.

 

Once all dependencies are installed, then

 

grunt serve

 

and you’re up and running...

 

 

Application-type scaffolding options

 

Classical

This option generates a “classical” UI5 application using the “sap.ui.commons” library based on an sap.ui.app.Application object.

 

Fiori Splitter App

This option generates a Fiori-style sap.m.SplitterApp application using some mock data so that the app runs out-of-the-box. The new component architecture is used as well as declarative XML views.

 

Fiori Tiles App

This option generates a Fiori-style sap.m.TileContainer application using a mock OData source. the new component architecture as well as XML views is used here as well.

 

Single Page MVC App

This option generates a simple single page MVC application, where the view and controller are all declared directly in the html file. This is handy for testing OpenUI5 features.

 

Add Elements to your Application

How to add a view

If you need additional views for you application just use the view sub-generator by running

 

yo openui5:view

 

on your terminal. You just have to provide a name of the view, the type and an namespace (optional). Views (with their controllers) are generated in the view sub-folder of your application.

How to add a Component

Additional components can be added with

 

yo openui5:facelessComponent
yo openui5:uiComponent

 

depending of what type of component you need.

The component name can contain a full package structure (e.g. foo.bar.myComponent). In that case the folder structure reflecting the package structure is generated and myComponent is placed in foo/bar/. If the package root (in the example above foo) is not yet registered as a local resource, the generator tries to fix that in the index.html file as well (alternatively you can add the full application namespace to the component package name).

Grunt Tasks

Yeoman comes with grunt as a task runner (similar to maven or ant).

Together with the UI5 application, the generator creates some tasks for you, which are useful for your application development and testing (they are defined in the file Gruntfile.js)

Running your generated application

For testing the application, there is a grunt server task configured which acts as a local web server. The really cool thing about it is, that you don’t need any configuration to run the basic application. Just start

 

grunt serve

 

This task starts the server and opens the application in your default browser.

 

If you need to access external resources (like oData services), you just need to add the information to the proxies section in Gruntfile.js. Further information can be found in the grunt-connect-proxy module documentation.

Testing

To run the unit tests of your application, just execute

 

grunt qunit:all

 

This task executes all unit tests located in the /test subfolder. Currently that folder is empty  after the scaffolding and it’s up to you to implement your unit tests. We plan though, to deliver some example tests in the future.

 

Besides the qunit task, we have two other handy tasks in stock:

 

grunt jshint
grunt watch

 

  • grunt jshint performs a jshint check on all your JavaScript files and gives you some hints about making your code cleaner. If you need to adjust the settings, you can modify them in the jshint.options section in the Gruntfile.js.
  • grunt watch basically waits until you change a file and then automatically executes the jshint task and then the qunit task. This very smoothly supports a test driven development workflow (I, for example have my sublime text split in two editors. One with the file I’m working on and one with the unit test belonging to it. On the right hand side a grunt watch task constantly executes jshint and the unit test whenever I save a file):

Bildschirmfoto 2014-02-03 um 23.24.25.png

 

What’s next

We have a couple of ideas how to enhance and optimize the generators and what features we could add (routing, Fiori Launchpad integration, building tasks, deployment options… just to name a few).

But we really would love to hear from you guys, what you would need or expect from the generator. So please leave your feedback or wishes either in the comments or directly on the generator issue page on github. For sure, contributors are more than welcome, any time!

 

One more thing...

Unfortunately I didn't manage to add a co-author to this post, therefore I'd like to express my thanks to Jason Scott this way. Not only did he help writing this blog but he also did an awesome job in helping to develop the generator to it's current state. Thanks mate!

Multi Model Support and Binding For OData Services

$
0
0

Problem:

 

Many times we need to include an OData service which is common for many application.In this scenario instead re writing the OData

service again we should create more than one model.

 

Create Main OData Model and set it globally :

 

this.metadataUrl = "proxy/sap/opu/odata/sap/ZMM_MOBILE_MATERIAL_SRV/";   sap.ca.common.uilib.Ajax.registerModelUrl(  "sap/opu/odata/sap/ZMM_MOBILE_MATERIAL_SRV/",  "proxy/sap/opu/odata/sap/ZMM_MOBILE_MATERIAL_SRV/");
this.oDataModel = new sap.ui.model.odata.ODataModel(this.metadataUrl,true);
this.oDataModel.setCountSupported(false);
sap.ui.getCore().setModel(this.oDataModel,"mainModel");

 

Create Second OData Model :

 

this.metadataUrl2 = "proxy/sap/opu/odata/sap/Z_NEW_ODATA_SRV/";   sap.ca.common.uilib.Ajax.registerModelUrl(  "sap/opu/odata/sap/Z_NEW_ODATA_SRV/",  "proxy/sap/opu/odata/sap/Z_NEW_ODATA_SRV/");
this.oDataModel2 = new sap.ui.model.odata.ODataModel(this.metadataUrl2,true);
this.oDataModel2.setCountSupported(false);
sap.ui.getCore().setModel(this.oDataModel2,"secondModel");

 

 

Explanation:

sap.ui.getCore().setModel(this.oDataModel,"mainModel");
sap.ui.getCore().setModel(this.oDataModel,"secondModel");

 

The above line will set OData models to the core of the application.To distiguish bwetween both of them in our application we can give

modelNames(mainModel,secondModel) while setting it.

 

Using The Models:

Say you want to set the "secondModel" to a list control :

 

this.getView().byId("list").setModel(this.oDataModel2);

 

Proprty Binding :

 

<Text text="{mainModel>/name}"/><Text text="{secondModel>/name}"/>

Regards,

Rauf

My 2 cents on Securing SAPUI5 Applications

$
0
0

Building SAPUI5 applications and putting them out on the server is good. Great !!! Ever wondered when these applications are deployed to the server how it can be accessed. SAP Portal is one option to host all your application developments. You have different ways of launching your applications from SAP Portal (URL or SAPUI5 iView Templates) in newer releases and URL iViews in older releases. So far good, Portal is secured with default authentication mechanisms. But the glitch here is any of these applications can be accessed via a direct URL like the below -


https://<hostname>:<port>/<UI5 Web Project>/index.html


index.jpg


Security !!! That's what we are talking about. I did not really look at this angle until a couple of days back I saw this thread SAPUI5 App running on Portal - SSO? Thought of following this thread for answers but this thread just kept going back from being seen from users. So, I thought lemme give a shot on how to secure these applications out there lying down in the server. Here are my 2 cents on how we can secure our applications via a BASIC authentication method. There might be other better ways around but this is the one I found which works good for basic authentication. Now let's get on to some action.


All the SAPUI5 applications comes with the web.xml file which can tweaked a little bit to secure the applications. Find below the code that added to my web.xml


<security-constraint>        <display-name>Authentication of Users</display-name>        <web-resource-collection>            <web-resource-name>SAPUI5</web-resource-name>            <url-pattern>/*</url-pattern>            <http-method>GET</http-method>            <http-method>POST</http-method>        </web-resource-collection>        <auth-constraint>            <role-name>Test</role-name>        </auth-constraint></security-constraint><login-config>       <auth-method>BASIC</auth-method>       <realm-name>domain_name</realm-name></login-config><security-role>       <role-name>Test</role-name></security-role>

Explanation of the above code -


1st Part - Security Constraint


Security Constraints are least understood by web developers, even though they are critical for the security of Java EE Web applications. Specifying a combination of URL patterns, HTTP methods, roles and transport constraints can be daunting to a programmer or administrator. It is important to realize that any combination that was intended to be secure but was not specified via security constraints, will mean that the web container will allow those requests. Security Constraints consist of Web Resource Collections (URL patterns, HTTP methods), Authorization Constraint (role names) .


2nd Part - Login config


Here you can define the BASIC authentication mechanism and realm could be depending on the how the users and groups in your organization are controlled. It could be either default or your domain name. In my case I have given my domain name of the server.


Note: There are different mechanisms available like the FORM, CLIENT_CERT etc.


3rd Part - Security Role


This is the same as auth constraint role name. This is the role that will be automatically deployed to your server.


Next and the final step is modifying your web-j2ee-engine.xml file. If you have created a web module project then this is automatically available if not you can create your file inside the Webcontent > WEB_INF folder.


Why do we need this file? This file is going to hold the role mapping between application and the server. From the Web.xml role name Test has to be mapped to a physical role that exists in the server UME database to authorize users who can access the applications. A sample mapping give below -

I am mapping the applications Test role to the Administrator role in Portal UME database.


<?xml version="1.0" encoding="UTF-8"?><web-j2ee-engine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="web-j2ee-engine.xsd">  <spec-version>2.4</spec-version>  <security-role-map>  <role-name>Test</role-name>  <server-role-name>Administrator</server-role-name>  </security-role-map></web-j2ee-engine>

Now, when you deploy the application to the server this is what you see when accessing the direct URL.


Auth.png


Now, who can access these applications? Only the users who are part of the Administrator role can view the applications.


app.png


When a user who does not belong to this role access the application below is the error you get.


ananymous.png


Tada My application is secure. Is your application secure? Share me your thoughts if there are other better ways out there !!!

 

PS: This is for your server versions where security provider roles and modules are managed via NWA. For older release there is an additional step after the role mapping in the xml file. You will have to manually configure the role and mapping references in the Visual Admin > Secure provider for specific components.

Matt Harding’s Fiori Like Challenge – High Resolution Prototype and then Some…(Part 5)

$
0
0

Continued from Matt Harding’s Fiori Like Challenge - The Diversion...(Part 4).


Happy New Year

For all those living in the Northern hemisphere; if you've been following this series I've just demonstrated how inconvenient your summer holidays are to us in the Southern Hemisphere when it comes to US TV shows abruptly stopping in the middle of our Winter.

So anyway, we've been enjoying our Summer Holidays down South, and with school now back, I can spend some time on this blog series again. Maybe we can consider this blog as the start of the 2nd season of the series with a really lame cliff hanger from last year!

So with that, let’s get down to…

 

The High Resolution Demo

Well what you didn't see in the break is the numerous iterations I went through with my alter ego stakeholder and the number of changes made to the design.  We've kind of moved away at this stage from Design Thinking (DT) but since DT is a collaboration process with a diverse group of people, and I’m flying solo at the moment, I figured that’s probably okay!

 

Design Thinking Side Note

During the “break” I was lucky enough to take part in a DT workshop at SAP, witnessing SAP run this first hand.  I won’t talk in detail about it (as I’m not sure what I can and can’t talk about), but I will say we did end up with a lot of diverse thinking from people all over the world with very different backgrounds. The group I was privileged to be in challenged me greatly (in a good way) which did really result in a great overall impact on the final design.

Considering it was only 3 days in total, and we achieved a unique outcome with an action plan (that would not have been as comprehensively possible with any one of us alone); I’d say it was well worth it for SAP to do this.  All that said, one significant learning I did take away from the workshop was that while DT is collaborative, you still need decision makers to step in early to not let non-consensus stalemate you. Additionally, it’s also hilarious to watch Project Managers get nervous with the “fluffiness” of the DT process when they do not see an action plan till the very end of the workshop!

Anyway, back to our main program:

 

Anyway, since my last blog, I've focused purely on just the search aspect and fine-tuned it down to a couple of scenarios, with an additional tablet/desktop experience view option. What does it look like? We’ll let’s talk about the scenario we’ll be demoing first:

 

The Problem Scenario

John is sitting in a meeting with a guy named Bob? who’s some kind of Architect and wants to know more about him so he doesn't make a fool of himself!

 

Option 1: Sitting with just his mobile in his hand

I’ve inserted a video for this scenario as one of the key features is how quickly it responds which can only be seen in a video. The demo is obviously using scripted results coded into the solution so is incredibly quick, but I wouldn't want the final version to be that much slower (1 second AJAX style response times on search numbers is what I’m after in the final solution – hence expecting great things from HANA )

 

 

Option 2: Sitting with a PC in front of him

Almost identical (same code of course), but responsive design kicking in to give me permanent access to the Search area. We also have a table view with some information available if we just want to view key information on one screen for all people in the search (useful if calling everyone from one department).

Initial Desktop View.JPG

Initial Search Page on a Desktop

Search Results Desktop View.JPG

Search Results on a Desktop (Browse Mode)

Doce Doe Desktop View.JPG

Pulling up information on Doce Doe on a Destkop (that guy has a great head of hair)

 

Alternative Search Results Desktop View.JPG

Direct Access View on Desktop (allows Sorting, direct SMS or calling, emailing)

 

Option 3: Sitting with a tablet in his hand

Same as Option 2 except reduced information is available on table view (again UI5 responsive design features kicking in).

 

Initial Tablet View.JPG

Initial Search Page on an (emulated) iPad

Alternative Search Results Tablet View.JPG

Direct Access View (probably should show phone and email on Tablets rather than Organisation/Position).

Stakeholder Feedback

I like it…when can I have it – And can it be prettier, plus I want bookmarks to be synchronised between my mobile and iPad, and available offline…plus plus plus…

Well – at least they’re happy and excited with the fast turn around time of this type of development...

 

Next Steps for Name Search

So the above is all well and good, but what about a real deployment solution now. Not only that, I have lots more tasks to do with this before I'm finished. So to whet your appetite (but possibly keep you hungry for a long time too); the following are the next steps (not necessarily in order):

  • Stand up AWS development instance with Gateway/HANA installed to host Restful services/backend data model.
  • Not initially, but also possibly even stand up HANA Cloud Platform to host the app and handle authentication/authorisation, and link to Gateway via HANA Backend Connector (BHAG)
  • Build Gateway model (outside-in) to get people info, search, images, bookmark information, etc. Note - Gateway interfaces IMO should be made for easy focused consumption, and not as a completely reusable API for your backend (more on this to come in the future but as an example, my search API is going to be a single round trip for performance around the globe).
  • Enhance search to use HANA style SQL queries for performance
  • Pretty up the entire solution (still too clunky for my liking)
  • Sort out a github integrated scenario for development (been lazy so far with development)
  • Explore the use of a manifest.cache option to deploy, plus ways of minimising code/obfuscation/caching to maximise resource loading performance and get more native app like performance.
  • Explore creating new UI5 image control to use image offsets/sizes so we can create a large image file of 100's of faces, download once on device, and provide face images to browsers much quicker. Submit to OpenUI5 if possible when done! (This was inspired from GWT)
  • See if we can preload the previous image files in a way to have them even before a user has searched.
  • Build an ABAP Image processor to shrink and combine photos into a 100 photos per image, for the previous task to use.
  • Implement some kind of SSO.
  • Implement the solution within an Android KAPSEL based solution, and deploy in the SMP cloud.
  • Build bookmark functionality, including offline access.
  • Then in 2016 I might...hmm

 

Sharing Some of the recent UI5 Prototype Learnings

Moving Target

I’ve felt like over the last 3 months, UI5 best practices have been slowly progressed, but are still far from established. The problem and opportunity with what is now an open source web framework is that unlike ABAP, and predefined approaches to JAVA that SAP have traditionally pushed forward with; there is nothing in the Web world stopping you doing whatever you want in any way you want to. In terms of best practices, sure the MVC aspect of UI5 is defined, but even the switch from JS to XML views is not consistent with the AppBuilder’s use of HTML views, and then there’s the various MVC project structure best practices that are followed, versus the best practices defined in the SDK documentation. This actually concerns me as I worry about those who won't have a web background or are use to ABAP tools doing so much for them - the number of enterprise flavours of UI5 we may see in 2 years time may be scary.

 

Choice and Limitations

Within the prototype, I tried to stick to mobile libraries as one of the big requirements, but it sure is easy to see other controls and want to include them (both UI5 and outside of UI5). There are a pleasing number of controls to use in the UI5 libraries today, but to a degree, it almost feels like we need to squeeze the app's into the controls rather than address the problem at hand. For example, the bookmark button in the demo is actually a button with CSS moving it to the top of the window where I want it. In hindsight, I probably should have embedded my own HTML and done my own thing to get exactly what I want; but kind of feels more "custom" if I do that and if others all did the same thing, then we'd all need to be cross-browser experts in CSS (this is an expert career in itself)!

 

Is Eclipse or Sublime the Dark Side?

I tried to embrace Eclipse for development, and JavaScript code completion and Al Templeton’s XML Parser for helping build XML Views worked okay (actually helped me build an XML where the doco was wrong in one case and had me scratching my head), but the XSD’s from SAP weren't perfect; the lack of keyboard shortcuts for testing, the need to start up a tomcat server (I could have automated it, but why when IIS is much easier to manage IMO), and the general “clunkiness” of Eclipse such as navigating the file system for demo code and the like; just made me want to go back to notepad++.

 

Even the code-completion in JavaScript wasn’t really enough to keep me in Eclipse and in the end, after watching DJ Adams' Sublime video, and Jason Scott also in love with Sublime for the fact you don’t need to use your mouse, meant I’m now trying to use Sublime for development. The ability to simply point IIS at my source made testing instantaneous and Sublime isn't half bad either.


I really do want to go back to Eclipse, but it’s just getting too heavy and slow and ironically not focused on the user experience of a developer IMO. That said, I’ll probably end up back there in the near future when XML View auto-complete and better ways of working with the file system and testing are figured out, or at the very least, to manage my Gateway development when I do that next.

 

Implied paths

Did I ever mention that I hate leaps of faith in coding?  One aspect that drives me crazy is the leap of faith for views and fragments.  These predefined suffixes that UI5 expects for filenames, while your code refers to simply the first part of the filename. Yeah – I’ll get over it, but it does make some of the code cryptic.

 

Chrome is Awesome

Most of you already know this, but the abilities with Chrome for developers are fantastic. Even yesterday I only just discovered the icon "{}" on debugging JavaScript - Basically it pretty prints compressed JavaScript code for you so you can debug like a human being. Ethan Jewett then also pointed out the Console.Table command (very cool visualisation of objects command).

 

The most obvious feature of use in Chrome was the ability to emulate different devices/screen sizes but the ability to disable cache while dev tools open would be a close 2nd.


Frederic to the rescue

Prior to the 1.18.8 OpenUI5 release, XML samples were far and few between (check out the latest sap.m explored demo app and press the lightbulb icon to see some good XML view examples).  Creating XML views is an art you can learn, but it’s very freaky when coming from an HTML view to get used to having to read API documentation, and understand things like default content areas, XML Fragments, etc.  But that was made much easier when I commented on Twitter about my frustration of trying to take JS examples and make XML out of them and Frederic Berg came to the rescue:

Berg.JPGWow – Automatic generation of XML from any type of UI5 app you have browser access to. Not a perfect extract in all cases (eg. Complex filter objects within tables); but enough to help during the learning curve. Pretty impressive help from Frederic in just 1 tweet of information!

 

Creation Tool and App Builder Tool

Since the last blog, a creation tool was (sort of) released and the App Builder Tool for mobile UI5 apps was released by SAP.  Both quite slick, but a little too programmatic for my liking, but could be good to get a framework in place (albeit the App Builder produced HTML views). In my opinion, UI5 is about crafting a web page, and not just building it like you did in ABAP with predefined ways of doing everything; but definitely some good first releases to explore. I attempted to start again with these tools, but found it better to come back to my handcrafting technique.

 

The full meta model extract of UI5 controls

Useful sapui5 coding help meta information files

Thanks to Lucky Li, the link above includes links to download a programatically extracted meta model text file of all the UI5 libraries. Just having the all libraries file open in Sublime on 1 tab was handy when you wanted to know what keywords or constants were (without reading the API documentation).

 

Building from Scratch versus Retrofitting Examples

DJ Adams also mentioned something like this to me, but while demos were great to understand what was possible, writing UI5 was best learnt by adding what you need to your views by crafting the XML versus cutting and pasting content.  Once you truly understand it, cut and paste away is what I say!

 

High Resolution Prototype is Still a Throwaway Prototype

I think I built 3 or 4 prototypes till settling on this as a prototype to share.  Partly because even after going through the complete set of mobile controls, you don't realise what can be done till you play around with the control in anger. For example, not all CSS attributes will impact controls the way you would like it to leading to a very cool control that isn't quite right. And as soon as I get the Gateway service up and running, I'll put all the code on github to share/improve.

 

Community is Small but has some Rockstars Already

With the UI5 stack overflow community ramping up, and some obvious key players being quite vocal and sharing great content/tools/etc; the challenge for SAP is to have consultants at customer sites suitably up-skilled and semi-consistent ASAP since I am already seeing flavours out there (on SCN/jsbin/github) of development. The community needs to grow, with quality web experienced developers ASAP, and hopefully the open source community outside of SAP may be what we need?

 

End of Season 2

What? Yep - No more Fiori Like Challenges. So an abrupt end to Season 2, but rather than continue the Fiori Like Challenge series, I'll break into mini-series now where we talk about the continued development using Gateway, HCP, HANA, etc.

Text Area resize handler thingy

$
0
0

Hi again,

The following one is from the tips and tricks department.


This is something I came across trying to solve a weird issue in a text area control we added somewhere in the portal and I thought it might be fun to share.

Sometimes you want to have a text area that can be re-sized by the user for whatever reason.

 

When you create a new textArea control, it comes with a fixed size that you can set in advance or by css etc.

 

However, you can very easily make it to be a dynamically re-sizable control if you get to know the following css class:

sapUiTxtA

 

Here is an example taken straight from the TextArea control's page on the SAPUI5 Demo Kit website.

 

I took the TextArea example and modified it in the same page.

When you initially create it, it will come with this class: 'sapUiTxtA' and look like this:

without.png

 

So what you can do, is just use removeStyleClass('sapUiTxtA') to get this:

with.png

 

I don’t know why, but sometimes you may have to explicitly add the class in order to actually be able to remove it...

(in this example I did it manually in the console)

 

I put a better example on snipix for you to play with and copy.

 

For some reason there is no API for this cute little feature and it does not show up anywhere in the documentation (at least not that I found...).

 

It’s a cool thing to know and may come in useful to some.

Keep in mind though, that playing around with the styles in such a way, or changing the way a control behaves not thru the API, may prove forward incompatible, so do it at your own risk, or at least keep good references of the places you have made such manipulations.

 

 

Have fun.

 

Byg


OpenUI5 and Google Charts

$
0
0

Introduction

When working with OpenUI5 (which is open source) you do not have all the libraries of SAPUI5.In most cases, you can accomplish your goals with OpenUI5. But there will be always cases that you’ll need more than what’s in OpenUI5. In that case, you’ll have multiple options. One of the most obvious choices is switching to SAPUI5 (if this has what you need). This option will have extra costs, which you do not want! So another option is looking for external open source libraries.

 

Charts

When you have the requirement to use Charts in your application, you will not be able to do this with OpenUI5. This is just not foreseen in OpenUI5. One of the options will be SAPUII5, because this has Chart components!

 

sapui5vsopenui5.png

 

But what if you don’t have the budget for a SAPUI5 license? Or you just want to keep using open source frameworks/libraries?

 

Besides switching to SAPUI5, you could look for other open source libraries. For Charts, google has a great library called Google Charts! Of course, there are multiple other libraries for Charts!

 

Google Charts

Google Charts is a javascript library for visualizing data on your website. You can visualize your data in different kind of charts.  An overview of all charts provided by google:

 

https://developers.google.com/chart/interactive/docs/gallery

 

Google Charts in OpenUI5

Okey, so Google Charts are looking nice! But how to use this in combination with OpenUI5?

 

  • Load Google Chart in the “index.html”

load googlecharts.png

  • Create an HTML component in the JS View ( I also add this HTML component to a Panel, which is not required)
    • In the HTML component I add a DIV which will be used for creating the chart.
    • In the afterRendering method I define my callback method, which is in the controller .

 

var html1 = new sap.ui.core.HTML("html1", {              content:                      "<div id=\"piechart_3d\" style=\"width: 900px; height: 500px;\"></div>",              preferDOM : false,                                 afterRendering : function(e) {              google.setOnLoadCallback( oController.drawChart() );              }      });
  • Initialization of my data by using the google API (Controller)
data = google.visualization.arrayToDataTable([                                              ['Task', 'Hours per Day'],                                              ['SAP',     15],                                              ['Eat',      2],                                              ['Traffic',  2],                                              ['Sport', 1],                                              ['Sleep',    4]                                                     ]);
  • Configure the Google Chart (Controller)
var options = {      title: 'My Daily Activities',      is3D: true,      slices: {  0: {offset: 0.2}},      legend : {position: 'left', textStyle: {color: 'blue', fontSize: 16}},    };
  • Define the Chart by using the DIV element(Controller)
chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));
  • Draw the Chart (Controller)
chart.draw(data, options);
  • Add an event listener  to the Chart for selection with a callback function (Controller)
google.visualization.events.addListener(chart, 'select',   this.selectHandler);
  • Create event listener (Controller)
    • The event listener will just alert the row, column and description of the selected value.
selectHandler: function(){   var selection = chart.getSelection();   var message = '';   for (var i = 0; i < selection.length; i++) {     var item = selection[i];     if (item.row != null && item.column != null) {       var str = data.getFormattedValue(item.row, item.column);       message += '{row:' + item.row + ',column:' + item.column + '} = ' + str + '\n';     } else if (item.row != null) {       var str = data.getFormattedValue(item.row, 0);       message += '{row:' + item.row + ', column:none}; value (col 0) = ' + str + '\n';     } else if (item.column != null) {       var str = data.getFormattedValue(0, item.column);       message += '{row:none, column:' + item.column + '}; value (row 0) = ' + str + '\n';     }   }   if (message == '') {     message = 'nothing';   }   alert('You selected ' + message);  }

 

Full Code

Full code of the view:

sap.ui.jsview("openui5withchart.chart", {  /** Specifies the Controller belonging to this View.  * In the case that it is not implemented, or that "null" is returned, this View does not have a Controller.  * @memberOf openui5withchart.chart  */  getControllerName : function() {  return "openui5withchart.chart";  },  /** Is initially called once after the Controller has been instantiated. It is the place where the UI is constructed.  * Since the Controller is given to this method, its event handlers can be attached right away.  * @memberOf openui5withchart.chart  */  createContent : function(oController) {  var content = [];  var html1 = new sap.ui.core.HTML("html1", {              content:                      "<div id=\"piechart_3d\" style=\"width: 900px; height: 500px;\"></div>",              preferDOM : false,                                  afterRendering : function(e) {              google.setOnLoadCallback( oController.drawChart() );              }      });  var oPanel = new sap.ui.commons.Panel();  oPanel.setTitle(new sap.ui.core.Title({text: "Google Chart"}));  oPanel.addContent(html1);  content.push(oPanel);  return content;  }
});

Full code of the controller:

var chart = null;
var me = null;
var data = null;
sap.ui.controller("openui5withchart.chart", {
// onInit: function() {
//
// },  drawChart: function() {   me = this;   data = google.visualization.arrayToDataTable([                                              ['Task', 'Hours per Day'],                                              ['SAP',     15],                                              ['Eat',      2],                                              ['Traffic',  2],                                              ['Sport', 1],                                              ['Sleep',    4]                                                     ]);   var options = {      title: 'My Daily Activities',      is3D: true,      slices: {  0: {offset: 0.2}},      legend : {position: 'left', textStyle: {color: 'blue', fontSize: 16}},    };    chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));    chart.draw(data, options);    google.visualization.events.addListener(chart, 'select',   this.selectHandler);  },  selectHandler: function(){   var selection = chart.getSelection();   var message = '';   for (var i = 0; i < selection.length; i++) {     var item = selection[i];     if (item.row != null && item.column != null) {       var str = data.getFormattedValue(item.row, item.column);       message += '{row:' + item.row + ',column:' + item.column + '} = ' + str + '\n';     } else if (item.row != null) {       var str = data.getFormattedValue(item.row, 0);       message += '{row:' + item.row + ', column:none}; value (col 0) = ' + str + '\n';     } else if (item.column != null) {       var str = data.getFormattedValue(0, item.column);       message += '{row:none, column:' + item.column + '}; value (row 0) = ' + str + '\n';     }   }   if (message == '') {     message = 'nothing';   }   alert('You selected ' + message);  }
});

Result

result1.png

After selection:

result2.png

 

 

You can find the view/controller and index in the attachment!

 

For the pie chart I’ve used following:

 

https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart#3D

 

For the select event I’ve used following:

 

https://developers.google.com/chart/interactive/docs/events#The_Select_Event

 

 

Another example of using open source libraries with Openui5: http://scn.sap.com/community/developer-center/front-end/blog/2014/02/20/client-side-sort-and-search-in-openui5-with-underscorejs

 

Hope it's useful!

 

Kind regards,

Wouter

Talk: Function the Ultimate by Douglas Crockford

$
0
0

Why "function" is the most important keyword in JavaScript

 

This Talk from JavaScript Guru Douglas Crockford explains the importance of the keyword "function". I'm convinced, that this video will give you a better understanding of the characteristics of JavaScript. Crockford says: "Functions are the very best part of JavaScript. It's where most of the power is, it's where the beauty is."

 

Simple tool to import sapui5 debug version files

$
0
0

     SAPUI5 provides two type of source code:

  1. The minimized such as Button-dbg.js, which is used for run time
  2. The debug version such as Button-dbg.js, which contain the human being readable source code.

    If we want to study the source code, we only need to add the debug version to the project. But as there are so many source code, it is very difficult to just add the debug version. In order to solve this problem, I create a simple tool for it.

 

Solution:

     ( Under Linux, it is very easy, just use the find command can find out all the *dbg.js and copy it to another folder. As most of us work on Windows, so it come out this blog )

In the windows command window, go to the directory contain the sapui5 source code, and type command

          dir *dbg.js /s /w

 

     The output like

Volume in drive C is OSDisk
 Volume Serial Number is 0460-99E1
 Directory of C:\tool\latest-ui5\20140227\sapui5-dist-static\resources
jquery-1.7.1-dbg.js            jquery-sap-dbg.js
jquery-ui-core-dbg.js          jquery-ui-datepicker-dbg.js
jquery-ui-position-dbg.js      jquery.sap.act-dbg.js
.....              29 File(s)      8,697,392 bytes
 Directory of C:\tool\latest-ui5\20140227\sapui5-dist-static\resources\sap\ca\scfld\md
ApplicationFacade-dbg.js   ComponentBase-dbg.js
ConfigurationBase-dbg.js   library-all-dbg.js
library-dbg.js             Startup-dbg.js               6 File(s)        178,864 bytes

 

     The output will list the directory, then list all the files under that directory. So we can create a tool which will analyze the output, then generate the command which can copy the debug version file into another folder.  Then we can import all the files under that folder.

 

 

Tool link and usage

Just  open  Copy UI5 Source

 

It looks like following, and is very easy to use.

copy_ui5.png

Generated 1.18.6 version copy command file

See attachment. Please remember change the first line to fit your real location

set parent=C:\tool\latest-ui5\1.18.6\sapui5-dist-static\resources
copy "%parent%\\jquery-1.7.1-dbg.js" 
copy "%parent%\\jquery-sap-dbg.js" 
copy "%parent%\\jquery-ui-core-dbg.js" 
.....
mkdir sap\ca\scfld\md
copy "%parent%\sap\ca\scfld\md\ApplicationFacade-dbg.js" sap\ca\scfld\md
copy "%parent%\sap\ca\scfld\md\ComponentBase-dbg.js" sap\ca\scfld\md
copy "%parent%\sap\ca\scfld\md\ConfigurationBase-dbg.js" sap\ca\scfld\md
copy "%parent%\sap\ca\scfld\md\library-all-dbg.js" sap\ca\scfld\md

Building SAP Fiori-like UIs with SAPUI5 in 10 Exercises

$
0
0

This blog describes our SAPUI5 tutorial (including SAPUI5 project sources) on Building SAP Fiori-like UIs with SAPUI5 in 10 Exercises.

 

Enjoy working through the exercises, enjoy building SAP Fiori like UIs with SAPUI5!

 

Regards, Bertram Ganz together with Thomas Marz, Frederic Berg and DJ Adams

 

Table of Content

Overview

Objectives:  Learn how to build own custom SAPUI5 applications that reflect the approach used with SAP Fiori-applications. Know important coding best-practices and architecture details to realize responsive UIs, device adaptation, table filtering, navigation or component-based MVC architecture by using the SAPUI5 mobile control library sap.m and the SAPUI5 runtime API.

 

What's not covered: This tutorial does not cover SAP Fiori UI extensibility, integration of custom SAPUI5 applications into SAP Fiori, SAP Fiori launchpad, SAP Fiori Toolkit, OData service provider implementation on backend side


Applies to:  The exercises are based on the SAPUI5 Runtime version 1.16.4 that is comprised in the following SAP platform releases:

  • SAP NetWeaver AS ABAP 7.0/7.01/7.02/7.03/7.31: UI add-on 1.0 for SAP NetWeaver SPS 06
  • SAP NetWeaver AS ABAP 7.40 SPS 6 (where no NetWeaver UI add-on is required)
  • SAP NetWeaver AS Java 7.31 SPS 10
  • SAP HANA Platform SPS 07: SAP HANA extended application services (SAP HANA XS)
  • OpenUI5 1.16.7 see http://sap.github.io/openui5/
  • Evaluation package for UI development toolkit for HTML5 1.16.3 (available here ...)
NOTE: You do not need any SAP backend to build and run the SAPUI5 application sample described in this document! The Fiori-like sample runs locally on a web server that is provided with the SAPUI5 tools in Eclipse IDE. The application’s business data is retrieved from a mock resource (via JSON model) so that no backend service is required.


DesignTime: SAPUI5 developer tools (Eclipse Java EE-based design time environment for the UI Development Toolkit for HTML5) that are freely available on https://tools.hana.ondemand.com/#sapui5 (via the SAP HANA Cloud 90 days trial license).


Target Group: Developers, architects, consultants, project leads and decision makers who want to get first hands-on experience with building SAP Fiori-like custom UIs in SAPUI5.


Exercise PDF: Building SAP Fiori-like UIs with SAPUI5 in 10 Exercise


SAPUI5 Project Sources: BuildingSAPFiori-likeUIsWithSAPUI5_Projects.zip


Estimated time for completion:  2-3 hours

 

SAP Fiori-like Application UI

The User Interface of the final SAP Fiori-like SAPUI5 application described in this document looks like this:

 

BuildingSAPFiori-likeUIsWithSAPUI5_img1.jpg

In the following screenshots you get an impression of the user interface functionality and SAPUI5 controls that's implemented in the tutorial.

BuildingSAPFiori-likeUIsWithSAPUI5_img2.jpg

What You Learn in 10 Exercises

  1. EXERCISE 0 Getting Started:  Set up the SAPUI5 development environment, prepare Google Chrome browser
  2. EXERCISE 1 Resource Model: Set proper titles to master and detail pages by implementing a resource model (aka i18n model, i18n stands for internationalization).
  3. EXERCISE 2 Object Controls: Make the UI of the master list and the detail page more beautiful by using the SAPUI5 controls sap.m.ObjectListItem and sap.m.ObjectHeader.
  4. EXERCISE 3 Formatter: Format status 'color' and 'date' properly by implementing custom formatters that are used in data binding.
  5. EXERCISE 4 Search: Implement a search on the master list by using sap.m.SearchField
  6. EXERCISE 5 Split App & Shell: Utilize the additional space by using the sap.m.SplitAppcontrol which shows the master and detail view next to each other. Wrap the split app in a shell that fills the remaining space on the desktop.
  7. EXERCISE 6 Additional Device Adaption: Adapt the controls to phone/tablet/desktop devices: Show the back button in the detail page only on the phone.Switch the list to selection mode on the tablet and desktop.
  8. EXERCISE 7 Supplier Tab: Add an info tab to the detail page that shows a little form with data of the business partner of the sales order.
  9. EXERCISE 8 Approval Process: Add button to the footer of the detail page to trigger the approval of a sales order. When the user presses the button a confirmation dialog is shown. If the user confirms the dialog the sales order is deleted from the model and a confirmation message is shown.
  10. EXERCISE 9 Line Item: Extend the detail page with a table that shows the line items of the sales order. The rows are active and allow navigating to the new line item page.
  11. EXERCISE 10 Grouping: Add a “Select” to the master list that lets the user select a grouping. Handle the user selection and apply the grouping to the data binding.

 

SAPUI5 Application Architecture

Following the MVC design principle the Approve Sales Order application consists of the following main pieces:

  • Component.js: Acts as a root or component container of the whole application. Implements logic to create the application’s root view (App view) and used model instances.
  • Views with related controllers: App, Master and Detail. App is our top-level view, containing the Master and Detail views. In the App view we use a SplitApp control to contain the Master and Detail views via the App control’s ‘pages’ aggregation.
  • Models: i18n for locale-dependant texts, JSON model with mock data (to be replaced with e.g. an OData model in real applications, a device model for device specific data needed at runtime.

BuildingSAPFiori-likeUIsWithSAPUI5_img3.jpg

Artifacts and package structure of the final SAP-Fiori like SAPUI5 application, that we incrementally build in the exercises, are displayed in this diagram:

BuildingSAPFiori-likeUIsWithSAPUI5_img4.jpg

 

Building SAP Fiori-like UIs with SAPUI5

 

UI Development Toolkit for HTML5 (SAPUI5)

 

SAP Fiori

  • What is SAP Fiori, by Masayuki Sekihara: the best available link collection on SAP Fiori related resources

Small steps: OpenUI5 toolkit now in jsbin.com

$
0
0

In our continued efforts to spread the word of SAPUI5 in general and OpenUI5 in particular, we try to make small steps forward.

 

Here's some quick news about a small step forward with respect to example and demonstration code snippets: jsbin.com now supports the automatic insertion of the OpenUI5 bootstrap. Select the "Add library" menu option, choose the OpenUI5 entry:

 

jsbin1.jpg

 

and lo, the bootstrap script tag is inserted, ready for you to go:

 

jsbin2.jpg

Have a go for yourself!

 

Reaching out and bringing the SAP and non-SAP developer communities closer, one small step at a time.

 

And if you're interested in how this came about, see this pull request on Github: https://github.com/jsbin/jsbin/pull/1220

 

Share & enjoy!

Viewing all 789 articles
Browse latest View live




Latest Images