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: 
Ulli_Hoffmann
Contributor
0 Kudos

Users like to have a certain amount of personal freedom and control when dealing with products and applications. One of the latest SAP products called "Introduction to SAP ViewPoint" session at TechEd San Diego emphasizes on content personalization in a web environment. Why do we request and like personalization? Somebody else once wrote: Personalization should make users more effective by helping them reach their goals!

That seems enough reason to think about how to bring personalization into BSP applications.</p>

Introduction

This weblog introduces some ideas of personalizing a BSP application. The example includes customizing the number of form items displayed and the order of how they appear on the screen. By implementing a simple BSP/MVC application it will be shown what kind of customization options could be offered to the user at runtime and how this can be achieved with reasonable effort. BSP technologies involved are BSP extensions ('phtmlb:formLayout'-tag) and server side cookies.


The starting example screen includes three input fields which are labeled 'First Name', 'Middle Name', and 'Last Name' and three checkboxes labeled 'ABAP', 'BSP', and 'JAVA'. The items are embedded in the 'phtmlb:formLayout'-tag. Using this tag we don't have to care much about the arrangement of fields and labels in case items get dropped during runtime. The tag internally takes care of getting columns and rows arranged neatly (see note 767167 for more documentation).

On the screen, located at the right above the layout items, there is a link called 'Personalize'. A mouse click will open another window including all items of the layout listed in a table. For each layout item the user can select its (in)visibility by setting a checkbox. The row in which the item appears on the screen can be set by selecting the desired row index from a dropdownlistbox.

Now we would like to do the following modifications:

1) hide the field 'Middle Name'

2) hide the checkbox 'JAVA'

3) move field 'Last Name' above field 'First Name'

4) move checkbox 'ABAP' above checkbox 'BSP'

After setting the values and pressing the button 'Update' the modified data is sent from the popup window to the server. The opener window is also forced to do a submit in order to pick up these modifications. With the response arriving at the browser window the personalized layout becomes visible.

!https://weblogs.sdn.sap.com/weblogs/images/2536/02screen03.jpg|height=164|alt=image|width=505|src=ht...!

Implementation

How did we do it? The application consists of one controller main.do (class zcl_main01_ctr) and two views:</br>

1) main.htm displaying the form items</br>

2) pers.htm displaying the personalization table.</br>

In our case, the model class zcl_model01 contains one attribute representing the table keeping the personalization data (mt_items) and attributes representing all layout items. Server side cookies are used in order to store user related personalization data.


When somebody logs on and starts the application, a server side cookie with the user name as parameter is created. Initialization of the personalization parameters is done in method do_init of controller class zcl_main01_ctr. In case there is already a cookie found at start up, then this data is used to fill the layout items table mt_items. The cookie get/set method calls are:


call method cl_bsp_server_side_cookie=>get_server_cookie
exporting
name = 'form_items'
application_name = runtime->application_name
application_namespace = runtime->application_namespace
username = syst-uname
session_id = 'same_for_all'
data_name = 'form_items'
changing
data_value = lv_data.


call method cl_bsp_server_side_cookie=>set_server_cookie
exporting
name = 'form_items'
application_name = runtime->application_name
application_namespace = runtime->application_namespace
username = syst-uname
session_id = 'same_for_all'
data_value = lv_data
data_name = 'form_items'
expiry_date_rel = 30.


lv_data is of type xstring. The import/export statements to fill/retrieve the data from/into an internal table are:



...
import form_items to li_md->mt_items from data buffer lv_data.
...
export form_items from li_md->mt_items to data buffer lv_data.
...



Method do_request of controller zcl_main01_ctr creates and calls main.htm or pers.htm depending on the form parameter personalize. This parameter is set to 'true' when the 'Personalize' link on the main.htm page gets selected. The model is passed as page attribute to both, the main.htm and the pers.htm view.


The structure which keeps the personalization data is of type HTMLBFITEM, table type HTMLBFICAT. These types are delivered within the SAP Web AS and were created for some other purpose than keeping user customizing data. But we use them in our example since they just fit our needs pretty well we don’t have to create new types in the DDIC. When implementing personalization in a real world application, you might consider to create specific types depending on what features the application is aimed offer to the user.


The example application uses the fields of structure HTMLBFITEM to represent the following information:

1) FIELD_NAME - keeps the id of the field

2) TEXT - keeps the label text of the field

3) DISP_TYPE - keeps the field type (either 'inputfield' or 'checkbox')
and is used in the view to render the correct phtmlb item tag

