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: 
Former Member

Since the introduction of HTML Islands in Web Dynpro for ABAP (WDA) it's possible to integrate more or less any web-based content. And as FPM is based on WDA, this is valid also for freestyle UIBBs in FPM (see for example the blog

How to use a Java Script Chart Library in Floorplan Manager Applications).This is also valid for UI5 based content. In this blog I want to demonstrate how a UI5 control can be integrated into FPM. I chose the timeline control as example, as WDA doesn't offer such a control. By following this example, you should be able to integrate any other UI5 control as well.

To do this we will:

  1. Create a Freestyle UIBB showing an HTML Island
  2. Add client-side JavaScript code to create and embed the  timeline control in the HTML Island
  3. Expose timeline data from the backend to the client and feed it into the timeline control
  4. Trigger a Web Dynpro Action from the timelines "select" event and inform the backend about the selected item

To understand this blog some basic knowledge in Web Dynpro for ABAP programming and FPM configuration is required. It's a very detailed step-by-step description how to create this freestyle UIBB. I will also explain the necessary JavaScript coding, so that you don't need JavaScript knowledge.

This blog is based on functionality available with Netweaver 7.40.

Create a Freestyle UIBB

First we need to create our new UIBB. To do this we go to transaction SE80 and create a new Web Dynpro component. The name is arbitrary - I will use ZSCN_TIMELINE_UIBB and use W_TIMELINE as window and V_TIMELINE as View name. I will also use an assistance class named ZCL_TIMELINE_ASSIST and Implement the UIBB interface IF_FPM_UI_BUILDING_BLOCK on this component

In the end the component structure should look like this:

To embed and interact the UI5 control we need to add an HTML island to view V_TIMELINE and assign "<div id="mytimeline" style="height:100%"></div>" as value for property "staticHtml".

To make the UI5 timeline control available to this HTML Island we have to add the necessary script accesses: To do this

  • we add a Script Element to the HTML Island and add as source to path to the UI5 core library (which is "/sap/public/bc/ui5_ui5/1/resources/sap-ui-core.js").
  • Then we need to add 2 custom attributes to the Script Element:
    • One with the name "id" and value "sap-ui-bootstrap" and
    • a 2nd with name "data-sap-ui-libs" and value "sap.ui.commons,sap.suite.ui.commons".

This will make sure that UI5 and the needed libraries are loaded at runtime.

Your view should now look like this:

Don't forget to save and activate everything you made so far!

Create a Test Application

Although our UIBB isn't capable of displaying anything so far, it's now time to create a test application where we can see and test the progress of our work.

  • Call Transaction FPM_WB. It will launch the FPM Workbench in a new browser window. There you can find the link to launch the "Wizard for Creating Empty FPM Applications". Click on it and you will get to the initial screen of the Application Creation Tool
  • Fill it out as shown in the screenshot

  • then press "Next" and on the next screen "Save" which brings you to the confirmation screen of the application creation tool. Please keep this screen open until the end of this chapter
  • The confirmation screen contains mainly 2 links, one to launch the configuration editor ("FLUID") and the 2nd to launch the new application. As the application is up to now completely empty, we first launch the configuration editor
  • There add our new UIBB to the application and give the only page as well as the panel a meaningful title (see screenshot)

  • After saving we can start the new application via the 2nd link on the confirmation screen.

As we did not add any content (except an empty DIV tag) to our Html Island there is only an empty space in the Timeline panel.

Add the Timeline Control with JavaScript

Now we have to add the necessary client side code to create the timeline control and place it into our Html Island. To do this create a simple text file, add the following code to it and save it (best with extension ".js").


var MY_TIMELINE = MY_TIMELINE || {
      timeline: {},
      oCallbackApi: {},
      init: function (oCallbackApi) {
          this.oCallbackApi = oCallbackApi;
          this.timeline = new sap.suite.ui.commons.Timeline();
          this.timeline.placeAt("mytimeline");
     }
}






























Let me shortly explain this code: We are creating one instance of object MY_TIMELINE on the client. This object has 3 members:

  • an empty object timeline, which we will use to store the timeline control,
  • an empty object oCallbackApi, which will hold the reference to a callback object, which we will use to communicate to the backend
  • and an init function. With this init function we are
    • receiving the callback object and storing it
    • create the Timeline control and
    • place it in our Html Island

