Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
HPSeitz
Active Participant

In this post I want to introduce the new module concept of SAPUI5/OpenUI5 which is propagated since version 1.28 of UI5. I will explain this with the help of WebStorm UI5 file templates, which will follow this new UI5 module approach and can be used for development custom Fiori apps.

Some words to WebStorm. WebStorm is one of the best IDE for web development (JetBRAINS is able to charge money for it, but still it is very cheap and in my opinion a good investment). And by the way SAP Web IDE is also not free for productive usage, at least up to now. With the following UI5 File Templates it is quite handy and quick to create custom Fiori applications based on the new module concept.

Asynchronous Module Definition (AMD) - New module concept of SAPUI5

With version 1.28 of SAPUI5/OpenUI5 a new module concept is propagated. In the core classes of SAPUI5 it is already used much longer. The code templates which will be introduced below will be based in this concept.

AMD (Asynchronous Module Definition) is designed to allow asynchronous loading of JavaScript modules (with this name not very surprising) in browsers. It is also the API which is supported by RequireJS. So SAP is following a well-established and accepted standard in the web, this is a good direction and will continue to make it a success.

In UI5 this is realised with sap.ui.define to define new modules and with sap.ui.require to resolve module dependencies. To understand usage, let’s have a look at some file template examples:

WebStorm UI5 File Template

File templates can be created in WebStorm via Preferences->Editor->File and Code Templates (in WebStorm 10 with a open project):

Via + (Plus sign) you can create a new Template. Specifiy a name and a extension and use placeholders with ${} syntax. As placeholder we will use ${UI5_Namespace} for the UI5 component namespace and ${NAME} for file name.

Let’s start with controller file:

UI5 Controller Template

Template NameExtension
UI5 Controllercontroller.js


sap.ui.define([
    "sap/ui/core/mvc/Controller"
], function (Controller) {
    "use strict";
    return Controller.extend("${UI5_Namespace}.controller.${NAME}", {
        onInit: function () {
            this.component = this.getOwnerComponent();
            this.bus = this.component.getEventBus();
            this.router = sap.ui.core.UIComponent.getRouterFor(this);
        }
    });
});


So what kind of structure do we facing, if using the new AMD concept:

  • The first parameter of sap.ui.define is an array of strings. Each string represents a dependency. In the example we need sap.ui.core.mvc.Controller class to define our own controller by extending this class. We have to replace all dots with forward slashes. So instead of sap.ui.core.mvc.Controller you need to use „sap/ui/core/mvc/Controller“.
  • Second parameter is the factory function, which get each dependency as parameter (here Controller) . This parameter can then be used within the factory function.

UI5 XML View Template

Template NameExtension
UI5 XML Viewview.xml


<mvc:View
        controllerName="${UI5_Namespace}.controller.${NAME}"
        xmlns="sap.m"
        xmlns:l="sap.ui.layout"
        xmlns:f="sap.ui.layout.form"
        xmlns:core="sap.ui.core"
        xmlns:mvc="sap.ui.core.mvc">
    <Page title="${NAME}"
          navButtonPress="onNavBack"
          showNavButton="true">
        <content>
        </content>
        <footer>
            <Bar>
            </Bar>
        </footer>
    </Page>
</mvc:View>


XML Views are as before, only we put the placeholders in, so that it is working as file template within WebStorm.

UI5 Component Template

Template NameExtension
UI5 Componentjs


