Skip to Content

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):

UI5FileTemplate1.png

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 Name Extension
UI5 Controller controller.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 Name Extension
UI5 XML View view.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 Name Extension
UI5 Component js

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 Name Extension
UI5 SplitApp view.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 Name Extension
UI5 index.html html



<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

UI5FileTemplate2.png

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:

UI5FileTemplate3.png

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

UI5FileTemplate4.png

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″:

UI5FileTemplate4b.png

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″).

UI5FileTemplate5.png

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:

UI5FileTemplate6.png

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

UI5FileTemplate7.png

UI5FileTemplate8.png

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

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. Pinaki Patra

    Hi,

    really nice blog !.

    Is there any means by which we can port the templates created via web-storm into WEB IDE or Eclipse  .

     

     

    Cheers

    Pinaki Patra

    (0) 
    1. HP Seitz Post author

       

      Hi,

      I’m not aware of any possibility to use such templates within WebIDE, especially with the parameter substituion. But I’m rarely using SAP Web IDE for UI5 development, so this might possibe.

      BR, HP

      (1) 

Leave a Reply