4) INVISIBLE - if set to 'X' the field is not displayed

5) HALIGN - keeps the row index of the field


When called the first time, the internal table in our example is initialized with the following data (attribute mt_items in model class):









FIELD_NAME

TEXT

DISP_TYPE

INVISIBLE

HALIGN

first_name

First Name

inputfield

 

1

middle_name

Middle Name

inputfield

 

2

last_name

Last Name

inputfield

 

3

bsp_geek

BSP

checkbox

 

4

abap_geek

ABAP

checkbox

 

5

java_geek

JAVA

checkbox

 

6


After the user has customized the layout, the table data changes to:









FIELD_NAME

TEXT

DISP_TYPE

INVISIBLE

HALIGN

first_name

First Name

inputfield

 

1

middle_name

Middle Name

inputfield

X

2

last_name

Last Name

inputfield

 

3

bsp_geek

BSP

checkbox

 

4

abap_geek

ABAP

checkbox

 

5

java_geek

JAVA

checkbox

X

6


When selecting the ‘Personalize’ link some Javascript in main.htm is executed which opens another browser window by calling the main controller including parameter personalize set to ‘true’.</br>

main.htm


...

      function do_personalize()

      { var s=0; r=1; w=300; h=300; x=screen.width/2;

        x=x-w/2;

        var y=screen.height/4;

        y=y-h/2;

        popUp=window.open('main.do?personalize=true','win','width='+ w

        ',height=' h +', left=' + x ',top=' y +');

      }

...


In method do_request of the main controller the view for displaying the personalization table pers.htm is created and called.

After the user has selected the modifications and pressed button ‘Update’, the personalization data is sent back to the server. Here the internal table mt_items of the model class is updated and the server cookie is set to the new values.




Then parameter mv_update_event (attribute in controller class zcl_main01_ctr) is set to ‘true’. The attribute keeps the information that we actually did submit our customization data. The response returns to the personalization window, which during loading executes some Javascript that triggers the main.htm-page (opener object) to do a submit and get the updated layout.</br>

pers.htm



...
function onLoadWindow()
{
var update = document.getElementById("update").value;
if (update == 'true') {
opener.document.mainform.submit();
self.close();
}
}
window.onload=onLoadWindow;
...


Then the personalization window closes itself. When the response returns to main.htm the customized layout data is displayed.


Not to be forgotten: the iterator of the personalization table is implemented in the controller class zcl_main01_ctr. In method get_column_definitions the column header texts are defined (remember: we used a table type that was originally created for other purposes than storing our customization data). Method render_cell_start adds the checkbox and dropdownlistbox elements to the table view cells.</p>

Coding

class-pool .

" class pool for class ZCL_MAIN01_CTR

" local type definitions

" use this source file for any type declarations (class

" definitions, interfaces or data types) you need for method

" implementation or private method's signature

class cl_pers_iterator definition.

  public section.

    interfaces if_htmlb_tableview_iterator.

    data: mt_pos   type tihttpnvp.

    methods: constructor importing it_pos type tihttpnvp.

  private section.

    data: m_rowref type ref to htmlbfitem.

endclass.                    "cl_pers_iterator DEFINITION

" class ZCL_MAIN01_CTR definition

" public declarations

class ZCL_MAIN01_CTR definition

  public

  inheriting from CL_BSP_CONTROLLER2

  final

  create public .

" public components of class ZCL_MAIN01_CTR

" do not include other source files here!!!

public section.

  data MV_UPDATE_EVENT type STRING .

  methods GET_ITERATOR

    returning

      value(RI_ITERATOR) type ref to IF_HTMLB_TABLEVIEW_ITERATOR .

  methods DO_INIT

    redefinition .

  methods DO_REQUEST

    redefinition .

" protected declarations

" protected components of class ZCL_MAIN_CTR

" do not include other source files here!!!

protected section.

  methods DO_FINISH_INPUT

    redefinition .

  methods DO_HANDLE_EVENT

    redefinition .

" private declarations

" private components of class ZCL_SDN_WL01_CTR

" do not include other source files here!!!

private section.

endclass. "ZCL_MAIN01_CTR definition

" macro definitions

" use this source file for any macro definitions you need

" in the implementation part of the class

" local class implementation

" local class implementation for public class

" use this source file for the implementation part of

" local helper classes

class cl_pers_iterator implementation.

  method constructor.

    mt_pos = it_pos.

  endmethod.                    "constructor

  method if_htmlb_tableview_iterator~get_column_definitions.

    data: tv_column  type tableviewcontrol.

    tv_column-columnname   = 'TEXT'.

    tv_column-title        = 'Field Name'.

    append tv_column to p_column_definitions.

    tv_column-columnname   = 'INVISIBLE'.

    tv_column-horizontalalignment = 'middle'.

    tv_column-title        = 'Invisible'.

    append tv_column to p_column_definitions.

    tv_column-columnname   = 'HALIGN'.

    tv_column-title        = 'Position'.

    append tv_column to p_column_definitions.

  endmethod.                    "IF_HTMLB_TABLEVIEW_ITERATOR~GET_COLUMN_DEFINITIONS

  method if_htmlb_tableview_iterator~render_row_start.

    m_rowref ?= p_row_data_ref.

  endmethod.                    "IF_HTMLB_TABLEVIEW_ITERATOR~RENDER_ROW_START

  method if_htmlb_tableview_iterator~render_cell_start.

    data:

           li_checkbox        type ref to   cl_htmlb_checkbox,

           li_ddlb            type ref to   cl_htmlb_dropdownlistbox.

*------- Render 'invisible' checkbox

    if p_column_key eq 'INVISIBLE'.

      create object li_checkbox.

      li_checkbox->id        = p_cell_id.

      li_checkbox->checked   = m_rowref->invisible.

      p_replacement_bee      = li_checkbox.

    endif.

*------- Render 'position' ddlb

    if p_column_key eq 'HALIGN'.

      create object li_ddlb.

      li_ddlb->id        = p_cell_id.

      li_ddlb->nameofkeycolumn   = 'NAME'.

      li_ddlb->nameofvaluecolumn = 'VALUE'.

      get reference of mt_pos into li_ddlb->table.

      li_ddlb->selection         = p_row_index.

      p_replacement_bee  = li_ddlb.

    endif.

  endmethod.                    "IF_HTMLB_TABLEVIEW_ITERATOR~RENDER_CELL_START

endclass.                    "cl_pers_iterator IMPLEMENTATION

class ZCL_MAIN01_CTR implementation.

" method's implementations

method GET_ITERATOR .

  data:

        lv_lines        type          i,

        lt_pos          type          tihttpnvp,

        ls_pos          type          ihttpnvp,

        li_md           type ref to   zcl_model01.

  li_md ?= get_model( 'm01' ).

*------ Create value table for field positioning

  describe table li_md->mt_items lines lv_lines.

  do lv_lines times.

    ls_pos-name  = syst-index.

    ls_pos-value = syst-index.

    append ls_pos to lt_pos.

  enddo.

  create object ri_iterator type cl_pers_iterator exporting it_pos = lt_pos.

endmethod.

method do_finish_input .

*CALL METHOD SUPER->DO_FINISH_INPUT

  • EXPORTING

  •    GLOBAL_EVENT    =

  •    GLOBAL_MESSAGES =

  •    .

  data:

         lv_data         type          xstring,

         li_md           type ref to   zcl_model01.

  li_md ?= get_model( 'm01' ).

  case global_event.

    when 'update_pers'.

      sort li_md->mt_items by halign.

      export form_items from li_md->mt_items to data buffer lv_data.

      call method cl_bsp_server_side_cookie=>set_server_cookie

        exporting

          name                  = 'form_items'

          application_name      = runtime->application_name

          application_namespace = runtime->application_namespace

          username              = syst-uname

          session_id            = 'same_for_all'

          data_value            = lv_data

          data_name             = 'form_items'

          expiry_date_rel       = 30.

      me->mv_update_event = 'true'.

    when others.

      clear me->mv_update_event.

  endcase.

endmethod.

method DO_HANDLE_EVENT .

*CALL METHOD SUPER->DO_HANDLE_EVENT

  • EXPORTING

  •    EVENT           =

  •    HTMLB_EVENT     =

    •    HTMLB_EVENT_EX  =

  •    GLOBAL_MESSAGES =

  • RECEIVING

  •    GLOBAL_EVENT    =

  •    .

  case event.

    when 'b02'.                          "update button pressed

      global_event = 'update_pers'.

    when others.

  endcase.

endmethod.

method DO_INIT .

*CALL METHOD SUPER->DO_INIT

  •    .

  data:

        lv_data            type         xstring,

        ls_item            type         htmlbfitem,

        li_md              type ref to  zcl_model01.

  li_md ?= create_model(  model_id   = 'm01'

                          class_name = 'zcl_model01' ).

*----- Read server cookie

  call method cl_bsp_server_side_cookie=>get_server_cookie

    exporting

      name                  = 'form_items'

      application_name      = runtime->application_name

      application_namespace = runtime->application_namespace

      username              = syst-uname

      session_id            = 'same_for_all'

      data_name             = 'form_items'

    changing

      data_value            = lv_data.

  if lv_data is not initial.

*----- Extract form layout items from server cookie

    import form_items to li_md->mt_items from data buffer lv_data.

    sort li_md->mt_items by halign.

  else.

*----- Initialize form layout items

    ls_item-disp_type  = 'inputfield'.

    ls_item-field_name = 'first_name'.

    ls_item-text       = 'First Name'.

    ls_item-halign     = '1'.

    append ls_item to li_md->mt_items.

    ls_item-disp_type  = 'inputfield'.

    ls_item-field_name = 'middle_name'.

    ls_item-text       = 'Middle Name'.

    ls_item-halign     = '2'.

    append ls_item to li_md->mt_items.

    ls_item-disp_type  = 'inputfield'.

    ls_item-field_name = 'last_name'.

    ls_item-text       = 'Last Name'.

    ls_item-halign     = '3'.

    append ls_item to li_md->mt_items.

    ls_item-disp_type  = 'checkbox'.

    ls_item-field_name = 'bsp_geek'.

    ls_item-text       = 'BSP'.

    ls_item-halign     = '4'.

    append ls_item to li_md->mt_items.

    ls_item-disp_type  = 'checkbox'.

    ls_item-field_name = 'abap_geek'.

    ls_item-text       = 'ABAP'.

    ls_item-halign     = '5'.

    append ls_item to li_md->mt_items.

    ls_item-disp_type  = 'checkbox'.

    ls_item-field_name = 'java_geek'.

    ls_item-text       = 'JAVA'.

    ls_item-halign     = '6'.

    append ls_item to li_md->mt_items.

*------ Write initial form layout items to server cookie

    export form_items from li_md->mt_items to data buffer lv_data.

    call method cl_bsp_server_side_cookie=>set_server_cookie

      exporting

        name                  = 'form_items'

        application_name      = runtime->application_name

        application_namespace = runtime->application_namespace

        username              = syst-uname

        session_id            = 'same_for_all'

        data_value            = lv_data

        data_name             = 'form_items'

        expiry_date_rel       = 30.

  endif.

endmethod.

method DO_REQUEST .

*CALL METHOD SUPER->DO_REQUEST

  •    .

  data:

        li_vw           type ref to   if_bsp_page,

        lv_form_field   type          string,

        li_md           type ref to   zcl_model01.

  dispatch_input( ).

  li_md ?= get_model( 'm01' ).

  lv_form_field = request->get_form_field( 'personalize' ).

  if lv_form_field is initial.

*------ Request to display main page

    li_vw = create_view( view_name = 'main.htm' ).

    li_vw->set_attribute( name = 'model' value = li_md ).

    call_view( li_vw ).

  elseif lv_form_field eq 'true'.

*------ Request to display personalization page

    li_vw = create_view( view_name = 'pers.htm' ).

    li_vw->set_attribute( name = 'model' value = li_md ).

    call_view( li_vw ).

  endif.

endmethod.

endclass. "ZCL_MAIN01_CTR implementation

*==================================================================

main.htm

      function do_personalize()

      { var s=0; r=1; w=300; h=300; x=screen.width/2;

        x=x-w/2;

        var y=screen.height/4;

        y=y-h/2;

        popUp=window.open('main.do?personalize=true','win','width='+ w ',height=' h +',

        left=' + x ',top=' y ',directories=0,status=0,scrollbars='s ',resizable=' r + ',menubar=0,locationbar=1');

      }

   

Discussion

Personalization of form layout items was described by setting the visibility of fields and checkboxes and rearranging their order. For storing the personalization data server side cookies were used. When implementing the functionality in a real world application, consider that certain legal restrictions regarding privacy might apply since user dependent data is stored.


Extending the personalization options introduced in this weblog, we could offer to the user to select his theme of choice from the five different themes which are shipped within the Web AS (see application 'sbspext_htmlb' for a coding example).


A second weblog covering personalization of table views is in work and will be published shortly.

10 Comments
Labels in this area