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

Extending the Design of the Composite Element

As the names of all IDs and events used were hard coded, it was not possible to use two pagers on the same HTML page. For example, this could be interesting in scenarios where a split screen showing two logical independent sequences is used, and can be paged separately. Thus, we will add an 'ID attribute'.

In addition, one never knew what the current page was. The pager only handled the previous and next pages. We add a 'current attribute', which is the name of the current page. This will also be rendered (left-aligned on screen).

Last, we are using a control that will have an onX attribute to allow us to configure the event handler that must be called on return. We add the 'onPage attribute'. Note that later we will have both pagePrevious and pageNext events. The onPage is just a string that is the user’s handle for the event. Although in most controls we define an onX per event, it is not required. Using one such onX string for a number of events is perfectly fine.

!https://weblogs.sdn.sap.com/weblogs/images/164/BP_EHICE_001.GIF|height=0 width=459 height=327 |width=0 width=459 height=327 |src=https://weblogs.sdn.sap.com/weblogs/images/164/BP_EHICE_001.GIF|border=0 width=459 height=327 !

For this Weblog, I just defined a new pager2 element, so as to keep the older example for reference. But it is also possible to just change the original code.

Using the Composite Element

Before we start looking under the hood at the code that will be needed to complete the work, let us first “use” the new element. From this, we can get a good feeling for what must be supported. The test program will be similar to that used previously.  We only have to set additional attributes for the element.

For each page, we define the following source code:

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

<!code>   

<!code>    ...body comes here...

<!code>   

<!code

<!code

<!code

<!code

<!code

<!code>   

<!code>  </htmlb:form></htmlb:page></htmlb:content>

<!code>   

For the onInputProcessing code, we would now like to use code that is similar to that of the HTMLB library:

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

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

<!code>  IF event IS NOT INITIAL AND event->event_id = 'myPager'.

<!code>    navigation->goto_page( event->event_defined ).

<!code>  ENDIF.

<!code>   

In addition, the element should support minimal data retrieval, where it is possible to query the previous, current, and next pages. The typical code for the data call is:

<!code>  DATA: pager TYPE REF TO CL_BCM_SDN_PAGER2.

<!code>  pager ?= cl_htmlb_manager=>get_data( request = request

<!code>                                       name    = 'bcm_sdn:

pager2'

<!code>                                       id      = 'myPager' ).

<!code>  * use here pager->current, pager->next, pager->prev

<!code>   

Notice that for the get_data call, it is important to also supply the library and element name. The HTMLB manager has no other help available to determine the correct handler class. The library name is not that of the prefix used in the layout, but the original name under which the library was created. This allows the HTMLB manager to again determine the correct handling class.

We see from the above coding that we wish to achieve a new pager element that will work transparently with the HTMLB manager. For the element's user, business is as usual.

Use of IDs

<!code>  htmlb_button = cl_htmlb_button=>factory(

<!code>                    id            =  'bcm_sdn_pager_next'

<!code>                    ... )

<!code>   

<!code>  htmlb_button = cl_htmlb_button=>factory(

<!code>                    id            = me->id

<!code>                    id_postfix    = '__Previous'

<!code>                    ... ).

<!code>   

<!code>  htmlb_button = cl_htmlb_button=>factory(

<!code>                    id            = me->id

<!code>                    id_postfix    = '__Next'

<!code>                    ... ).

<!code>   

The factory method will concatenate the id and id_postfix strings together to create the new ID for the specific button.

Integrating into the HTMLB Manager

<!code>  METHOD if_htmlb_data~event_initialize.

<!code>   

<!code>  * Initialize event_* parameters

<!code>    me->if_htmlb_data~event_* = ...

<!code>   

<!code>  * Restore all data from the request

