Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member181879
Active Contributor

Overview of Event Handling in HTMLB

HTML/HTTP does not support the concept of server events. At the lowest level, the only building block that is

available is forms in HTML, which can be submitted to a server. When a form is submitted, all input fields (which

includes hidden input fields) are transported to the server. Therefore, event handling in the browser reduces to

setting up specific predefined input fields (these are usually type=”hidden”) with values that reflect the event to

be sent to the server, and then submitting the form.

On the server, the event handling system will look at the incoming HTTP request. If it detects form fields with

well-known names (all HTMLB event input fields have a prefix ‘htmlbevt_’), it will signal an HTMLB event, and unpack

the relevant fields into an event object. Let’s look briefly at all the components that are involved in the event

handling system.

<!codeRendering Phase

<!code>    <htmlb:button id=”myBtn” onClick=”button_clicked”/>

<!code>    ... CL_HTMLB_BUTTON

<!code>        ... event = CL_HTMLB_MANAGER=>RENDER_EVENT_CALL(...).

<!code>        ... render onclick=’htmlbSubmitLib(...)’

<!code>   

<!codeIn Browser

<!code>    User clicks on button

<!code>    ... onclick is triggered, calls htmlbSubmitLib(...)

<!code>        ... Sets up a number of input fields with correct values

<!code>        ... calls form.submit();

<!code>   

<!codeOn Server

<!code>    event = CL_HTMLB_MANAGER=>GET_EVENT_EX( request )

<!code>        ... examines HTTP request for fields matching htmlbevt_*

<!code>        ... creates event object cl_htmlb_button, unpacks fields

<!code>   

During rendering, each control might require one or more events. This is usually done by wiring the HTML onclick

attribute with some JavaScript code that will handle the event. This specific, required JavaScript code is obtained

by a call to the method cl_htmlb_manager =>render_event_call. This method will return a sequence of JavaScript

code, which consists of one or more calls to the different JavaScript functions that are available for event

handling in the browser. The output of this method is internal only, already. In the past this output has been

improved a number of times. Do not try to concatenate this JavaScript output together directly, as this will cause

problems if the underlying event handling code is modified.

In the above examples, the JavaScript function htmlbSubmitLib is shown. However, the exact call that will be

generated depends on a number of factors, for example if a client side event is also involved, and whether the event

is listed in a predefined dictionary. Consider the output of the RENDER_EVENT_CALL method as a black box.

In the browser, once a control event is triggered, the JavaScript code in the onclick handler is executed. This

code calls the defined JavaScript code, which packs the event relevant information into hidden input fields, and

then submits the form.

At the server, the developer calls cl_htmlb_manager =>get_event_ex to see if any event was fired. (Note

get_event_ex is the newer replacement of get_event. The libraries XHTMLB and PHTMLB only work with the new

get_event_ex method. The HTMLB library has also been updated to work with this new method.) This method sees if any

form fields are in the incoming HTTP request that indicates an HTMLB event has been fired. If an event is detected,

the specific event handling class is found, instantiated and initialised with the event parameters. For all new

libraries, it’s expected that the rendering class is also the event handling class, and that this class implements

the additional interface if_htmlb_data.

When developing controls that use the HTMLB event system, there are only two relevant sections of code. The first

is the render_event_call for the JavaScript code that must be executed in the browser. The second is the

implementation of the if_htmlb_data interface, so that the HTMLB event system can initialize the event object with

relevant data.

RENDER_EVENT_CALL Method

Keep in mind that the actual generated JavaScript is placed

inside an HTML onclick sequence. In HTML, it is important to keep event bubbling in mind. One typical example is

