This blog series introduces the abap2UI5 Project. It is an open source project which helps you develop standalone UI5 applications in pure ABAP. All project information can be found here:

Repository on GitHub

News on Twitter

General Idea

Abap2UI5 gives you a cloud/on-premise ready and non-sap-gui way to create UI5 apps in pure ABAP without using OData, Javascript, Annotations or RAP – just like in the “old days” when we just needed a few lines of ABAP code to display tables and inputs with the CL_GUI_ALV_GRID and the CL_GUI_CFW framework.

Features

  • easy to use – implement just one interface for a standalone UI5 application
  • pure ABAP – development in 100% ABAP source code (no JavaScript, EML, DDL or Customizing)
  • small system footprint – based on a plain http handler (no OData, SEGW, BOPF, BSP, RAP or FE)
  • cloud and on-premise ready – works with both language versions (ABAP for Cloud, Standard ABAP)
  • high system compatibility – runs on all available ABAP stacks (NW 7.02 to ABAP 2302)
  • easy installation – abapGit project, no additional app deployment needed

Works with all available ABAP stacks and language versions

  • BTP ABAP Environment (ABAP for Cloud)
  • S/4 Public Cloud ABAP Environment (ABAP for Cloud)
  • S/4 Private Cloud or On-Premise (ABAP for Cloud, Standard ABAP)
  • R/3 NetWeaver AS ABAP 7.50 or higher (Standard ABAP)
  • R/3 NetWeaver AS ABAP 7.02 to 7.40 (Standard ABAP) – use the low syntax branch

Blog Series

(1/3) abap2UI5 – Development of UI5 Apps in pure ABAP (this blog post) This blog post focuses on how we can use ABAP2UI5 to develop applications in general
(2/3) abap2UI5 – Lists, Tables, Toolbar and editable Examples to display lists and tables with an ABAP2UI5 application are explained here.
(3/3) abap2UI5 – Demo apps (coming soon) Some full working demo apps are introduced in this blog post.

If you are interested in the technical background, take a look at this first blog post: abap2UI5 – Development of UI5 Selection Screens in pure ABAP

Demo

For a first impression of abap2UI5, take a look to this demo – everything is created in the backend in pure ABAP. No additional app deployment or javascript is needed:

An example application looks like this:

CLASS z2ui5_cl_app_demo_01 DEFINITION PUBLIC.

  PUBLIC SECTION.

    INTERFACES z2ui5_if_app.

    DATA product TYPE string.
    DATA quantity TYPE string.

ENDCLASS.

CLASS Z2UI5_CL_APP_DEMO_01 IMPLEMENTATION.

  METHOD z2ui5_if_app~controller.

    CASE client->get( )-lifecycle_method.

      WHEN client->cs-lifecycle_method-on_init.
        product = 'tomato'.
        quantity = '500'.

      WHEN client->cs-lifecycle_method-on_event.

        CASE client->get( )-event.

          WHEN 'BUTTON_POST'.
            client->display_message_toast( |{ product } { quantity } ST - GR successful| ).

        ENDCASE.

      WHEN client->cs-lifecycle_method-on_rendering.

        DATA(view) = client->factory_view( ).

        view->page( title = 'Page title'
           )->simple_form('Form Title'
             )->content( 'f'
                )->title( 'Input'
                )->label( 'quantity'
                )->input( view->_bind( quantity )
                )->label( 'product'
                )->input( value = product editable = abap_False
                )->button( text = 'post' press = view->_event( 'BUTTON_POST' ) ).

    ENDCASE.
  ENDMETHOD.
ENDCLASS.

The other code examples can be found here:

Selection-Screen / Messages / List

As you can see, the only thing you have to do to develop an UI5 app with abap2UI5 is to create a new class implementing the following interface:

INTERFACE z2ui5_if_app
  PUBLIC .

  INTERFACES if_serializable_object.

  METHODS controller
    IMPORTING
      client TYPE REF TO z2ui5_if_client.

ENDINTERFACE.

Let’s go through the development process step by step starting with the controller:

Development with ABAP2UI5

Controller

The interface Z2UI5_IF_APP provides the method “controller,” which gives you the control of the frontend UI5 app similar to a Javascript controller of an UI5 freestyle application. Therefore they look very similar:

