Saturday, April 23, 2016

UI5 JS view and xml view binding format with sap.m.list

When binding sap.m.list to json data, the path format is different between xml view and js view.

For xml view, the item is specified with curly bracket as below
<mvc:View
   xmlns="sap.m"
   xmlns:mvc="sap.ui.core.mvc">
   <List
      headerText="{i18n>invoiceListTitle}"
      class="sapUiResponsiveMargin"
      width="auto"
      items="{invoice>/Invoices}" >
      <items>
         <ObjectListItem
            title="{invoice>Quantity} x {invoice>ProductName}"/>
      </items>
   </List>
</mvc:View>

But in jsview, the item path is specified without the bracket as below. Note inside the ObjectListItem, the binding to title property still need the curly bracket.

   var list = new sap.m.List("test_list", {
       headerText: "{i18n>invoiceListTitle}",
       width : "auto",
       items :{
           path:"invoice>/Invoices", 
           template: new sap.m.ObjectListItem({
                                 title : "{invoice>Quantity} x {invoice>ProductName}"

                        }) 
       }
            });

Thursday, April 21, 2016

How UI5 defines and creates module instance

In UI5, there are two different ways to define and create modules.

1. The first one is easy to understand, it uses sap.ui.define method to define a module, which takes the dependent libraries and a factory method to define the module. The return value of the factory method is the module object.

sap.ui.require can be used to get the module and pass the module as a parameter in the callback method.

UI5 MVC controller is created in this way as shown below:
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast"
], function (Controller, MessageToast) {
"use strict";

return Controller.extend("sap.ui.demo.wt.controller.App", {

onShowHello : function () {
// read msg from i18n model
var oBundle = this.getModel("i18n").getResourceBundle();
var sRecipient = this.getModel().getProperty("/recipient/name");
var sMsg = oBundle.getText("helloMsg", [sRecipient]);

// show message
MessageToast.show(sMsg);
}
});
});

Only modules defined with sap.ui.define method can be used as dependend models by sap.ui.define as shown above in bold font.


2. The second one is more confusing, as it uses the same method to define and create the instance. For example,sap.ui.jsview method can be used to define  sap.ui.core.mvc.JSView and to create  sap.ui.core.mvc.JSView instance, depends on how the method is called. The document has the below description:

The behavior of this method depends on the signature of the call and on the current context.
  • View Definition sap.ui.jsview(sId, vView): Defines a view of the given name with the given implementation. sId must be the view's name, vView must be an object and can contain implementations for any of the hooks provided by JSView
  • View Instantiation sap.ui.jsview(sId?, vView): Creates an instance of the view with the given name (and id). If no view implementation has been defined for that view name, a JavaScript module with the same name and with suffix "view.js" will be loaded and executed. The module should contain a view definition (1st. variant above).
A sample code to define the jsview is shown below
sap.ui.jsview("sap.ui.demo.wt.view.HelloPanel", {

getControllerName: function() {
return "sap.ui.demo.wt.controller.App";
},

       createContent : function(oController) {
         var controls = [new sap.m.Button({
                                            text : "{i18n>openDialogButtonText}",
                                            press: [oController.onOpenDialog, oController]
                                          }).addStyleClass("sapUiSmallMarginEnd myCustomButton")
                                        ];
                  
                    var panel =  new sap.m.Panel({
                              headerText : "{i18n>helloPanelTitle}",
                              content : controls,
                              width: "auto"
                    });
                    
                    return panel;
          }
});

The sample code to create the view instance is shown at below:

var myView = sap.ui.view(
  {   type:sap.ui.core.mvc.ViewType.JS, 
       viewName:"sap.ui.demo.wt.view.HelloPanel"
  });

Understanding UI5 basic concept

UI5 Control
For each ui control included in the library, two js files are available: one is the definition file, which wraps in sap.ui.define function for others to create the control, another one is render file, which is used to render the control to a html element to be added in the DOM tree.

Note UI control is just a view item rended in html page, which is shown as a basic html element. There is no data or business logic associated with it.

Note all UI5 control has a placeAt method, which can be called to insert the rendered html element into the specified DOM element.

Sometimes, the ui controls are also referred as modules, and can be loaded from UI library by sap.ui.define method.

UI5 library
UI5 Librarey is used to distribute a set of UI controls or types. A UI5 library is represented as a folder structure, and the most important file for the UI5 library is library.js in the root folder, which defined what controls or types are defined in the library. For example, sap.m is a library contains the common ui controls.

library.js's initLibrary method specify the library's namespace, version, dependency, types, and the UI controls implemented by the library.

key methods in sap-ui-core.js
jQuery.sap.require : load a control or ;ibrary
requireModule: send xhr request to load a js module resource
execModule: exec the loaded js module using eval


UI5 Component (or UIComponent)
UI5 Component is used to distribute a set of mvc view and controller, so that it can be used in different index.html page. It can be used to implement an independent business logic, for example, each tile in fiori launch pad is a separate UI component.

When creating a UI5 app from template, it actually create a simple UI5 component, and then wraps it into index.html. The same component can be easily used in other html files.

A UI5 component contains one or more UI5 MVC view and controller to handle the business logic. In the component meta data, it can specify a rootview, which will load the first mvc view in the component. The component can set model on it, which will be inherited to views and controllers created by the component.

Each component has a component.js to initialize the component, and set the model for the component. Starting from ui5 1.30, the component.js can also specify a metadata file to specify the configuration, such as the rootview name and type, resource model, etc. This metadata file is also called application descriptor file. Although it actually describes the UI component.