sap.ui.define([
    "sap/ui/core/UIComponent",
    "sap/ui/model/resource/ResourceModel"
], function (UIComponent, ResourceModel) {
    "use strict";
    return UIComponent.extend("${UI5_Namespace}.Component", {
        metadata: {
            "rootView": "${UI5_Namespace}.view.App",
            "dependencies": {
                "minUI5Version": "1.28.0",
                "libs": ["sap.ui.core", "sap.m", "sap.ui.layout"]
            },
            "config": {
                "i18nBundle": "${UI5_Namespace}.i18n.i18n",
                "serviceUrl": "here/goes/your/serviceUrl/"
            },
            "routing": {
                "config": {
                    "routerClass": "sap.m.routing.Router",
                    "viewType": "XML",
                    "viewPath": "${UI5_Namespace}.view",
                    "controlId": "idAppControl",
                    "controlAggregation": "detailPages",
                    "bypassed": {
                        "target": ["master", "notFound"]
                    }
                },
                "routes": [
                    {
                        "pattern": "",
                        "name": "master",
                        "target": ["detail", "master"]
                    },
                    {
                        "pattern": "detail/{detailId}",
                        "name": "detail",
                        "target": ["master", "detail"]
                    }
                ],
                "targets": {
                    "master": {
                        "viewName": "Master",
                        "viewLevel": 1,
                        "viewId": "master",
                        "controlAggregation": "masterPages"
                    },
                    "detail": {
                        "viewName": "Detail",
                        "viewId": "detail",
                        "viewLevel": 2
                    },
                    "notFound": {
                        "viewName": "NotFound",
                        "viewId": "notFound",
                        "viewLevel": 3
                    }
                }
            }
        },
        init: function () {
            var mConfig = this.getMetadata().getConfig();
            // set the internationalization model
            this.setModel(new ResourceModel({
                bundleName: mConfig.i18nBundle
            }), "i18n");
            // call the base component's init function and create the App view
            UIComponent.prototype.init.apply(this, arguments);
            // create the views based on the url/hash
            this.getRouter().initialize();
        },
        destroy: function () {
            // call the base component's destroy function
            UIComponent.prototype.destroy.apply(this, arguments);
        }
    });
});


This is a component file template for a master-detail application.

In the Component the App View is referenced as rootView. For master-detail application the SplitApp is used, let’s create another File Template „UI5 SplitApp“ (extension: view.xml) for this:

Template NameExtension
UI5 SplitAppview.xml


<mvc:View
        controllerName="ui5v128.controller.App"
        xmlns="sap.m"
        xmlns:mvc="sap.ui.core.mvc">
    <SplitApp id="idAppControl" displayBlock="true"/>
</mvc:View>


And finally we create a index.html file for local testing:


UI5 index.html Template

Template NameExtension
UI5 index.htmlhtml



<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta charset="UTF-8">
    <title>UI5 App</title>
    <script id="sap-ui-bootstrap"
            src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
            data-sap-ui-libs="sap.m"
            data-sap-ui-theme="sap_bluecrystal"
            data-sap-ui-preload="async"
            data-sap-ui-compatVersion="edge"
            data-sap-ui-resourceroots='{"${UI5_Namespace}": "./"}'
            data-sap-ui-frameOptions='allow'>    // NON-SECURE setting for testing environment
    </script>
    <script>
        sap.ui.getCore().attachInit(function () {
            sap.ui.require([
                "sap/ui/core/ComponentContainer",
                "${UI5_Namespace}/Component"
            ], function (ComponentContainer, Component) {
                new sap.ui.core.ComponentContainer({
                    name: "${UI5_Namespace}"
                }).placeAt('root');
            });
        });
    </script>
</head>
<body class="sapUiBody" id="root">
</body>
</html>


This is an example how to use sap.ui.require and load necessary dependencies. The structure is somehow identically to the sap.ui.require usage. In the first parameter (array of strings) the necessary dependencies are listed, which are passed as parameters to the callback function.


Now we ready to go and create a custom Fiori application.


And Action – Create App with File Templates


Now we want to use the new file templates within WebStorm (of course you can use these templates also without WebStorm)

Create an empty project and two folders (the given templates assume this kind of directory structure):

  • controller – for controller files
  • view – for view files

We want to create a master view and a detail view.

Therefore select the view folder and right-click and select New and select the UI5 XML View template:

Enter as File name „Master“ and as UI5 namespace „ui5v128″ (you can also use your own namespace):

For the controller select controller folder and and right-click and select New and select the UI5 Controller template. Enter again as File name „Master“ and as UI5 namespace „ui5v128″:

Repeat this for the Detail view/controller (File Name „Detail“,UI5 namespace „ui5v128″).

Additionally we will need the SplitApp View. Please name it „App“ and select the „UI5 SplitApp“ Template (again UI5 namespace „ui5v128″).

If you follow this convention the given UI5 Component template will fit, this is is our last step.

Create a UI5 Component (file name: Component) and index.html file (file name index) in the project root folder, both with the same UI5 namespace „ui5v128″. The result should look like this:

Within WebStorm you can directly run the App via the index.html file. Right-click the index.html and select Run ‚index.html‘:

The working app is more or less empty, but uses the new module structure. So you prepared for the future (v1.30) and now it is up to you to fill it with more content.

Have fun with SAPUI5 and AMD concept and migrating Fiori Apps.

Additional Information

3 Comments
Labels in this area