UI5-Controller vs. abap2UI5-Controller
sap.ui.controller("sap.ui.myApp.controller.one", {

	onInit: function() {

	},

	onBeforeRendering: function() {
		 
	},

	onEvent: function() {
	//button event handling here
	},

	onAfterRendering: function() {
		
	},

	onExit: function() {

	}
	
});
METHOD z2ui5_if_app~controller.

    CASE client->get( )-lifecycle_method.

      WHEN client->cs-lifecycle_method-on_init.
       "set initial values....

      WHEN client->cs-lifecycle_method-on_event.
        "event handling....

      WHEN client->cs-lifecycle_method-on_rendering.
        DATA(view) = client->factory_view( ).
        "rendering here....

    ENDCASE.

ENDMETHOD.

The abap2UI5 controller has three lifecycle events. The path on_init is called when an app is started, the path on_rendering is called after every server request when the view is rendered and the path on_event when an UI5 event is raised.

Of course when everything is handled in one method this is not the idea of clean code, but abap2UI5 does not want to make any requirements on how apps are structured. So this method is the basic layer and then every users can implement different methods on top of this by themselves. Maybe one for init, one for user_commands etc.

View

ABAP2UI5 provides the possibility to develop UI5 Views similar to an UI5 freestyle application. The only difference is that views are not defined in XML, instead they are created with the abap2UI5 view class. With this the user has complete freedom in structuring the view and also the flexibility to use a lot of different UI5 controls. A simple example (compared to a normal UI5 View) looks like this:

Example 1

UI5-View vs. abap2UI5-View
<Page title="Page title" showNavButton="true" navButtonTap="onEvent" >
	<f:SimpleForm title="Form Title">
		<f:content>
			<Title text="Input" />
			<Label text="quantity"/>
			<Input editable="true" value="{/oUpdate/QUANTITY}"/>
			<Label text="product" />
			<Input value="tomato" />
			<Button press="onEvent" text="post" enabled="true"/>
		</f:content>
	</f:SimpleForm>
</Page>
view->page( title = 'Page title' nav_button_tap = view->_event_display_id( client->get( )-id_prev_app )
        )->simple_form('Form Title'
          )->content( 'f'
             )->title( 'Input'
             )->label( 'quantity'
             )->input( view->_bind( quantity )
             )->label( 'product'
             )->input( value = product editable = abap_False
             )->button( text = 'post' press = view->_event( 'BUTTON_POST' ) ).

And a more detailed example looks like this:

Example 2

UI5-View vs. abap2UI5-View
<Page title="Example - ZZ2UI5_CL_APP_DEMO_02" showNavButton="true" navButtonTap="onEvent">
	<l:Grid defaultSpan="L6 M12 S12" class="sapUiSmallMarginTop">
		<l:content>
			<f:SimpleForm title="Input">
				<f:content>
					<Label text="Input with value help" />
					<Input placeholder="fill in your favorite colour" showClearIcon="false" editable="true" value="{/oUpdate/SCREEN-COLOUR}" suggestionItems="{/MT_SUGGESTION}" showSuggestion="true">
						<suggestionItems>
							<core:ListItem text="{VALUE}" additionalText="{DESCR}" />
						</suggestionItems>
					</Input>
				</f:content>
			</f:SimpleForm>
			<f:SimpleForm title="Time Inputs" editable="true">
				<f:content>
					<Label text="Date" />
					<DatePicker value="{/oUpdate/SCREEN-DATE}" />
					<Label text="Date and Time" />
					<DateTimePicker value="{/oUpdate/SCREEN-DATE_TIME}" />
					<Label text="Time Begin/End" />
					<TimePicker value="{/oUpdate/SCREEN-TIME_START}" />
					<TimePicker value="{/oUpdate/SCREEN-TIME_END}" />
				</f:content>
			</f:SimpleForm>
		</l:content>
	</l:Grid>
	<l:Grid defaultSpan="L12 M12 S12" class="sapUiSmallMarginTop">
		<l:content>
			<f:SimpleForm title="Input with select options" editable="true">
				<f:content>
					<Label text="Checkbox" />
					<CheckBox text="this is a checkbox" selected="{/oUpdate/SCREEN-CHECK_IS_ACTIVE}" enabled="true" />
					<Label text="Combobox" />
					<ComboBox showClearIcon="false" selectedKey="{/oUpdate/SCREEN-COMBO_KEY}" items="{/1}">
						<core:Item key="{KEY}" text="{TEXT}" />
					</ComboBox>
				</f:content>
				<Label text="Segmented Button" />
				<SegmentedButton selectedKey="{/oUpdate/SCREEN-SEGMENT_KEY}">
					<items>
						<SegmentedButtonItem icon="sap-icon://accept" key="BLUE" text="blue" />
						<SegmentedButtonItem icon="sap-icon://add-favorite" key="GREEN" text="green" />
						<SegmentedButtonItem icon="sap-icon://attachment" key="BLACK" text="black" />
					</items>
				</SegmentedButton>
				<Label text="Switch disabled" />
				<Switch type="Default" enabled="false" state="/2" customTextOff="B" customTextOn="A" />
				<Label text="Switch accept/reject" />
				<Switch type="AcceptReject" enabled="true" state="/oUpdate/SCREEN-CHECK_SWITCH_01" customTextOff="off" customTextOn="on" />
				<Label text="Switch normal" />
				<Switch type="Default" enabled="true" state="/oUpdate/SCREEN-CHECK_SWITCH_02" customTextOff="NO" customTextOn="YES" />
			</f:SimpleForm>
		</l:content>
	</l:Grid>
	<footer>
		<OverflowToolbar>
			<Link text="Go to Source Code" target="_blank" href="" enabled="true" />
			<ToolbarSpacer />
			<Button press="onEvent" text="Clear" enabled="true" icon="sap-icon://delete" type="Reject" />
			<Button press="onEvent" text="Send to Server" enabled="true" type="Success" />
		</OverflowToolbar>
	</footer>
