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.