Overview
You can embed dialog parts of other ABAP classes as "iframe" (inline frame) in your HTML page. To do this, you only need an attribute in your ABAP class with an object reference to the external class. By embedding the iframe, not only is the visualization included in HTML, but the external class becomes active for displaying and processing the data from the embedded part.

iframes are part of the HTML5 standard; they are supported in all major browsers. As long as the embedded parts come from the same source, in our case the same SAP system, there are no security issues with the "same origin policy" when using iframes, which browsers use to prevent reciprocal access via JavaScript in the case of iframes of different origin.

Example
In a page with various information about a customer, you want to show the company relationships stored in the SAP customer hierarchy as a diagram. Between the sections "Relationships" and "Prices, Invoice" you want to insert the hierarchy representation:



Instead of reading the customer hierarchy yourself in your application and building a diagram from it, use an existing module and embed it as an iframe in your HTML page.

For our example, the reusable class in SE24 is called "/s10/customer". You create a public attribute in your ABAP class with a reference to this class:

* customer standard functions
     s10customer 
type ref to /s10/customer.

To build the hierarchy diagram, the object s10customer needs the customer number and the sales area:

create s10customer object with correct key data
for standard functions (eg customer hierarchy)
    
create object s10customer.
    s10customer
->kunnr kunnr.
    s10customer
->vkorg vkorg.
    s10customer
->vtweg vtweg.
    s10customer
->spart spart.


The page with the hierarchy representation you want to embed is called "customer.hierarchy.html". It is located in the SAP MIME Repository in a different path than your application, so you have to specify a somewhat complicated relative URL:

HTML
<div class="subtitle">
   Kundenhierarchie
</div>

<iframe
 
s10object="s10customer"
  src="../../../../../s10/public/classes/customer/views.de/customer.hierarchy.html">
</iframe>

This means that you go up a few levels in the path hierarchy from your project and then into the "public" folder of the SE24 class. Here, "s10" is the namespace from the class name "/s10/customer".

Nothing more is necessary. The hierarchy display now appears in the customer information:



The entire functionality, i.e. reading the SAP customer hierarchy and generating the diagram from it, is encapsulated in the external class /s10/customer and can be used in all projects.

It makes sense to describe in the class documentation which externally usable methods and views the class offers.


Display size of the iframe
The size of an iframe is normally set by height= and width=, optionally also by the corresponding style parameters within "<iframe>". Otherwise, the browser assumes a width of 300px and a height of 150px as default. Such a rigid size is rather useless in S10 applications, as the interface should adapt to the display size of the respective device.

For this reason, if you do not specify "height=", the S10 framework dynamically changes the actual displayed height of the iframe so that it exactly matches the height of the content depending on the width. The width is set to the entire width. In the example above, a less extensive hierarchy looks like this:




You can also specify a fixed width and let the S10 framework only adjust the height, for example two iframes next to each other with 50% width each.

Other display attributes of the iframe
As soon as you have specified the "s10object=" attribute in "<iframe", the S10 Framework hides the default border of the iframe and sets "margin" and "padding" to 0 so that the dialogue part is embedded seamlessly in your page. The scroll bars are also hidden. The background colour is set to "transparent".

If a border, spacing, scroll bars or a background colour are to be included, these can be set either in the embedded page or in your page by a parent "<div>" element.

In the example of the customer hierarchy, it makes sense to make the diagram itself scrollable horizontally:


 

Vertical scrolling of the diagram is not necessary as the scrolling is done with the whole page:



Format
It is best to use only the attributes "s10object=" and "src=" in the iframe tag, and width= if necessary:

<iframe
 
s10object="..."
  src="...">
</iframe>

For the special case that you want to use iframes that belong to the currently active dialogue object, please use the notation


<iframe
 
s10object="me"
  src="...">
</iframe>

because without the s10object= specification the embedding mechanism will not be effective.


Implementation of the iframe object
Nothing special needs to be considered when implementing the iframe object and the HTML page to be embedded. The HTML page is implemented like a normal HTML page of the S10 framework and can therefore be called separately, i.e. without embedding it in another page.
It is also possible to call it as a separate popup with s10dialog() without changing the page or the logic.


Binding of variables and methods
Within the iframe, all variable bindings, i.e. the name= parameter, automatically refer to the iframe object specified with s10object=. This means that input fields transport their value into the variables of the iframe object. Validation and build methods also run there. Method calls, e.g. triggered by push buttons, are executed in the iframe object.


Reference back to the superordinate ABAP object
In some cases, it makes sense to forward a user action within the iframe to the higher-level object. For example, the hierarchy diagram could allow a click on one of the displayed customers and forward this click to the main program. You can illustrate this with ABAP OO means, e.g. by giving the iframe object another reference to the frame object:

s10customer->refobject me.

and then call a specified method of the frame object dynamically from the iframe object.

Another possibility is to use the ABAP OO event mechanism here, i.e. the iframe object triggers an event for which the frame program has registered with the ABAP statement "Set Handler".

A third possibility is to call a function of the "parent" object from the iframe at JavaScript level, which can then call a method of the frame object through S10Apply().

A fourth possibility is to send a message to the frame window from the iframe at JavaScript level with parent.postMessage(), for which the frame window has registered with window.addEventListener. When the message is received, a method of the frame object can then be called by S10Apply(). This option is very flexible, as it also allows you to perform local actions directly at the JavaScript level and the parent.postMessage() calls do not interfere if the frame window has not implemented any handling of the message.