</Page>
DATA(page) = view->page( title = 'Example - ZZ2UI5_CL_APP_DEMO_02' nav_button_tap = view->_event_display_id( client->get( )-id_prev_app ) ).

DATA(grid) = page->grid( 'L6 M12 S12' )->content( 'l' ).

grid->simple_form('Input' )->content( 'f'
        )->label( 'Input with value help'
        )->input(
            value       = view->_bind( screen-colour )
            placeholder = 'fill in your favorite colour'
            suggestion_items = view->_bind_one_way( mt_suggestion ) )->get(
            )->suggestion_items( )->get(
                )->list_item( text = '{VALUE}' additional_text = '{DESCR}' ).

grid->simple_form('Time Inputs' )->content( 'f'
        )->label( 'Date'
        )->date_picker( view->_bind( screen-date )

        )->label( 'Date and Time'
        )->date_time_picker( view->_bind( screen-date_time )

        )->label( 'Time Begin/End'
        )->time_picker( view->_bind( screen-time_start )
        )->time_picker( view->_bind( screen-time_end ) ).

page->grid( default_span  = 'L12 M12 S12' )->content( 'l'
       )->simple_form('Input with select options' )->content( 'f'

    )->label( 'Checkbox'
    )->checkbox(
         selected = view->_bind( screen-check_is_active )
         text     = 'this is a checkbox'
         enabled  = abap_true

    )->label( 'Combobox'
    )->combobox(
         selectedkey = view->_bind( screen-combo_key )
         items      = view->_bind_one_way( VALUE ty_t_combo(
             ( key = 'BLUE'  text = 'green' )
             ( key = 'GREEN' text = 'blue'  )
             ( key = 'BLACK' text = 'red'   )
             ( key = 'GRAY'  text = 'gray'  ) )
         ) )->get( )->item( key = '{KEY}' text = '{TEXT}'
        )->get_parent( )->get_parent(

    )->label( 'Segmented Button'
    )->segmented_button( view->_bind( screen-segment_key ) )->get(
        )->items( )->get(
             )->segmented_button_item( key = 'BLUE'  icon = 'sap-icon://accept'       text = 'blue'
             )->segmented_button_item( key = 'GREEN' icon = 'sap-icon://add-favorite' text = 'green'
             )->segmented_button_item( key = 'BLACK' icon = 'sap-icon://attachment'   text = 'black'
       )->get_parent( )->get_parent(

    )->label( 'Switch disabled'
    )->switch( enabled = abap_false    customtexton = 'A' customtextoff = 'B'
    )->label( 'Switch accept/reject'
    )->switch( state = screen-check_switch_01 customtexton = 'on'  customtextoff = 'off' type = 'AcceptReject'
    )->label( 'Switch normal'
    )->switch( state = screen-check_switch_02 customtexton = 'YES' customtextoff = 'NO' ).

page->footer( )->overflow_toolbar(
         )->link(
             text = 'Go to Source Code'
             href = client->get( )-s_request-url_source_code
         )->toolbar_spacer(
         )->button(
             text  = 'Clear'
             press = view->_event( 'BUTTON_CLEAR' )
             type  = 'Reject'
             icon  = 'sap-icon://delete'
         )->button(
             text  = 'Send to Server'
             press = view->_event( 'BUTTON_SEND' )
             type  = 'Success' ).