Now we have to upload this code as MIME object to our new component. Launch SE80 and navigate to our UIBB component. Import your javascript file as Mime object via context menu on the component.

Now add this script as additional script to the Html Island

At runtime the script will be loaded and the Html Island can access the script. However to create and locate the timeline control the init method has to be called. Therefore we need to add a call to this method to our Html Island and this is done by adding the following ABAP code to the view's WDDOMODIFYVIEW method:


METHOD wddomodifyview .
   IF first_time = abap_true.
     DATA(lo_timeline) = CAST cl_wd_html_island( view->get_element( `TIMELINE` ) ).
     lo_timeline->add_script_call( cl_wd_html_script_call=>new_call(
         )->variable( `MY_TIMELINE`
         )->function( `init`
         )->add_callback_api(  ) ).
ENDIF.
ENDMETHOD.


























We simply add a script call object to our Html Island. The script call is calling the init function on (object) variable MY_TIMELINE and is adding a single parameter to the script call - the call back API. This JavaScript function will now be called on the client. If you run the test application you can see only a small change on the UI, a filter icon. However this filter icon belongs to the UI5 timeline control - we have now successfully instantiated the UI5 control and embedded it into our FPM application.

Feed the control with application data from the backend

A timeline control without any data isn't very exciting, therefore let it display some backend data. First let's create some timeline data. We will do this in our assistance class:

  • Create 2 public types for storing the data:

types: begin of TY_S_ITEM,
            datetime type string,
            user_name type string,
            title type string,
            text type string,
            icon type string,
          end of ty_s_item.
   types: ty_t_item type STANDARD TABLE OF ty_s_item with DEFAULT KEY.






















  • Then add a public method Get_Timeline_Data to your assistance class

methods GET_TIMELINE_DATA
     returning
       value(RT_DATA) type TY_T_ITEM .























  • And add some code creating some sample data to the methods body (I chose to use some version control data for this example).

DATA(lo_version_provider) = cl_wb_object_version_provider=>create_instance( ).
       DATA(lo_version_info) = lo_version_provider->get_versions(
                              pgmid                   = 'R3TR'
                              object_type             = 'CLAS'
                              object_name             = 'CL_FPM_OVP_ASSIST'
                          ).
       LOOP AT lo_version_info->get_list( ) ASSIGNING FIELD-SYMBOL(<version_list>).
         DATA(ls_vers_info) = <version_list>->get_info( ).
         APPEND INITIAL LINE TO rt_data ASSIGNING FIELD-SYMBOL(<item>).
         CONVERT DATE ls_vers_info-datum TIME ls_vers_info-zeit
                 INTO TIME STAMP DATA(ts) TIME ZONE sy-zonlo.
         <item>-datetime = |{ ts TIMESTAMP = ISO TIMEZONE = 'UTC   ' }|.
         <item>-user_name = ls_vers_info-author.
         <item>-title = ls_vers_info-korrnum.
         <item>-text = ls_vers_info-trequest_text.
         <item>-icon = 'sap-icon://request'.
       ENDLOOP.


























  • Now we have to create a context node in the view to store the data and transport it to the UI. We will create a 0..n node with the structure defined by TY_S_ITEM

  • And in the view's WDDOINIT method we will fill this node:

method WDDOINIT .
   data(lo_nd_item) = wd_context->get_child_node( name = wd_this->wdctx_item ).
   lo_nd_item->bind_table( new_items = wd_assist->get_timeline_data( ) ).
endmethod.























  • The data is now accessible in the view contoller's context. Now we will bind it to the Html Island. To do this we have to first create the binding targets on the Html Island. Therefore we add a JsonDataSource and JsonDataElements corresponding to our context structure to the Html Island and bind our context to them

Pay attention to the name attributes. These are used to access the data in the JavaScript code. I chose "content", "datetime", "userName", "title", "text" and "icon". If you are using other names you have to adjust the script accordingly.

  • Now the timeline data is available on the client and we have to fill our timeline control with the data. Therefore we will now extend our script:

