This blog post is about integrating a SAPUI5 application into the Web UI. The application will be able to communicate with the Web UI via the htmlIsland control from the thtmlbx library of SAP.
💾 I published a sample application on GitHub. The repository also contains a sample for the .htm page in the Web UI view. https://github.com/BloggingWithJan/thtmlbx-htmlIsland-Integration
thtmlbx:htmlIsland
The integration of the htmlIsland takes place in the .htm page of a view.
![.htm page of a view - bsp component](https://bloggingwithjan.com/wp-content/uploads/2022/11/htm_file_location_in_component_workbench.png)
To access controls of the thtmlbx library we have to declare the use of it in the .htm page.
<%@extension name="thtmlbx" prefix="thtmlbx" %>
Through the htmlIsland control, applications such as a SAPUI5 application can be integrated into the Web UI.
<%@extension name="thtmlbx" prefix="thtmlbx" %> <thtmlbx:htmlIsland id = "htmltestIsland" height = "800px" width = "100%" htmlFile = "/sap/bc/ui5_ui5/sap/zhtmlisland/index.html" > </thtmlbx:htmlIsland>
💡 If you need the SAPUI5 application to update on every roundtrip in the Web UI, set the property
forceUpdate
to"TRUE"
⚠️ Unfortunately, the htmlIsland cannot handle %-specifications in the property
height
, like for example 60%. A workaround fo this is described below.
thtmlbx:htmlIslandProperty
The htmlIslandProperty enables us to transfer variables from the Web UI to the SAPUI5 application in the htmlIsland. If we are in the service order, we can, for example, transfer the service order number and the bus object to the htmlIsland. The SAPUI5 application within the htmlIsland can access this data and thus has the necessary context.
<%@page language="abap" %> <%@extension name="thtmlbx" prefix="thtmlbx" %> <% *--- Just an example DATA: lr_property_a type ref to data. DATA: lr_property_b type ref to data. DATA(lv_property_a) = 'A'. DATA(lv_property_b) = 'B'. GET Reference of lv_property_a into lr_property_a. GET REFERENCE of lv_property_b into lr_property_b. %> <thtmlbx:htmlIsland id = "htmltestIsland" height = "800px" width = "100%" htmlFile = "/sap/bc/ui5_ui5/sap/zhtmlisland/index.html" > <thtmlbx:htmlIslandProperty id = "propertyA" name = "propertyA" value = "<%= lr_property_a %>" /> <thtmlbx:htmlIslandProperty id = "propertyB" name = "propertyB" value = "<%= lr_property_b %>" /> </thtmlbx:htmlIsland>
💡 How we can access the htmlIslandPropertys from within the SAPUI5 application is described below.
thtmlbx:htmlIslandDataSource
If not only individual variables from the Web UI are required, but also many data entries, the htmlIslandDataSource is the right choice. With the htmlIslandDataSource entire internal tables can be transferred to the SAPUI5 application. In addtion, the data can also be changed in the SAPUI5 application and transferred back to the Web UI.
<%@extension name="thtmlbx" prefix="thtmlbx" %> <thtmlbx:htmlIsland id = "htmlIslandTest" height = "800px" width = "100%" htmlFile = "/sap/bc/ui5_ui5/sap/zhtmlisland/index.html" > <thtmlbx:htmlIslandDataSource id = "sflight" name = "sflight" data = "//SFLIGHT/Table" properties = "<%= controller->gt_properties %>" /> </thtmlbx:htmlIsland>
A prerequisite for using the htmlIslandDataSource is the creation of a table value node in the view. In addition, a few adjustements have to be made in the implementation class. SAP has provided an official example in the component FLEX_SANDBOX.
💡 How we can access the htmlIslandDataSource from within the SAPUI5 application is described below.
⚠️ The htmlIslandDataSource also has a few limitations. New data records cannot be created via the SAPUI5 application. Furthermore, no existing entries can be deleted via the SAPUI5 application.
thtmlbx:htmlIslandEvent
The htmlIslandProperty and the htmlIslandDataSource allow data to be transferred from the Web UI to the htmlIsland. The htmlIslandEvent on the other hand allows us to communicate with the Web UI from the SAPUI5 application.
<%@extension name="thtmlbx" prefix="thtmlbx" %> <thtmlbx:htmlIsland id = "htmltestIsland" height = "800px" width = "100%" htmlFile = "/sap/bc/ui5_ui5/sap/zhtmlisland/index.html" > <thtmlbx:htmlIslandEvent id = "event" name = "event" onAction = "event" /> </thtmlbx:htmlIsland>
In addition to the changes in the .htm implementation, it is necessary to create an event handler of the same name in the Web UI view.
![Event Handler of an view - bsp component](https://bloggingwithjan.com/wp-content/uploads/2022/11/image.png)
To access parameters passed by the event add the following code to the event handler implementation.
METHOD eh_onevent. DATA: lo_thtmlbx_event TYPE REF TO cl_thtmlbx_hi_event. DATA: lt_parameters TYPE tihttpnvp. *--- access parameters passed with the event lo_thtmlbx_event ?= htmlb_event_ex. lo_thtmlbx_event->get_param_list( IMPORTING et_event_parameters = lt_parameters ). ENDMETHOD.
💡 How we can trigger an event from the SAPUI5 application is described below.
SAPUI5 application
For the htmlIsland integration we need to create an index.html. The client-side island_script is embedded and registered in the index.html. Thus, getter and setter, aswell as events can be defined to communicate with the Web UI. Furthermore the SAPUI5 application instantiated in the index.html.
Instantiation of the SAPUI5 application
There are different options for instantiating the application in the index.html. Three possible instantiations are stored in the GIT repo. (there you can also see the basic coding that we need in the index.html – but this is not discussed in detail here)
htmlIslandProperty
For each htmlIslandProperty a getter and setter must be implementend in the index.html. The property must be named exactly as in the Web UI.
<thtmlbx:htmlIslandProperty id = "propertyA" name = "propertyA" value = "<%= lr_property_a %>" />
App.prototype.getPropertyA = function() { return this._sPropertyA; }; App.prototype.setPropertyA = function(val) { this._sPropertyA = val; };
These propertys can be accessed in the SAPUI5 application via the global variable app
or they can be passed to the application when its instantiated. Take a look at the GIT repo for examples.
htmlIslandDataSource
For each htmlIslandDataSource a getter and setter must be implemented in the index.html. The data source must be named exactly as in the Web UI. Since htmlIslandDataSources involve multiple data, it makes sense to store the data in an sap.ui.model.json.JSONModel
.
App.prototype.init = function(rootID){ thtmlbxHIslandLib.register(this); //... // Create the central model(s) var model = new sap.ui.model.json.JSONModel(); model.setData({data: this.getSFlight()}); // initially empty list // place the model instance in a central location, available to UI Components as well as the App sap.ui.getCore().setModel(model, 'sflight'); } // getter for flightData DataSource App.prototype.getSFlight = function() { return this._sflight; }; // setter for flightData DataSource App.prototype.setSFlight = function(val) { var model = sap.ui.getCore().getModel('sflight'); // get the central model model.setData({data: val}); model.updateBindings(true); // let the UI Component know the data has changed this._sflight = val; // store on the private member variable };
htmlslandEvent
In order to trigger events from the SAPUI5 application we define a fireServerEvent
function in the index.html
App.prototype.fireServerEvent = function(name, paramMap) { logX('App1', 'fireServerEvent', 'Event name: ' + name); thtmlbxHIslandLib.fireEvent(name, paramMap); };
This function can then be called from everywhere in the SAPUI5 application.
app.fireServerEvent("event", {param1: 'Hello', param2: 'World'});
thtmlbxHIslandLib Events
The thtmlbxHIslandLib
has many standard events we can listen to:
thtmlbxHIslandLib.EVENT_BEGIN_FREEZE
thtmlbxHIslandLib.EVENT_END_FREEZE
thtmlbxHIslandLib.EVENT_BEGIN_UPDATE
thtmlbxHIslandLib.EVENT_END_UPDATE
thtmlbxHIslandLib.EVENT_BEGIN_UPDATE_EVENTS
thtmlbxHIslandLib.EVENT_END_UPDATE_EVENTS
thtmlbxHIslandLib.EVENT_BEGIN_UPDATE_PROPS
thtmlbxHIslandLib.EVENT_END_UPDATE_PROPS
thtmlbxHIslandLib.EVENT_BEGIN_UPDATE_DATASOURCES
thtmlbxHIslandLib.EVENT_END_UPDATE_DATASOURCES
thtmlbxHIslandLib.addEventListener(thtmlbxHIslandLib.EVENT_END_UPDATE, this.onEndUpdate, this);
Since the thtmlbxHIslandLib
can be addressed globally in the application, it is recommend to store the event listeners in the Component.js
or an view controller.
Lessons Learned
During development and implementation, there were a few challenges that, looking back, are of course easily solvable. Certain topics are briefly presented below.
FLP User Settings
When the Web UI application is displayed in the Fiori Launchpad, the SAPUI5 application in the htmlIsland has no information about the user settings on the FLP. The user can set preferences like language, time format, date format, theme options and much more.
These settings can normally be accessed via the following code.
sap.ui.getCore().getConfiguration().getFormatSettings()...
However, since the htmlIsland is technically an iframe, we cannot access this information. To solve this we make use of the browser variable parent
.
//access flp configuration var determineFLPConfiguration = function (oParent) { var oConfiguration; try { oConfiguration = oParent.sap.ui.getCore().getConfiguration(); if (oConfiguration.getFormatSettings().getDatePattern("medium")) { //check if the configuration contains an value for medium date pattern return oConfiguration; } else { return determineFLPConfiguration(oParent.parent); //if the configuration contains no value we are probably not there yet (recursive) } } catch (error) { return determineFLPConfiguration(oParent.parent); //there is no configuration, we are probably not there yet (recursive) } } var sLanguage = determineFLPConfiguration(parent).getFormatSettings().getFormatLocale().getLanguage(); sap.ui.getCore().getConfiguration().setLanguage(sLanguage); var sDateFormat = determineFLPConfiguration(parent).getFormatSettings().getDatePattern("medium"); sap.ui.getCore().getConfiguration().getFormatSettings().setDatePattern("medium", sDateFormat); var sTimeFormat = determineFLPConfiguration(parent).getFormatSettings().getTimePattern("medium"); sap.ui.getCore().getConfiguration().getFormatSettings().setTimePattern("medium", sTimeFormat); var sDecimalFormat = determineFLPConfiguration(parent).getFormatSettings().getNumberSymbol("decimal"); sap.ui.getCore().getConfiguration().getFormatSettings().setNumberSymbol("decimal", sDecimalFormat); var sTheme = determineFLPConfiguration(parent).getTheme(); sap.ui.getCore().applyTheme(sTheme);
Another possibility would be to pass parameters like sy-langu via an htmlIslandProperty. However, it should be clear that the “browser language” option, which can be set in FLP, cannot be covered by sy-langu. It is therefore advisable to determine the settings in the SAPUI5 application.
htmlIsland height
As described above, the htmlIsland cannot deals with %-specifications in the property height. Only “px” specifications can be processed. If you render your htmlIsland in an popover… this is a big problem. Multiple scroll bars, no responsiveness… to solve this i implemented the following code in the index.html. (if someone discovers a better solution, let me know!)
//set height of parent to iframe thtmlbxHIslandLib._client.thisIframe.height = parent.innerHeight + "px"; //attach an resize event to the parent parent.addEventListener("resize", function (event) { thtmlbxHIslandLib._client.thisIframe.height = parent.innerHeight + "px"; }, true);
If you don’t render your htmlIsland in an popover and you can use certain criteria to define exactly how high the htmlIsland has to be, you can calculate the height and pass this information to the htmlIsland at runtime in the .htm page.
<%@page language="abap" %> <%@extension name="thtmlb" prefix="thtmlb" %> <%@extension name="thtmlbx" prefix="thtmlbx" %> <% DATA(lv_htmlislandheight) = CONTROLLER->DETERMINE_HTMLISLAND_HEIGHT( ). %> <thtmlbx:htmlIsland id = "htmltestIsland" height = "<%= lv_htmlislandheight %>" width = "100%" htmlFile = "/sap/bc/ui5_ui5/sap/zhtmlisland/index.html" > </thtmlbx:htmlIsland>
Caching Issues
After the second version of the application was transported to the quality system, the users had serious cache problems.
To fix the cache issue it’s recommended to add the following meta tags to the index.html.
<meta http-equiv="cache-control" content="no-cache" /> <meta http-equiv="expires" content="0" /> <meta http-equiv="pragma" content="no-cache" />
In addition the appCacheBuster should be activated so that the files of the SAPUI5 application are only cached until a new version of the SAPUI5 application get’s deployed.
data-sap-ui-appCacheBuster="./"
Lastly activate the Cache Buster for the SAPUI5 application resources
src="resources/sap-ui-cachebuster/sap-ui-core.js"
⚠️ Another alternative would be to empty the browser cache by the user himself. Depending on the age group of the user, however, this can quickly become a challenge. Furthermore, there is a good reason why caching mechanisms exist. Emptying the entire cache would lead to performance losses in other browser applications.
Focus Issues
When initially calling up the Web UI application and navigating back and forth, there were often weird jumps between sections. If the section with the htmlIsland integration was hidden, these problems almost completely disappeared. The Web UI is instantiated faster than the SAPUI5 application inside the htmlIsland. When the UI5 application is instantiated and the view is rendered, the focus is usually drawn to a specific SAPUI5 control. This causes the browser to change its scroll position which leads to weird jumps between sections.
Or in other words: setting the autoFocus
property of the sap.m.App
to false
helped a lot.
<App autoFocus="false"> ... </App>
Credits
Finally, credits to other people, somehow i got myself into the subject. I recommend the following blog posts, espcially if you are interested in the index.html coding.
- Integration of HTML Island in CRM BSP Application Using HANA IDE
- How to integrate an SAPUI5 application into the SAP Web UI
Furthermore, in every SAP system there is an example bsp application called ISLANDTEST and a WebUI component called FLEX_SANDBOX. (that’s the offical example of sap for the use of the htmlIsland control)
That’s it. Any questions…? Write them in the comments!