Welcome to part 5 of this blog series introducing
abap2UI5 — an open-source project for developing UI5 apps purely in ABAP.
This post explains various ways of creating views and enhancing them with HTML, CSS and JavaScript.
Blog Series & More
You can find all the information about this project on
GitHub, stay up-to-date by following on
Twitter and be sure to explore the other articles of this blog series:
Content
This post covers the following areas:
- Creating UI5 Views in the Backend
- View Class Way
- View Class Generic Way
- Pure XML Way
- HTML, CSS & JavaScript
- Canvas & SVG
- External Libraries
- Additional Comments
- Conclusion
Let’s begin with the first topic.
1. Creating UI5 Views in the Backend
There are various methods for creating views in abap2UI5. To illustrate, we will create a simple view consisting of an input field and a button, comparing different creation processes. Here's how the view looks:
View created in three different ways
1.1. View Class Way
We'll start by creating the view using the method detailed in previous blog posts, utilizing the class z2ui5_cl_xml_view. Here's an example of the code for creating the view:
lo_view->shell(
)->page(
title = 'abap2UI5 - NORMAL NORMAL NORMAL'
navbuttonpress = client->_event( 'BACK' )
shownavbutton = abap_true
)->header_content(
)->link(
text = 'Source_Code'
href = z2ui5_cl_xml_view_helper=>hlp_get_source_code_url( app = me get = client->get( ) )
target = '_blank'
)->get_parent(
)->simple_form( 'Form Title'
)->content( 'form'
)->title( 'Input'
)->label( 'quantity'
)->input( client->_bind( quantity )
)->button(
text = 'NORMAL'
press = client->_event( 'NORMAL' )
)->button(
text = 'GENERIC'
press = client->_event( 'GENERIC' )
)->button(
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 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.
1.2. View Class Generic Way
To use a control that is not included in the view class, we can also use the method '_generic'. This approach, while offering flexibility, requires more code and forgoes the benefits of typed interfaces. Here's an example:
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' ) ) )
)->_generic(
name = `SimpleForm`
ns = `form`
t_prop = VALUE #(
( n = `title` v = 'title' )
) )->_generic(
name = `content`
ns = `form`
)->_generic(
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(
)->_generic(
name = `Button`
t_prop = VALUE #(
( n = `text` v = `NORMAL` )
( n = `press` v = client->_event( 'NORMAL' ) ) )
)->get_parent(
)->_generic(
name = `Button`
t_prop = VALUE #(
( n = `text` v = `GENERIC` )
( n = `press` v = client->_event( 'GENERIC' ) ) )
)->get_parent(
)->_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->view_display( page->stringify( ) ).
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.
1.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="http://www.w3.org/1999/xhtml" xmlns:f="sap.ui.layout.form" xmlns:mvc="sap.ui.co` &&
`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 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:
Copying Views of the Documentation and Run it with abap2UI5
And here we add a popup using the same method:
Copying Popups of the UI5 Documentation and run it with abap2UI5
We add interaction by replacing the event handler with the abap2UI5 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_edit( 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.
2. Using 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="http://www.w3.org/1999/xhtml"` && |\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=>factory( client )->hlp_get_source_code_url( ) && `"/>` && |\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>`.
|
<mvc:View controllerName="z2ui5_controller"
xmlns:mvc="sap.ui.core.mvc" displayBlock="true"
xmlns:z2ui5="z2ui5"
xmlns:m="sap.m"
xmlns="http://www.w3.org/1999/xhtml"
>
<m:Button
text="back"
press="onEvent( { 'EVENT' : 'BACK', 'METHOD' : 'UPDATE' } )"
class="sapUiContentPadding sapUiResponsivePadding--content"/>
<m:Link target="_blank" text="Source_Code" href="<<system>>m/sap/bc/adt/oo/classes/Z2UI5_CL_APP_DEMO_32/source/main"/>
<html>
<head>
<style>
body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}
</style>
</head>
<body>
<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' />
</body>
</html>
</mvc:View>
|
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="http://www.w3.org/1999/xhtml"` && |\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| &&
`</mvc:View>`.
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( client->get( )-t_args[ 1 ] ).
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.
3. 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.
4. External 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 method, you can also incorporate additional libraries in the future for various functionalities, such as displaying QR codes, using barcode scanning with the camera, employing localization techniques, or utilizing other device capabilities.
Update 15.12.2023: Over the recent months, more external libraries have been integrated into abap2UI5. For more detailed information, please refer to part 10 of this series. |
5. Additional Comments
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 & handling events) and server-client communication (for creating models & transferring data). However, the entire view logic remains separated of the framework. Therefore, the class z2ui5_cl_xml_view is just loosely coupled to 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.
Update 15.12.2023: We have explored now various methods for integrating JavaScript into abap2UI5, but have not yet addressed the best practices for encapsulating this code. This topic will be covered in part 11, where we will focus on the development of Custom Controls for the integration of JavaScript for the use with abap2UI5. |
6. Conclusion
This concludes part five of this introduction to
abap2UI5. You now have an understanding about the various methods of creating views in the backend and ideas how to extend it with HTML, CSS and JavaScript.
In the
next part, we will focus on how to install, configure and debug abap2UI5.
Thank you for reading! Your questions, comments and wishes for this project are always welcome, create an
issue or leave a comment.