var MY_TIMELINE = MY_TIMELINE || {
    timeline: {},
    oCallbackApi: {},
  init: function (oCallbackApi) {
       this.oCallbackApi = oCallbackApi;
       this.timeline = new sap.suite.ui.commons.Timeline();
       this.timeline.placeAt("mytimeline");
   },
    setContent: function (content) {
       this.timeline.destroyContent();
       for(var i=0, max=content.length; i<max; i++) {
            var item = new sap.suite.ui.commons.TimelineItem({
                 dateTime : new Date(content[i].datetime),
                 userName : content[i].userName,
                 title : content[i].title,
                 text : content[i].text,
                 icon : content[i].icon
            });
            this.timeline.addContent(item);
       }
  }
}





















To pass the data to the control I added the setContent function to the script. This method will get the timeline data as an array parameter and it will create timeline items for each array entry.

  • Re-upload the changed JavaScript file to your component
  • Last step call the new JavaScript function from the backend: Add the following script call to the WDDOMODIFYVIEW method of V_TIMELINE

    lo_timeline->add_script_call( cl_wd_html_script_call=>new_call(
         )->variable( `MY_TIMELINE`
         )->function( `setContent`
         )->add_ui_elem_data_source( `content` ) ).



















Now everything should be done and the test application should show some data (if it doesn't work you have to clear the browser cache😞

Sending the Selected Item to the Backend

Up to now, we have embedded a UI5 control in to an FPM application and filled it with data from the ABAP backend. What's missing is the other direction: Sending data from the control to the backend.

This is done by raising a Web Dynpro Action from the client-side JavaScript code.

  • Therefore we will start by adding a new action "SELECT" to view V_TIMELINE.
  • Let's add some simple code to the action handler, which will later show that the SELECT action has been triggered:

method ONACTIONSELECT .
   cl_fpm_factory=>get_instance( )->mo_message_manager->report_message(
     EXPORTING
       iv_message_text  = wdevent->get_string( `DATA` )
   ).
endmethod.















  • Then we have to add an HtmlEvent to our Html Island and attach the newly created "SELECT" action to it

  • Now the backend is ready - the only thing missing is to raise the Html Event via JavaScript. To do this we have to enhance our timeline.js script once more:

var MY_TIMELINE = MY_TIMELINE || {
    timeline: {},
    oCallbackApi: {},
     init: function (oCallbackApi) {
          this.oCallbackApi = oCallbackApi;
          this.timeline = new sap.suite.ui.commons.Timeline();
          this.timeline.placeAt("mytimeline");
          this.timeline.attachSelect(
               function(oControlEvent) {
                    MY_TIMELINE.oCallbackApi.fireEvent('select', oControlEvent.getParameter("selectedItem").getTitle());
               }
          );
     },
     setContent: function (content) {
          this.timeline.destroyContent();
          for(var i=0, max=content.length; i<max; i++) {
               var item = new sap.suite.ui.commons.TimelineItem({
               dateTime : new Date(content[i].datetime),
               userName : content[i].userName,
               title : content[i].title,
               text : content[i].text,
               icon : content[i].icon
               });
               this.timeline.addContent(item);
          }
     }
}












The only changes are lines 8-12: There we attach a new function to the control's Select event. In this function we are using the callback api we already stored in the first version of the script to forward this client-side event to the backend, where it then raises the SELECT-Action of our view. As event parameter we pass the selected items title to the backend.

Now if run the test application again and click on any item we should get a (error) message with the item's title as text:

Summary

Although this blog is quite lengthy, it's not much effort to integrate a UI5 control. The integration control is the Html Island. Via standard WD Abap methods like context binding the application data is passed to the Html Island. The rendering, and placing of the control as well as the data transport from the Html Island to the control is then done via JavaScript coding attached to the Html Island. The backward direction is done by raising HtmlEvents via JavaScript coding, which then triggers Web Dynpro Actions.

My step-by-step description was reduced to the absolute minimum necessary to demonstrate the integration of a UI5 control. Therefore the result is a bit ugly and there is still a lot of work to be done before such a UIBB can be used productively. But the basic steps are the same as the FPM team used when implementing the Carousel or the Visbiz UIBB.

11 Comments
Labels in this area