<!code>    me->if_htmlb_data~restore_from_request(request = p_request

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

<!code>   

<!code>    ...now apply event onto restored data...

<!code>   

<!code>  ENDMETHOD.

<!code>   

<!code>  METHOD if_htmlb_data~restore_from_request.

<!code>   

<!code>  * Use event_id as flag to check whether we also have an event. Let it do work.

<!code>    IF me->if_htmlb_data~event_id IS INITIAL AND

<!code>       CL_HTMLB_MANAGER=>CHECK_AND_INITIALISE_EVENT(

<!code>                       instance          = me

<!code>                       request           = request

<!code>                       event_id_expected = id

<!code>                       class_name        = me->m_class_name

<!code>                  ) IS NOT INITIAL.

<!code>      RETURN. " means an event found and restored (recursively called here)

<!code>    ENDIF.

<!code>   

<!code>    ...restore values from request...

<!code>   

<!code>  ENDMETHOD.

<!code>   

Not perfectly elegant, and looking at it now years later…Oh well, let us just cut-and-paste it into our code, no further comments.

Data Handling

We require that the pager is able to restore the values of the previous, current, and next pages. We must keep in mind that any control on the page can trigger an event to the server, and thus it's not always possible to retrieve this information from the event data.

The best technique to store the view state within an HTML page, is to use hidden input fields. This information is not rendered, and will be returned to the server when the form is submitted.

The following code is used within the do_at_beginning method to render the view state into the response, so that it will be returned to the server on the next request:

<!code>  DATA: html TYPE STRING.

<!code>  CONCATENATE

<!code>    ``

<!code>    ``

<!code>    ``

<!code>  INTO html.

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

<!code>   

Notice the use of the ID with sub strings to create new names for each hidden input field. The values are taken from the current element attributes.

To restore the values, the code below is used in the restore_from_request method:

<!code>  me->id = id.

<!code>   

<!code>  CONCATENATE me->id `_valPrev` INTO name.

<!code>  me->prev = request->get_form_field( name ).

<!code>   

<!code>  CONCATENATE me->id `_valCurrent` INTO name.

<!code>  me->current = request->get_form_field( name ).

<!code>   

<!code>  CONCATENATE me->id `_valNext` INTO name.

<!code>  me->next = request->get_form_field( name ).

<!code>   

Notice again the use of the ID to compute the actual names of the form fields that hold the data in the incoming HTTP request.

Event Handling

<!code>  htmlb:button:click:null

<!code>   

But, it is also possible to add additional handler classes onto this string, using ‘::’ as separator sequences.

<!code>  htmlb:button:click:null::

<!code>   

This means that even although a button-click event is received, the newly specified handler class must be called to decode the event. As it is not possible to configure these escape strings when processing another element, the HTMLB manager will also accept these escape sequences when they are attached to the event server name (onX strings).

<!code>  DATA: htmlb_button TYPE REF TO cl_htmlb_button.

<!code>  htmlb_button = cl_htmlb_button=>factory(

<!code>                        id            = me->id

<!code>                        id_postfix    = '__pagePrevious'

<!code>                        text          = me->prev

<!code>                        design        = 'PREVIOUS' ).

<!code>  CONCATENATE me->onPage '::cl_bcm_sdn_pager2::' me->prev '.BSP'

<!code>         INTO htmlb_button->onclick.

<!code>  WHILE m_page_context->element_process(htmlb_button ) = co_element_continue.

<!code>  ENDWHILE.

<!code>   

<!code>  METHOD if_htmlb_data~event_initialize .

<!code>   

<!code>  * Copy those parameters which we keep verbatim

<!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>    me->if_htmlb_data~event_intercept_depth = p_event_intercept_depth.

<!code>   

<!code>  * The pager uses two <htmlb:button> elements. Massage the event

<!code>  * to be pager event.

<!code>  * Event name will be 'button', should be our 'pager2'.

<!code>  * Event Id will be __pagePrevious

<!code>  * Event Type will be click from the button. The actual value we want, was

<!code>  * already encoded into the ID before.

<!code>   

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

<!code>    SPLIT me->if_htmlb_data~event_id AT '__'

<!code>      INTO me->

if_htmlb_dataevent_id me->if_htmlb_dataevent_type.</b>

<!code>   

<!code>  * Restore view state from the request

<!code>    me->if_htmlb_data~restore_from_request(request = p_request

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

<!code>   

<!code>  ENDMETHOD.

<!code>   

With the above changes, events are now presented as pager2 events.

!https://weblogs.sdn.sap.com/weblogs/images/164/BP_EHICE_002.GIF|height=0 width=331 height=296 |width=0 width=331 height=296 |src=https://weblogs.sdn.sap.com/weblogs/images/164/BP_EHICE_002.GIF|border=0 width=331 height=296 !</body>

2 Comments