Skip to Content
Technical Articles
Author's profile photo Oblomov Dev

abap2UI5 – (5/7) Extensions with XML Views, HTML, JS & Custom Controls

Welcome to part five of this blog series introducing abap2UI5 — an open-source project for developing standalone UI5 apps in pure ABAP.

This post explains various ways of creating views and enhancing them with Custom Controls, HTML, CSS, JavaScript and third-party libraries.

Find all the information about the project on GitHub and stay up-to-date by following on Twitter.

Blog Series

(1/7) Introduction: Developing UI5 Apps in pure ABAP
(2/7) Displaying Selection Screens & Tables
(3/7) Popups, F4-Help, Messages & Controller Logic
(4/7) Advanced Functionality & Demonstrations
(5/7) Extensions with XML Views, HTML, JS & Custom Controls (this blog post)
(6/7) Installation, Configuration & Debugging
(7/7) Technical Background: Under the Hood of abap2UI5

There are different ways to create views in abap2UI5. To compare each way, we will begin by creating a simple view that includes an input field and a button, and then compare the creation processes. This is how the view looks like:


View created in three different ways

1. View Class Way

First, we will create the view using the method explained in previous blog posts and use the class z2ui5_cl_xml_view. The code for creating the view looks like this:

              title          = 'abap2UI5 - NORMAL NORMAL NORMAL'
              navbuttonpress = client->_event( 'BACK' )
              shownavbutton  = abap_true
                  text = 'Source_Code'
                  href = z2ui5_cl_xml_view_helper=>hlp_get_source_code_url( app = me get = client->get( ) )
                  target = '_blank'
          )->simple_form( 'Form Title'
              )->content( 'form'
                  )->title( 'Input'
                  )->label( 'quantity'
                  )->input( client->_bind( quantity )
                      text  = 'NORMAL'
                      press = client->_event( 'NORMAL' )
                      text  = 'GENERIC'
                      press = client->_event( 'GENERIC' )
                      text  = 'XML'
                      press = client->_event( 'XML' ) ).

The class z2ui5_cl_xml_view provides ABAP-typed methods for creating UI5 controls. The class acts as an ABAP-typed proxy for the SAPUI5 Library and as an result only contains repetitive code with no extra logic:


This class stores all control information in a tree structure and ultimately generates a stringified XML view based on that structure. This class is continuously updated with additional controls. If there is a control that you would like to use that is not currently part of the class, you can open an issue or add it by yourself and submit a pull request on GitHub that it becomes available for everyone to use.

Notably, every method in the class calls the generic method _generic to save the control information. As a result, we can skip the first step and call this generic method directly. This will be the second approach for generating a view for abap2UI5, which we will explore now.

2. View Class Generic Way

To use a control that is not included in the view class, we can also use the method ‘_generic’. The generic approach for the above example looks as follows:

lo_view->_generic( 'Shell' )->_generic(
       name      = `Page`
       t_prop = VALUE #(
           ( n = `title`          v = 'abap2UI5 - GENERIC GENERIC GENERIC' )
           ( n = `showNavButton`  v = `true` )
           ( n = `navButtonPress` v = client->_event( 'BACK' ) ) )
            name = `SimpleForm`
            ns   = `form`
            t_prop = VALUE #(
                ( n = `title` v = 'title' )
       ) )->_generic(
            name = `content`
            ns   = `form`
            name = `Label`
            t_prop = VALUE #(
                ( n = `text` v = 'quantity' )
       ) )->get_parent( )->_generic(
            name = `Input`
            t_prop = VALUE #(
                ( n = `value` v = client->_bind( quantity ) )
       ) )->get_parent(
            name = `Button`
            t_prop = VALUE #(
                ( n = `text`  v = `NORMAL` )
                ( n = `press` v = client->_event( 'NORMAL' ) ) )
            name = `Button`
            t_prop = VALUE #(
                ( n = `text`  v = `GENERIC` )
                ( n = `press` v = client->_event( 'GENERIC' ) ) )
            name = `Button`
            t_prop = VALUE #(
                ( n = `text`  v = `XML` )
                ( n = `press` v = client->_event( 'XML' ) ) ) ).

If you wish to use different namespaces, you have the option to modify them in the call of the factory method. The default namespaces are as follows:

Default namespaces of the abap2UI5 view class

This generic approach allows us to generate any control, but it requires more code to be written and we lose the benefits of typed interfaces that make the first approach more convenient to use.

Now, let us examine how the view output is ultimately provided to abap2UI5. The view class creates the UI5 view and outputs it as a string, which is then received by abap2UI5 as a ready-to-use UI5-XML-View:

client->set_next( value #( xml_main = page->get_root( )->xml_get( ) ) ).

That means abap2UI5 is not involved in the creation of the views. It operates entirely independently of the view class and just receives the result and sends it to the frontend as it is.

Therefore you also have the freedom to build your own view class or encapsulate the existing one in a way that better fits your needs. The provided view class is just a suggestion but there might be better solutions for the view creation process. Keeping this in mind, we can now also bypass the z2ui5_cl_cml_view class and use XML directly, which will be the next approach we will focus on.

3. Pure XML Way

Now we copy the XML view directly into ABAP as a string and replace the event handler and data binding. The previous example in XML looks like this:

    data(lv_xml) = `<mvc:View controllerName="zzdummy" displayBlock="true" height="100%" xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout" xmlns:html="" xmlns:f="sap.ui.layout.form" xmlns:mvc="` &&
`re.mvc" xmlns:editor="sap.ui.codeeditor" xmlns:ui="sap.ui.table" xmlns="sap.m" xmlns:uxap="sap.uxap" xmlns:mchart="sap.suite.ui.microchart" xmlns:z2ui5="z2ui5" xmlns:webc="sap.ui.webc.main" xmlns:text="sap.ui.richtexteditor" > <Shell> <Page ` && |\n|
                          `  title="abap2UI5 - XML XML XML" ` && |\n|  &&
                          `  showNavButton="true" ` && |\n|  &&
                          `  navButtonPress="` &&  client->_event( 'BACK' ) && `" ` && |\n|  &&
                          ` > <headerContent ` && |\n|  &&
                          ` > <Link ` && |\n|  &&
                          `  text="Source_Code" ` && |\n|  &&
                          `  target="_blank" ` && |\n|  &&
                          `  href="<system>sap/bc/adt/oo/classes/Z2UI5_CL_APP_DEMO_23/source/main" ` && |\n|  &&
                          ` /></headerContent> <f:SimpleForm ` && |\n|  &&
                          `  title="Form Title" ` && |\n|  &&
                          ` > <f:content ` && |\n|  &&
                          ` > <Title ` && |\n|  &&
                          `  text="Input" ` && |\n|  &&
                          ` /> <Label ` && |\n|  &&
                          `  text="quantity" ` && |\n|  &&
                          ` /> <Input ` && |\n|  &&
                          `  value="` &&  client->_bind( quantity ) && `" ` && |\n|  &&
                          ` /> <Button ` && |\n|  &&
                          `  press="` &&  client->_event( 'NORMAL' ) && `"`  && |\n|  &&
                          `  text="NORMAL" ` && |\n|  &&
                          ` /> <Button ` && |\n|  &&
                              `  press="` &&  client->_event( 'GENERIC' ) && `"`  && |\n|  &&
                          `  text="GENERIC" ` && |\n|  &&
                          ` /> <Button ` && |\n|  &&
                             `  press="` &&  client->_event( 'XML' ) && `"`  && |\n|  &&
                          `  text="XML" ` && |\n|  &&
                          ` /></f:content></f:SimpleForm></Page></Shell></mvc:View>`.

abap2UI5 takes the XML view as it is (only changing the controller method) and sends it to the frontend. The following demonstration showcases the three approaches in action. Each time, the view remains the same, but it is created using a different method:


App with views created in three different ways

Check out the source code here. The XML approach may appear unconventional and could potentially be difficult to maintain. However, it is a speedy way to create prototypes, as this approach enables us to copy and paste any code snippets from the SAPUI5 Library. Here is an example of how to copy the generic tile example of the UI5 API to abap2UI5:


Copy View of the Documentation and run it with abap2UI5

And here we add a popup using the same method:


Copy Popup of the UI5 Documentation and run it with abap2UI5

We add interaction by replacing the event handler with the abap2UI5 event handler:

  `<Button text="BACK" type="Emphasized" press="` && client->_event( 'BACK') && `"/>`

We add data transfer by replacing the data binding with the abap2UI5 binding:

 ` <Input id="loadingMinSeconds" width="8rem" type="Number" description="seconds" value="` && client->_bind( mv_value ) && `"/>`

Within minutes, we can create a fully functional prototype with event handling and data transfer:


UI5-XML-View in abap2UI5 with Events and Data Transfer

Check out the source code of the app here.

Although the video makes it seem easy, it is important to exercise caution when using this approach. You are now fully responsible for everything. abap2UI5 simply sends it as is to the frontend, so you must ensure that the namespace is correct, libraries can be loaded, images are displayed properly and so on. This approach provides flexibility, but also comes with the potential for problems to occur.

If you need to make corrections, you can activate logging, and the XML view output will be written to the console of your browser. From there, you can copy it, make adjustments and copy it back to the ABAP class:


Console Output of the UI5-XML-View

A great way to create views is to use sandboxes, for example use the OpenUI5 Sandbox:

OpenUI5 SandBox

After we now got full control of the view creation process, we can go one step further and add native HTML, CSS, and JS.

4. HTML, CSS & JavaScript

UI5 provides the ability to use native HTML in XML Views. You can refer to this documentation for more information. A simple example of HTML output in XML Views looks like this:

Native HTML and CSS in abap2UI5

Here is the XML view in ABAP for the above example (and a more readable version):

    app-next-xml_main = `<mvc:View controllerName="project1.controller.View1"` && |\n|  &&
                          `    xmlns:mvc="sap.ui.core.mvc" displayBlock="true"` && |\n|  &&
                          `  xmlns:z2ui5="z2ui5"  xmlns:m="sap.m" xmlns=""` && |\n|  &&
                          `    ><m:Button ` && |\n|  &&
                          `  text="back" ` && |\n|  &&
                          `  press="` && client->_event( 'BACK' ) && `" ` && |\n|  &&
                          `  class="sapUiContentPadding sapUiResponsivePadding--content"/> ` && |\n|  &&
                   `       <m:Link target="_blank" text="Source_Code" href="` && z2ui5_cl_xml_view_helper=>hlp_get_source_code_url( app = me get = client->get( ) ) && `"/>` && |\n|  &&
                          `<html><head><style>` && |\n|  &&
                          `body {background-color: powderblue;}` && |\n|  &&
                          `h1   {color: blue;}` && |\n|  &&
                          `p    {color: red;}` && |\n|  &&
                          `</style>` &&
                          `</head>` && |\n|  &&
                          `<body>` && |\n|  &&
                          `<h1>This is a heading with css</h1>` && |\n|  &&
                          `<p>This is a paragraph with css.</p>` && |\n|  &&
                          `<h1>My First JavaScript</h1>` && |\n|  &&
                          `<button type="button">send</button>` && |\n|  &&
                          `<Input id='input' value='frontend data' /> ` &&
                          `</body>` && |\n|  &&
                          `</html> ` && |\n|  &&
<mvc:View controllerName="z2ui5_controller"
	xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
  press="onEvent( { 'EVENT' : 'BACK', 'METHOD' : 'UPDATE' } )" 
  class="sapUiContentPadding sapUiResponsivePadding--content"/>
	<m:Link target="_blank" text="Source_Code" href=""/>
body {background-color: powderblue;}
h1   {color: blue;}
p    {color: red;}
			<h1>This is a heading with css</h1>
			<p>This is a paragraph with css.</p>
			<h1>My First JavaScript</h1>
			<button type="button">send</button>
			<Input id='input' value='frontend data' />

To enable interaction and data transfer, we add JavaScript to the XML view:

  app-next-xml_main = `<mvc:View controllerName="project1.controller.View1"` && |\n|  &&
                          `    xmlns:mvc="sap.ui.core.mvc" displayBlock="true"` && |\n|  &&
                          `  xmlns:z2ui5="z2ui5"  xmlns:m="sap.m" xmlns=""` && |\n|  &&
                          `    ><m:Button ` && |\n|  &&
                          `  text="back" ` && |\n|  &&
                          `  press="` && client->_event( 'BACK' ) && `" ` && |\n|  &&
                          `  class="sapUiContentPadding sapUiResponsivePadding--content"/> ` && |\n|  &&
                   `       <m:Link target="_blank" text="Source_Code" href="` && z2ui5_cl_xml_view_helper=>hlp_get_source_code_url( app = me get = client->get( ) ) && `"/>` && |\n|  &&
                          `<html><head><style>` && |\n|  &&
                          `body {background-color: powderblue;}` && |\n|  &&
                          `h1   {color: blue;}` && |\n|  &&
                          `p    {color: red;}` && |\n|  &&
                          `</style>` &&
                          `</head>` && |\n|  &&
                          `<body>` && |\n|  &&
                          `<h1>This is a heading with css</h1>` && |\n|  &&
                          `<p>This is a paragraph with css.</p>` && |\n|  &&
                          `<h1>My First JavaScript</h1>` && |\n|  &&
                          `<button onclick="myFunction()" type="button">send</button>` && |\n|  &&
                          `<Input id='input' value='frontend data' /> ` &&
                          `<script> function myFunction( ) { sap.z2ui5.oView.getController().onEvent({ 'EVENT' : 'POST', 'METHOD' : 'UPDATE' }, document.getElementById(sap.z2ui5.oView.createId( "input" )).value ) } </script>` && |\n|  &&
                          `</body>` && |\n|  &&
                          `</html> ` && |\n|  &&

Finally, we have a working frontend application that uses events and data transfer to the backend with HTML, CSS and JS:


HTML, CSS and JavaScript in abap2UI5

Here we create the server roundtrip with abap2UI5 and use the second parameter of the event method to transfer data to the backend:

sap.z2ui5.oView.getController().onEvent({ 'EVENT' : 'POST', 'METHOD' : 'UPDATE' }, document.getElementById(sap.z2ui5.oView.createId( "input" )).value ) 

Then in the backend the data can be found in the following parameter:

client->popup_message_toast( app-get-event_data ).

The value of ‘app-get-event_data’ can also be filled with a stringified JSON, which provides a generic approach for sending data to the backend without requiring changes to the HTTP handler. Take a look at the full source code of the app here.

This approach provides a lot of freedom, but it also requires you to manage JavaScript, CSS, and HTML within your normal ABAP code. Good wrappers can be helpful, but it’s worth considering whether it would be better to create a regular frontend app instead. Additionally, the code in this example isn’t considered good practice because we’re calling UI5 from the outside, using global variables etc. So, consider it only as an example to see what is possible, and not as a coding guideline to follow.

Example – Canvas & SVG

We can now use this approach for functionalities that are not normally within the scope of UI5. For example, we can use canvas and SVG:


Canvas and SVG in abap2UI5

You can find the source code here.

Example – Include third-party Libraries

Or including third-party open-source libraries — for example use JSBarcode to display barcodes:


JSBarcode in abap2UI5

The source code of the app is here.

With this approach, it is also possible to include additional libraries in the future to, for example, display QR codes, use barcode scanning with the camera, utilize localization or leverage other device capabilities. Per default to prevent cross-side-scripting loading third party libraries is not allowed. So if you include other external libraries, make also sure to adjust the csp meta tag as described at security here.

Now let’s move on to the final part of this blog post and take a look at UI5 custom controls, which are a way to encapsulate HTML CSS, and JS for the use with UI5.

5. Custom Control Way

Custom controls are the recommended way to build extensions in UI5. A simple example with a button and data transfer looks like this:


Custom Control in abap2UI5

The source code is here. JavaScript of the custom control looks like this:

sap.ui.define( [
    ], function (Control) {
        "use strict";
        return Control.extend("z2ui5.MyCC", {
            metadata: {
                properties: {
                    value: { type: "string" }
                events: {
                    "change": {
                        allowPreventDefault: true,
                        parameters: {}
            renderer: function (oRm, oControl) {
                oControl.oInput = new sap.m.Input({
                    value: oControl.getProperty("value")
                oControl.oButton = new sap.m.Button({
                    text: 'button text',
                    press: function (oEvent) {
                        this.setProperty("value",  this.oInput.getProperty( 'value')  )

Embedded in abap2UI5 as a string for the XML view:

 `<script>if(!z2ui5.MyCC){"z2ui5.MyCC");` && |\n|  &&
                            `    sap.ui.define( [` && |\n|  &&
                            `        "sap/ui/core/Control",` && |\n|  &&
                            `    ], function (Control) {` && |\n|  &&
                            `        "use strict";` && |\n|  &&
                            `        return Control.extend("z2ui5.MyCC", {` && |\n|  &&
                            `            metadata: {` && |\n|  &&
                            `                properties: {` && |\n|  &&
                            `                    value: { type: "string" }` && |\n|  &&
                            `                },` && |\n|  &&
                            `                events: {` && |\n|  &&
                            `                    "change": {` && |\n|  &&
                            `                        allowPreventDefault: true,` && |\n|  &&
                            `                        parameters: {}` && |\n|  &&
                            `                    }` && |\n|  &&
                            `                }` && |\n|  &&
                            `            },` && |\n|  &&
                            `            renderer: function (oRm, oControl) {` && |\n|  &&
                            `                oControl.oInput = new sap.m.Input({` && |\n|  &&
                            `                    value: oControl.getProperty("value")` && |\n|  &&
                            `                });` && |\n|  &&
                            `                oControl.oButton = new sap.m.Button({` && |\n|  &&
                            `                    text: 'button text',` && |\n|  &&
                            `                    press: function (oEvent) {` && |\n|  &&
                            `                        this.setProperty("value", this.oInput.getProperty( 'value')  )` && |\n|  &&
                            `                        this.fireChange();` && |\n|  &&
                            `                    }.bind(oControl)` && |\n|  &&
                            `                });` && |\n|  &&
                           `                oRm.renderControl(oControl.oInput);` && |\n|  &&
                            `                oRm.renderControl(oControl.oButton);` && |\n|  &&
                            `            }` && |\n|  &&
                            `    });` && |\n|  &&
                            `}); } </script>`

To use the custom control, we need to load its JS snippet before rendering it on a view. Therefore, we send it with the first button click. After that, we can use the custom control in the second and all following requests. The usage of the custom control in abap2UI5 is as follows:

` <z2ui5:MyCC change=" ` && client->_event( 'MYCC' ) && `"  value="` && client->_bind( mv_value ) && `"/>`

The custom control encapsulation makes data transfer very easy. It is integrated into the XML Views and can be easily bound with abap2UI5. In addition, nothing is called from the outside anymore, and we stay completely within the UI5 logic. It becomes even more convenient when we additionally add the custom control to the view class from the beginning. Take a look at this example of how we use the custom control of the file uploader:

     value       = client->_bind( mv_value )
     path        = client->_bind( mv_path )
     placeholder = 'filepath here...'
     upload      = client->_event( 'UPLOAD' ) ).

It has a completely ABAP-typed interface with this. Here is the source code of the app.

The next step would be to enhance this custom control with the JavaScript logic we saw before (such as Canvas, SVG, and third-party libraries).


As we have seen, there are many different ways to create views in abap2UI5, each with its own level of flexibility and maintenance requirements. The view creation process is independent to the rest of abap2UI5, as it simply takes the created view and sends it to the frontend as is. Therefore, each user can choose the method that works best for them.

The view class-based approach is very intuitive and is built on typed ABAP methods. The XML approach, which involves copying and pasting views, is extremely fast for creating prototypes with popups in a short amount of time, but maintaining the views can be challenging later on. The last approaches offer a lot of flexibility, but they require deep knowledge of JS and HTML and essentially use the ABAP source code as a BSP. It’s a question whether frontend development may be better in this case.

The idea behind abap2UI5 is to just provide a basic layer that offers some flow logic (for easy switching between apps) and server-client communication (for creating view models, handling events and transferring data). However, the entire view logic remains outside of the framework. Therefore, the class z2ui5_cl_xml_view is not part of the abap2UI5 core functionality. With this approach abap2UI5 remains small and flexible, suitable for a wide range of use cases.

Feel free to find your best way to create views and extend abap2UI5.


This was part five of this introduction to abap2UI5. You now have an understanding about the different ways of creating views with abap2UI5 and ideas how to extend it with HTML, CSS and JavaScript.

In the next blog post, we will focus on how to install, configure and debug abap2UI5.

Thank you for reading this blog post!

Your questions, comments and wishes for this project are always welcome, create an issue or leave a comment.

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.