ABAP and HTML code of the iframe object in the example

ABAP

 
 method build_hierarchy.

    
clearhierarchyhierarchy_legend.

    
if kunnr is initial or vkorg is initial or vtweg is initial or spart is initial.
      
return.
    
endif.


    
datacustomername type kna1-name1,
          
nodelabel    type string,
          
sales_area   type table of bapi_sdvtber,
          
node_list    type table of bapikna1_knvh,
          
va           type bapi_sdvtber,
          
node         type  bapikna1_knvh,
          
tab          type string,
          
newline      type string.

    
tab cl_abap_char_utilities=>horizontal_tab.
    
newline cl_abap_char_utilities=>newline.

    
va-sales_org vkorg.
    
va-distr_chan vtweg.
    
va-division spart.
    
append va to sales_area.

    
call function 'BAPI_CUSTOMER_GET_ROOT'
      
exporting
        
custhityp  'A'
        customerno 
kunnr
      
tables
        
sales_area sales_area
        node_list  
node_list.

should return one node
    
read table node_list index into node.
    
if sy-subrc ne 0.
      
select single name1 into customername  from kna1 where kunnr kunnr.

      s10writestring
exporting in kunnr attrname 'kunnr' importing out nodelabel ).
      nodelabel
 nodelabel && |<br>| &&  cl_http_utility=>escape_htmlcustomername && || ).
      
hierarchy =  hierarchy && kunnr && tab && nodelabel && tab && | |.
      
return.
    
endif.

    
refresh node_list.
    
call function 'BAPI_CUSTOMER_GET_CHILDREN'
      
exporting
        
custhityp  'A'
        customerno 
node-customer
      
tables
        
sales_area sales_area
        node_list  
node_list.

    
loop at node_list into node.

      
select single name1 into customername  from kna1 where kunnr node-customer.

      s10writestring
exporting in node-customer attrname 'kunnr' importing out nodelabel ).

      nodelabel
 nodelabel && |<br>| &&   cl_http_utility=>escape_htmlcustomername && || ).

      
if node-rebate_rel 'X' or node-pric_rel 'X'.
        
nodelabel =  nodelabel  && |<br>|.
        
if node-rebate_rel 'X'.
          
nodelabel =  nodelabel  && | 💰 |.
        
endif.

        
if node-pric_rel 'X'.
          
nodelabel =  nodelabel  && | 🔖 |.
        
endif.
      
endif.

current customer?
      
if node-customer kunnr.
        
nodelabel |<div style='background-color:#fff9c0;'>| && nodelabel && |</div>|.
      
endif.

      
if  hierarchy is not initial.
        hierarchy 
=  hierarchy && newline.
      
endif.
      
hierarchy =  hierarchy && node-customer && tab && nodelabel && tab && node-parent_customer.

    
endloop.

    
hierarchy_legend |<table><tr><td>💰</td><td>|
                       && 
cl_http_utility=>escape_htmls10localize'bonusrel) )
                       && |</
td></tr><tr><td>🔖</td><td>|
                       &&  
cl_http_utility=>escape_htmls10localize'pricelistrel) )
                       && |</td
></tr></table>|.


  
endmethod.



HTML

<!DOCTYPE html>
<html>
<head>
   
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <link rel='stylesheet' type='text/css' href='../../../style/s10.style.css'>
   
<link rel='stylesheet' type='text/css' href='../../../style/custom.style.css'>
    <script src='../../synactiveS10/synactiveS10.java.js'></script>

    // the chart example is essentially taken from Google API documentation
    // https://developers.google.com/chart/interactive/docs/gallery/orgchart
 

    <
script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
   
<script type="text/javascript">

       google.charts.load('current', { packages: ["orgchart"] });

       
function drawChart(hstring) {

           
var data = new google.visualization.DataTable();
            data.addColumn(
'string', 'Name');
           
data.addColumn('string', 'Manager');


           
var myhierarchy = hstring.split('\n');

            // insert SAP hierarchy data into Google chart data
            for (var k = 0; k < myhierarchy.length; k++) {
                var parts = myhierarchy[k].split('\t');
                data.addRow([{ 'v': parts[0], 'f': parts[1] }, parts[2]]);
            };

           
// create the chart
           
var chart_div = document.getElementById('chart_div');
            var chart = new google.visualization.OrgChart(chart_div);

           
// draw the chart
           
chart.draw(data, { 'allowHtml': true });

           
// left aligned display
           
var tab = chart_div.getElementsByTagName('TABLE')[0];
            if (tab) tab.align = 'left';
        }
   
</script>
</head>
<body>


    <div style="padding:4px; overflow:auto;">

       
<!-- chart area -->
       
<style>
           
.google-visualization-orgchart-space-medium {
               
width: 20px;
            }
       
</style>
        <div id="chart_div"></div>

       
<!-- we add a legend -->
        <div style="clear:both;"></div>
       
<div class="outputhtml" name="hierarchy_legend"></div>

   
</div>

    <!-- hidden field for chart data and start of chart drawing -->
    <input type="hidden" class="output" name="hierarchy" id="hierarchy" onchange="drawChart(this.value);" />
</body>
</html>




Components: S10 Framework