when an anchor is used to render a control. If the onclick does not return false, the documentation  (http://help.sap.com/saphelp_nw04/helpdata/en/f8/7e1d3c55a0f503e10000000a114084/frameset.htm) for detailed instructions on writing BSP extensions and elements.  In the

workbench, create a new BSP element, and define a number of attributes. After the element is activated, all the

relevant classes are generated.

!https://weblogs.sdn.sap.com/weblogs/images/164/BID_UTHES_001.GIF|height=0 width=570 height=365 |width=0 width=570 height=365 |src=https://weblogs.sdn.sap.com/weblogs/images/164/BID_UTHES_001.GIF|border=0 width=570 height=365 !

The name attribute is used to specify the name of the JavaScript function. Alternatively, if the event_code

attribute is specified, the JavaScript code will be returned (placed into this string reference), and no JavaScript

function is rendered.

The attributes id, event_type, onClick (mapped onto server_event), event_defined and return_value are strings

that will be passed directly to the render_event_call. These strings must be statically known during the rendering,

and cannot be determined later in the browser. The attribute onClientClick (mapped onto client_event) can contain

any sequence of JavaScript code that will be executed in the browser when the event is triggered.

The attributes p1, p2, and p3 are used to specify the parameters of the rendered JavaScript function, and will

then be passed to the event handling code.

As this will be an “empty” control (meaning it can have no body text), only the do_at_beginning method is

implemented. The complete method is listed below, and then discussed.

<!code>  METHOD if_bsp_element~do_at_beginning.

<!code>   

<!code>    IF me->id IS INITIAL.

<!code>      me->id = 'id'.

<!code>    ENDIF.

<!code>   

<!code>    IF me->event_code IS NOT BOUND.

<!code>      IF me->name IS INITIAL

<!code>      OR me->name    CN '_abcdefghijklmnopqrstuvwxyzABCDEFGHIKLMNOPQRSTUVWXYZ0123456789'

<!code>      OR me->name(1) CA '0123456789'.

<!code>        me->raise_error( msg = 'Der Parameter "name" ist kein gültiger

JavaScript-Name.'(001) ).

<!code>      ENDIF.

<!code>    ENDIF.

<!code>   

<!code>    DATA: param_string TYPE string,

<!code>          param_count  TYPE I VALUE 0.

<!code>    IF me->p1 IS NOT INITIAL.

<!code>      CONCATENATE param_string `,` me->p1 INTO param_string.

<!code>      param_count = param_count + 1.

<!code>    ENDIF.

<!code>    IF me->p2 IS NOT INITIAL.

<!code>      CONCATENATE param_string `,` me->p2 INTO param_string.

<!code>      param_count = param_count + 1.

<!code>    ENDIF.

<!code>    IF me->p3 IS NOT INITIAL.

<!code>      CONCATENATE param_string `,` me->p3 INTO param_string.

<!code>      param_count = param_count + 1.

<!code>    ENDIF.

<!code>   

<!code>    DATA: event_string TYPE string.

<!code>    event_string = CL_HTMLB_MANAGER=>RENDER_EVENT_CALL(

<!code>                      BSP_ELEMENT          = me

<!code>                      EVENT_TYPE           = me->eventType

<!code>                      SERVER_EVENT         = me->onClick

<!code>                      CLIENT_EVENT         = me->onClientClick

<!code>                      CLIENT_EVENT_INLINED = 'X'

<!code>                      EVENT_DEFINED        = me->p0

<!code>                      PARAM_COUNT          = param_count

<!code>                      PARAM_STRING         = param_string

<!code>                      RETURN_VALUE         = js_return ).

<!code>   

<!code>    IF me->event_code IS BOUND.

<!code>      me->event_code->* = event_string.

<!code>    ELSE.

<!code>      IF STRLEN( param_string ) IS NOT INITIAL.

<!code>        SHIFT param_string LEFT.

<!code>      ENDIF.

<!code>      CONCATENATE ``

<!code>                    `function ` name `(` param_string `){ ` event_string `;}`

<!code>                  `</script>`

<!code>             INTO event_string.

<!code>      me->print_string( event_string ).

<!code>    ENDIF.

<!code>   

<!code>    rc = CO_ELEMENT_DONE.

<!code>   

<!code>  endmethod.

<!code>   

The first important step is to do a sanity check on the attribute name, as this string will be used to generate

the name of a JavaScript function. This is only done if the event_code is not returned directly.

In the next code block, the optional parameters p1, p2, and p3 are built into one string. This string will be

required twice. It is needed to build the interface for the JavaScript function and as a parameter list onto the

HTMLB event system call.

Thereafter, the render_event_call is used to retrieve the correct HTMLB event system JavaScript code. Note that

the returned code depends very much on the mix of input parameters. The actual string returned is handled as a black

box. No assumptions are made about the string or its format.

As the last step, either the event string is returned if so requested, or a JavaScript function is rendered that

can be used later to fire the event.

Handling Incoming Events

On incoming HTTP requests, you use the get_event_ex call to determine if an HTMLB event is available. The

cl_htmlb_manager will map the event onto the correct class, which is by default the same class that is also used for

rendering the control. It instantiates a new copy of this class, and then does a query for the if_htmlb_data

interface.

The method event_initialized will be called with all the standard attributes of an HTMLB event. In our case,

these values are restored onto the event attributes defined on if_htmlb_data. The last call will be to

event_set_parameters with all additional parameters that were available in the incoming HTTP request. These are also

restored into the class attributes.

<!code>  METHOD if_htmlb_data~event_initialize.

<!code>   

<!code>    me->if_htmlb_data~event_id          = p_event_id.

<!code>    me->if_htmlb_data~event_type        = p_event_type.

<!code>    me->if_htmlb_data~event_class       = p_event_class.

<!code>    me->if_htmlb_data~event_name        = p_event_name.

<!code>    me->if_htmlb_data~event_server_name = p_event_server_name.

<!code>    me->if_htmlb_data~event_defined     = p_event_defined.

<!code>   

<!code>    me->id            = me->if_htmlb_data~event_id.

<!code>    me->event_type    = me->if_htmlb_data~event_type.

<!code>    me->event_defined = me->if_htmlb_data~event_defined.

<!code>    me->onclick       = me->if_htmlb_data~event_server_name.

<!code>   

<!code>  ENDMETHOD.

<!code>   

<!code>  METHOD if_htmlb_data~event_set_parameters.

<!code>   

<!code>    me->p1 = p_param_1.

<!code>    me->p2 = p_param_2.

<!code>    me->p3 = p_param_3.

<!code>   

<!code>  ENDMETHOD.

<!code>   

With the handling of an incoming event, the integration into the HTMLB event handling system is complete, and the

control can be used.

Using the Event System

Using the HTMLB event system now reduces to using the control to generate a JavaScript function that can be

called from any other HTML or JavaScript code.

<!code>  <%@page language="abap"%>

<!code>  <%@extension name="bsp"   prefix="bsp"%>

<!code>  <%@extension name="htmlb" prefix="htmlb"%>

<!code>   

<!code>  <htmlb:content design="design2003">

<!code>  <htmlb:page>

<!code>   <htmlb:form>

<!code>   

<!code>   

<!code>     <bsp:htmlbEvent name="buttonPressed" p1="btnId"/>

<!code>  myButton1

<!code>   

<!code>     <% DATA: event_code TYPE STRING. %>

<!code>     <bsp:htmlbEvent event_defined="myBtn2" event_code="<%=event_code%>"/>

<!code>   

<!code

<button onclick = "<%=event_code%>">myButton2</button>

<!code>   

<!code>   </htmlb:form>

<!code>  </htmlb:page>

<!code>  </htmlb:content>

<!code>   

Two different techniques can be used now. In the first, the name attribute is set, and one additional attribute

P1 is defined. This will result in a JavaScript function, “buttonPressed(btnId) {...}” been rendered out. In the

next step, raw HTML is used, where the onclick handler is now tied to the HTMLB event system. (The sequence

is used to generate a button in HTML that can be used to submit a form.)

The alternative technique is to set the event_code attribute. Because this attribute is flagged as a reference

attribute, the BSP compiler will pass a reference to the variable into the control. The control will write the

generated JavaScript code directly into this variable, so it can be used.

The (heavily edited) output seen in the browser is listed below.

<!code

<!code>   

<!code>   

<!code>   

<!code>      function buttonPressed(btnId)

<!code>      {

<!code>        htmlbSubmitLib('htmlb', this, 'bsp:htmlbEvent:EVENT:null', 'htmlb_form_1', 'id', 'buttonPressed',

1, btnId);

<!code>        return false;

<!code>      }

<!code>    </script>

<!code>   

<!code>  myButton1

<!code>   

<!code>  myButton2

<!code>   

<!code>  </form></body></html>

<!code>   

Incoming events are now handled exactly the same way as HTMLB events!

<!code>  DATA: event       TYPE REF TO if_htmlb_data,

<!code>        htmlb_event TYPE REF TO cl_bsp_htmlb_event.

<!code>  event = cl_htmlb_manager=>get_event_ex( request ).

<!code>  IF event IS NOT INITIAL AND event->event_class = 'CL_BSP_HTMLB_EVENT'.

<!code>    htmlb_event ?= event.

<!code>    ... use htmlb_event to see p1,p2,p3

<!code>  ENDIF.

<!code>   

The returned interface reference already has enough data to determine nearly all attributes of the event. Only if

the parameters p1, p2, or p3 are required, is the actual cast into the class required. The parameters are attributes

of the class, and not of the generic HTMLB event system.

If the event data is only displayed on the BSP example page, you have the following output:

!https://weblogs.sdn.sap.com/weblogs/images/164/BID_UTHES_002.GIF|height=0 width=283 height=220 |width=0 width=283 height=220 |src=https://weblogs.sdn.sap.com/weblogs/images/164/BID_UTHES_002.GIF|border=0 width=283 height=220 !</body>

2 Comments