In the second example you can see that you need 70 lines of code for a view. Maybe that seems to be a lot for a single view and the generating process is very technical. But again abap2UI5 just wants to provide the basic layer and functionality to create UI5 applications so that the system footprint of abap2UI5 stays very small. Apart from this every user can build useful wrappers around the view rendering.

abap2UI5 Library

At the moment the following UI5 controls are available and more will be added in the future:

Which UI5 controls are working with abap2UI5?

Only controls which do not depend on additional JavaScript logic are working. That means for example we can use the Input control, because it has just attributes, which abap2UI5 can send directly back to the server so we don not need any additional javascript for this. Most of the controls 70-80% work like this and we can use them with abap2UI5 out of the box.

Controls which need an additional JavaScript implementation like the Message Manager are not possible without further effort. But there would be the possibility to build a Custom Control around it and make it controllable by the server and with this a part of abap2UI5. But the question is if these efforts are worth it. In the future it makes sense to take a look on very popular controls, but first abap2UI5 stays simple and skips this.

Events

There are two event methods possible at the moment.

Event

view->( )->button( 
             text = 'post' 
             press = view->_event( 'BUTTON_POST' )
 ).
Most of the times it is sufficent to just send a simple user-command back to the server. For this you can use the method _event( )

Event Display ID

 view->page( 
    title.         = 'Page title' 
    nav_button_tap = view->_event_display_id( 
                               client->get( )-id_prev_app ) 
    ).

 
With this method ABAP2UI5 jumps back to a response with a certain id. For example, this is very helpful when you just want to navigate back after calling a new app. In the section REST and Draft you can see that every request generates a new id and a draft of the actual app status is saved. That gives us the possibility to also jump to every previous state with the method _event_display_id()

If there is the need for more event functions, it is possible to extend ABAP2UI5 in the future.

Model (Data Binding)

There are three possibilities how abap2UI5 sends data to the frontend:

Direct XML

view( )->label( 'product'
      )->input( 
           value    = product 
           editable = abap_false
  ).
         
Just put the value into the attribute, then abap2UI5 writes the value directly into the UI5-XML-View and sends it to the frontend

One-Way-Binding

view->( )->label( 'product'
        )->input( 
            value    = _bind_one_way( product )
            editable = abap_False
   ).
Abap2UI5 writes the value into the View Model and binds the View Model to the XML View. Helpful for deep data models like tables, we will take a look to this in the next blog post

Two-Way-Binding

view( )->label( 'quantity'
      )->input( view->_bind( quantity ) ).
Same as one-way-binding, but in addition the frontend values are send back to the server with every request. So make sure that the value you bind here are public attributes of your app that abap2UI5 can assign it and update the values from outside. This binding mode is useful for inputs or editable tables.

So the user has to decide during the view definition how the data is send to the frontend and if it should be send back or not. To keep the request payload small it is a good idea to use two-way-binding only if it is needed and values are changed at the frontend. It is also recommended not to overload the app with thousands of attributes, because abap2UI5 loops after every request over all attributes of the class and checks if values exists which have to be updated.

REST and Draft

Abap2UI5 is based on REST. No session exists between two HTTP requests. Therefore it is compatible to  mobile use cases and mobile devices. It is also compatible to “restful” environments like BTP ABAP Environment or the new language version ABAP Cloud.

Besides that after every request the actual state of the app is serialized and persisted to the database. The Z2UI5_IF_APP includes the interface IF_SERIALIZABLE_OBJECT, therefore it is possible to use attributes of the app instance between two requests and it feels like working with a stateful application like in a dynpro or selection-screen environment:

The persistence of abap2UI5 is called a draft table, although it is not completely the same as you know from RAP. The abap2UI5 drafts are not type specific, they just persist the app class in a generic way. Therefore there is no extra work in creating typed draft tables, everything works automatic in the background.

The drafts are very helpful for interim results, but maybe don’t exaggerate with this possibility. It is not a good idea to build endless chains of apps saving each other in attributes or try to save millions of entries in internal tables. But of course this is also not a good programming style in general.

Summary

That was the first part of the introduction to the ABAP2UI5 Project. Feel free to install this project and try out the examples and demos.

In the next blog post we will use ABAP2UI5 to send deep data models to the frontend and develop apps displaying lists and tables.

Feel free to install this project and try out the examples and demos. For news and improvements follow this project on Twitter or take a look to the GitHub repository.

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

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x