UI5 MVC view 
MVC view is a UI control object, and can be directly put into html page by placeAt method, the view can specify a MVC controller by name, and also has a getController method to get the associated controller, the view has a setModel/getModel method to set/get associated model object, multiple model object can associate to a view by giving different model name. The default model does not have a name.

When a method is referenced by name in xml view, the method name refers to the method defined in controller object used by the view.

MVC view uses createContent method to specify what UI controls are put in the view object, the method can return a single UI control or an array of UI controls.

Although view can be created by xml, js, json. It is better to create view using javascript for debug purpose.

In order to create a js view instance, use the below sample code
createContent : function(oController) {
        var myView = sap.ui.view({type:sap.ui.core.mvc.ViewType.JS,
                      viewName:"sap.ui.demo.wt.view.HelloPanel"});
        return myView;
}

In case the sap.m.Page content does not show while it already exists on the DOM tree, you may need to disable scroll or set page height to 100%
    var page =  new sap.m.Page({
                              title : "{i18n>homePageTitle}",
                              content : controls,
                              enableScrolling : false,
                              height: "100%"
                    });


UI5 MVC controller
MVC controller has getView method to get the mvc view object associated with it. it also has getOwnerComponent to get the UI component that contains the controller.

UI5 Model
UI5 model are mvc's model object, MVC view has setModel and getModel method to set/get model.


UI5 sap.m.page, panel, app, and shell
sap.m includes container view as panel, page, app, and shell, they can be used to organize the ui controls, and also provide common function and UI such as page title and navigation buttons. sap.m.shell can also be used to adapt screen size and theme.

UI5 sap.ui.core.Icon
There is a good article talking about how icon is organized in UI5 view
http://scn.sap.com/community/fiori/blog/2015/06/27/fiori-icon-logic
The icon is specified by data-sap-ui-icon-content attribute, and then the actual image data is rendered by library.css style.





Saturday, April 9, 2016

MS Azure webapi note

1. To enable debug output to visual studio output window, when creating the dbContext, set the Database.log to System.Diagnostics.Debug as below
        public mysqldbEntities()
            : base("name=mysqldbEntities")
        {
            this.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
            System.Diagnostics.Debug.WriteLine("log enabled");
        }

2. When EntityFramework is used to retrieve data from database, the controller name must match the EntitySet's name defined in Register method as below

     public static void Register(HttpConfiguration config)
        {
           ODataModelBuilder builder = new ODataConventionModelBuilder();
                builder.EntitySet<Product>("Product");
     
               config.MapODataServiceRoute(
                   routeName: "ODataRoute",
                   routePrefix: null,
                   model: builder.GetEdmModel());


    public class ProductController : ODataController
    {
...
}

3. When routing the request, WebAPI controller matches controller and action name case insensitive. But oDataController matches controller and action name case sensitive.

Friday, March 25, 2016

CORS, Content-Security-Policy and JSONP

CORS (Cross-origin resource sharing) is supported by most browsers to hand cross origin requests. Basically, when html content is loaded from bar.com, and it sends an xmlhttprequest to foo.com, then when foo.com returns the response to the browser, it needs to specify the header of
Access-Control-Allow-Origin: *
or
Access-Control-Allow-Origin: http://bar.com
otherwise, the browser will not load the response to the web content. So in this case browser enforces the check based on the server's response header.

Note CORS does not care how the script is loaded in original html page (bar.com), the browser only makes the decision after the response of cross domain request comes back. It would be better it browser can proactively disable the malicious js code if it is not from trusted source. That is how Content-Security-Policy does.

How Content-Security-Policy works is when the original html page returned from bar.com, the server can specify the trusted source for any javascript, css, so that even if malicious js code gets loaded in the page, it will not be executed. For example, if the policy indicates
script-src 'self'
then only the script from the same domain can be executed. Note this also disable JSONP function when it is used for cross domain request, as the script is loaded from a different domain, and it will not be trusted unless Content-Security-Policy allows it to do so.

By the way, for CORS request, by default, hte browser does not send credentials (cookies and http authentication scheme) with the request. In order to send them with a cross-origin request, the client must set XMLHttpRequest.withCredentials to true. In addition, the server must include Access-Control-Allow-Credentials header, this header tells the browser that the server allows the credential to be used for a cross origin request. If the browser sends the credentials with the request, but the server response does not include a valid Access-Control-Allow-Credential header, then browser will not expose the response to the application, and the ajax request will fail.

Saturday, March 19, 2016

Steps to uppload html&js file to MS Azure web app

Visual Studio can easily upload asp.net app to Azure by default setting. But for simple testing Azure web app with html&js files, ftp is the easier to do so with the following steps.

1. Create an Azure web app in Azure portal
2. optional update deploying credential from webapp settings->Deployment credential page
3. click top toolbar button of "Get Publish Profile"
4. open the downloaded file from xml notepad or any xml editor
5. Find FTP profile, and get the value for "publishUrl", "userName", and "userPWD" fields
6. download filezilla or any other ftp tools
7. set host, username, password to the previous values in webapp profile
8. select the local folder for mapping the remote www folder
9. connect to ftp url, and download or update the html&js file to azure web app

Friday, March 18, 2016

Use Vysor to share Android device to desktop

1. goto http://www.vysor.io/ and download vysor and install Vysor (Beta) to Chrome
2. Connect android device using USB cable to mac, it is not necessary to put device and mac in the same Wifi network
3. launch vysor app from chrome and select the android device to share the display.