Quantcast
Channel: SCN : Blog List - Web Dynpro ABAP
Viewing all 107 articles
Browse latest View live

Step by step to use Component usage clone

$
0
0

In NET311 the topic component usage clone is discussed there. One example is also given there:

The user of a Web Dynpro application can mark multiple lines of a table to display details for each selected data set. The details of one data set is displayed by one usage of a certain component. Thus, the number of component usages equals the number of marked lines, which is not known at design time.
clipboard1.png
The prerequisite for cloning any component usage is, that a single usage of this component has been defined at design time. Any controller having added the name of the static component usage to the list of used controllers / components can then create additional usages of the same component. Each component usage must have a unique name.


I will reuse the component created in the blog Step by Step to create UI elements and context node attribute in the runtime . After I maintain the content number and click create button, the label and text view together with their bound context node attribute will be generated in the runtime. The value of text view "Echo from Usage clone:<number>" is returned by the cloned component usage.

clipboard2.png

1. Create a simple component ZDYNAMICUSAGE which will be consumed as component usage later. Implement the echo method in component controller.

clipboard3.png

2. In order to use component usage, there must be at least one static component usage.Also define usage of the interface controller in the consumer view controller. 

clipboard4.png

3.In method CREATE_CONTEXT, just enhance one line. ( In the original example, I just set the value of newly-generated context attribute to its attribute name)

method CREATE_CONTEXT .

  CONSTANTS: cv_value type string value 'VALUE'.

  data(lo_node) = wd_context->get_child_node( 'DYNAMIC' ).

  data(lo_node_info) = lo_node->get_node_info( ).

  data(lt_attributes) = lo_node_info->get_attributes( ).


  DO iv_count TIMES.

     DATA(lv_attribute_name) = cv_value && sy-index.

     READ TABLE lt_attributes WITH KEY name = lv_attribute_name TRANSPORTING NO FIELDS.

     IF sy-subrc <> 0.

        data(ls_attribute_prop) = VALUE wdr_context_attribute_info( NAME = lv_attribute_name

                                                                    TYPE_NAME = 'STRING' ).

        lo_node_info->add_attribute( attribute_info = ls_attribute_prop ).

        DATA(lv_value) = wd_this->get_value_by_index( sy-index ).

        lo_node->set_attribute( name = lv_attribute_name value = lv_value ).

     ENDIF.

  ENDDO.

endmethod.


4. Define one attribute in view controller, which is an internal table to store all references of component usage instance.

clipboard6.png

In view controller WDDOINT, insert the static component usage to the internal table. The internal table would have the first line as static component usage instance and all remaining ones for cloned component usage from the static one.

 

method WDDOINIT .

  DATA(lo_static_usage) = wd_this->wd_cpuse_zclone_example( ).

  APPEND lo_static_usage TO wd_this->gt_cmp_usages.


endmethod.

 

5. Implement the method get_value_by_index which is called in step3. I will read the internal table gt_cmp_usages by index. Index 1 means this is a static component usage so I directly use the one return from wd_this->wd_cpuse_zclone_example( ). Or else the left one will be cloned from the static one. Since the usage name should be unique, so I use a prefix and an index to fulfill the uniqueness.

 

method GET_VALUE_BY_INDEX .  DATA(lo_static_com_usage) = wd_this->wd_cpuse_zclone_example( ).  DATA: lo_generic_usage TYPE REF TO if_wd_component_usage,        lo_interface_control TYPE REF TO ZIWCI_DYNAMICUSAGE.  READ TABLE wd_this->gt_cmp_usages ASSIGNING FIELD-SYMBOL(<usage>) INDEX iv_index.  CASE iv_index.    WHEN 1.      IF lo_static_com_usage->has_active_component( ) IS INITIAL.         lo_static_com_usage->create_component( ).      ENDIF.      lo_generic_usage = lo_static_com_usage.    WHEN OTHERS.      READ TABLE wd_this->gt_cmp_usages ASSIGNING FIELD-SYMBOL(<dyn_usage>) INDEX iv_index.      IF sy-subrc <> 0.         DATA(lv_usage_name) = 'DYNAMIC_USAGE' && sy-index.         data(lo_dyn_usage) = lo_static_com_usage->create_comp_usage_of_same_type( name = lv_usage_name ).         APPEND lo_dyn_usage TO wd_this->gt_cmp_usages.      ENDIF.      IF lo_dyn_usage->has_active_component( ) IS INITIAL.         lo_dyn_usage->create_component( ).      ENDIF.      lo_generic_usage = lo_dyn_usage.   ENDCASE.   lo_interface_control ?= lo_generic_usage->get_interface_controller( ).   rv_output = lo_interface_control->get_field_value( iv_index ).
endmethod.

In the debugger I would observe that every component usage in gt_cmp_usages are unique:

clipboard7.png


Step by step for Embedding and Displaying an Interface View dynamically

$
0
0

If the component usage is not defined at design time, it is not possible to embed an interface view of this component usage into a ViewUIElementContainer of another view. It is also not possible to define a navigation link connecting any outbound plug of an existing view to an inbound plug of this interface view at design time. In this case methods of the Web Dynpro API have to be applied.

 

I will use the example in the following two blogs to demonstrate the trick.

 

1. Step by Step to create UI elements and context node attribute in the runtime

2. Step by step to use Component usage clone

after you specify the number of rows you want to generate and click the create button, all ui elements and context node attribute will be generated in the runtime. The ui elements marked in blue come from the interface view of another compoonent, and this view embedding logic is also done dynamically in the runtime.

 

clipboard1.png

1. Draw a simple caption in component ZDYNAMICUSAGE which will be consumed by host component ZDYNAMIC.

clipboard2.png

2. The layout of main view in component ZDYNAMIC remains unchanged.

Create an outbound plug, which will be used in API later.

clipboard3.png

Create a new attribute in view controller to store all component usage name, both static one and the dynamical one cloned from the static one.

clipboard4.png

3. In method GET_VALUE_BY_INDEX, store the component usage of both static and dynamic one into the attribute GT_USAGE_NAME created in step2.

  DATA(lo_static_com_usage) = wd_this->wd_cpuse_zclone_example( ).

  DATA: lo_generic_usage TYPE REF TO if_wd_component_usage,
        lo_interface_control TYPE REF TO ZIWCI_DYNAMICUSAGE.

  READ TABLE wd_this->gt_cmp_usages ASSIGNING FIELD-SYMBOL(<usage>) INDEX iv_index.
  CASE iv_index.
    WHEN 1.
      IF lo_static_com_usage->has_active_component( ) IS INITIAL.
         lo_static_com_usage->create_component( ).
      ENDIF.
     APPEND 'ZCLONE_EXAMPLE' TO wd_this->gt_usage_name.
      lo_generic_usage = lo_static_com_usage.

    WHEN OTHERS.
      READ TABLE wd_this->gt_cmp_usages ASSIGNING FIELD-SYMBOL(<dyn_usage>) INDEX iv_index.
      IF sy-subrc <> 0.
         DATA(lv_usage_name) = 'DYNAMIC_USAGE' && sy-index.
         data(lo_dyn_usage) = lo_static_com_usage->create_comp_usage_of_same_type( name = lv_usage_name ).
         APPEND lo_dyn_usage TO wd_this->gt_cmp_usages.
         APPEND lv_usage_name TO wd_this->gt_usage_name.
      ENDIF.
      IF lo_dyn_usage->has_active_component( ) IS INITIAL.
         lo_dyn_usage->create_component( ).
      ENDIF.
      lo_generic_usage = lo_dyn_usage.
   ENDCASE.

   lo_interface_control ?= lo_generic_usage->get_interface_controller( ).

   rv_output = lo_interface_control->get_field_value( iv_index ).
endmethod.

4. In method ONACTIONCREATE, now also create seperate view container UIElement instance for each component usage. That view container will be used to embed

the interface view exposed by component ZDYNAMICUSAGE. Then we use API prepare_dynamic_navigation to create a navigation link dynamically, from host view in component ZDYNAMIC to the interface view of component ZDYNAMICUSAGE. The component usage name stored in attribute gt_usage_name in step3 will be used during API call. Finally fire the outbound plug of MAIN view to make the embedded view displayed in UI.

 

method ONACTIONCREATE .

  CONSTANTS: cv_label TYPE string VALUE 'LABEL',
             cv_field TYPE string VALUE 'FIELD',
            cv_container TYPE string VALUE 'EMBEDDED',
             cv_bind_text TYPE string VALUE 'DYNAMIC.VALUE'.
  DATA: lv_count type i,
               lo_container type ref to cl_Wd_uielement_container.
  wd_context->get_attribute( EXPORTING name = 'NUMBER' IMPORTING value = lv_count ).

  CHECK lv_count > 0.
  create_context( lv_count ).
  DATA(lo_root) = wd_this->mr_view->get_element( 'DYNAMICUI' ).
  lo_container ?= lo_root.
  lo_container->remove_all_children( ).

  DO lv_count TIMES.
    data(lv_field_id) = cv_field && sy-index.
    data(lv_label_id) = cv_label && sy-index.
    data(lv_bind_path) = cv_bind_text && sy-index.
    DATA(lo_text_view) = cl_wd_text_view=>new_text_view( id = lv_field_id bind_text = lv_bind_path ).
    DATA(lo_label) = cl_wd_label=>new_label( id = lv_label_id label_for = lo_text_view->id text = lv_label_id ).
    CL_WD_ROW_HEAD_DATA=>new_row_head_data( element = lo_label ).
    cl_wd_row_data=>new_row_data( element = lo_text_view ).

    DATA(lv_container_id) = cv_container && sy-index.
   data(lo_view_cont) = CL_WD_VIEW_CONTAINER_UIELEMENT=>new_view_container_uielement( id = lv_container_id ).
    CL_WD_ROW_HEAD_DATA=>new_row_head_data( element = lo_view_cont ).
    lo_container->add_child( the_child = lo_label ).
    lo_container->add_child( the_child = lo_text_view ).
    lo_container->add_child( the_child = lo_view_cont ).

  ENDDO.

  DATA: lr_api_main_view TYPE REF TO if_wD_view_controller.

  lr_api_main_view = wd_this->wd_get_api( ).

  DO lv_count TIMES.
    READ TABLE wd_this->gt_usage_name ASSIGNING FIELD-SYMBOL(<usage_name>) INDEX sy-index.
    DATA(lv_position) = 'MAIN/' && cv_container && sy-index.
    lr_api_main_view->prepare_dynamic_navigation(
       source_window_name = 'ZDYNAMIC'
       source_vusage_name = 'MAIN_USAGE_0'
       source_plug_name   = 'VIEW_TO_USAGE'
       target_component_name = 'ZDYNAMICUSAGE'
       target_component_usage = <usage_name>
       target_view_name       = 'ZDYNAMICUSAGE'
       target_plug_name       = 'DEFAULT'
       target_embedding_position = lv_position ).

    wd_this->fire_view_to_usage_plg( ).
  ENDDO.
endmethod.

 

How to find the value of source_vusage_name?

clipboard5.png

Reading ALV Filter values in Webdynpro ABAP

$
0
0

Hi,

 

I got a requirement  where i need to read the filtered values from ALV table in webdynpro ABAP. Some workaround helped me to make my task easier.Below is the code which i used to read the filtered values.

 

   DATA: lr_interfacecontroller    TYPE REF TO iwci_salv_wd_table.

   DATA: l_value                       TYPE if_salv_wd_table=>s_type_param_get_ui_info.

   DATA: lt_salv_bs_t_int           TYPE salv_bs_t_int.

   DATA: ls_salv_bs_t_int          TYPE i.

   DATA: l_displayed_element    TYPE LINE OF if_salv_wd_table=>s_type_param_get_ui_info-t_displayed_elements.

   DATA: lt_visible_indices         TYPE cl_wdha_assist=>indices.
  DATA: lw_visible_indices         LIKE LINE OF lt_visible_indices.

 

      TRY.
      lr_interfacecontroller =   wd_this->wd_cpifc_used_component( )." ( In my case :   lr_interfacecontroller =   wd_this->wd_cpifc_source_roles_dirclty( ).

    CATCH cx_wdr_rt_exception.
  ENDTRY.

 

   IF NOT lr_interfacecontroller IS INITIAL.

       l_value = lr_interfacecontroller->get_ui_info( ).  " ( GET_UI_INFO( ) : The method returns information about the currently displayed ALV.)

     

        IF  l_value-s_service_info-is_filtered = abap_true. "( To check if filter is applied)

 

          lt_salv_bs_t_int = l_value-t_displayed_elements.

              CLEAR lt_visible_indices[].

               LOOP AT   l_value-t_displayed_elements  INTO l_displayed_element.
        l_index-index = l_displayed_element.
        APPEND l_index TO lt_visible_indices.       " ( Returns the index(s) of the internal table records which we have selected from filtered values)
      ENDLOOP.

 

         SORT lt_visible_indices BY index.

          

         

       ENDIF.

 

   ENDIF.

 

Hope this helps for all who have similar requirement which makes their task easier.

Comments/Suggestions are welcome.

 

Thanks

Katrice Hawkins

Webdynpro trace tool WD_TRACE_TOOL

$
0
0

You can use tcode WD_TRACE_TOOL to switch on trace.

clipboard1.png

clipboard2.png

After that when you launch your webdynpro application, you can observe there is a Webdynpro trace window embedded in the bottom of the application. You can either deactivate the trace in old dynpro tool or in that embedded window.

clipboard3.png

After you click Store trace as Zip File & Finish trace,you can save the trace file as zip locally.

clipboard4.png

The trace setting is checked and loaded in the very beginning phase of webdynpro runtime initialization,

clipboard5.png

The trace is actually added in the runtime via the utility macro below:

clipboard6.png

And finally into trace file with xml format

clipboard7.png

Wedynpro runtime performance trace tool

$
0
0

Under package SWDP_PERFORMANCE_VERIFICATION there is a pair of reports WDT_TRACE_ON and WDT_TRACE_OFF which could switch on and switch off performance trace.

To switch on trace, set the user parameter WDA_PERF_TRACE_ON as abap_true, then run report WDT_TRACE_ON.

clipboard1.png

In the webdynpro runtime framework code,you could see there is code to record the runtime performance information implemented via keyword GET RUN TIME FIELD.

 

clipboard2.png

You can find all positions where framework has done such performance recording with the help of report RS_ABAP_SOURCE_SCAN with search keyword name = macro name wdr_perf_trace_on and search package name = SWDP_RUNTIME_CORE.

clipboard3.png

Once you activate the performance trace, you can run your application in UI as usual. After application runs over, you can deactivate the trace by running report WDT_TRACE_OFF, it will retrieve all runtime performance trace information with start and stop time.

clipboard4.png

the report will also do some calculations based on those two times and display the result:

clipboard5.png

For description of each columns, please refer to description maintained in DDIC structure STRC_S_STAT.

clipboard6.png

How to check supported web browser version

$
0
0

Since recently when I am supporting local customers I am frequently asked by question like "Which version of Internet explorer is supported in NW7XX for ABAP webdynpro / BSP?" and "is firefox also supported?",

I just write this step by step guide how to figure it out.

 

1. openhttp://service.sap.com, then click hyperlink "Product availability"

clipboard1.png

2. Now Product Availability Matrix is opened. Choose the product you want to query under "Available as of Q4/2013 or Q1/2014", for example SAP NETWEAVER 7.4

clipboard2.png

3. click tab "Technical Release Information"->"Web Browser Platforms". If we need to check web browsers against ABAP webdynpro and BSP, we just need to choose

"Application Server ABAP" for Product Instance. You can set filter for Firebox, Chrome and IE accordingly.

clipboard3.png

Webdynpro : New Layout's in SAP NetWeaver 7.40

$
0
0


Hi,

 

Following are the new layout's in SAP NetWeaver 7.40.

 

1) Form Layout

2) Matrix Layout

3) Row Layout

4) Flow Layout

5) Formlayout Advance

6) FormDesign Layout

7) Grid Layout

8) Raster Layout

 

Commets/Suggestions/Opinions/Detailed Explanations are welcome.

 

Thanks

Katrice

How to get PDF render trace of ABAP webdynpro interactiveForm control

$
0
0

In ABAP webdynpro you can use InteractiveForm control to achieve PDF render, as long as you specify the dataSource of PDF via context node, and form template uploaded via tcode SFP.

clipboard1.png

In some case you need to know the details about PDF rendering process by ADS, for example the PDF is failed to be rendered, and you want to know the root cause, or you meet with a performance issue of PDF rendering, and you want to find the bottleneck ( is it caused by too many elements in form template, or inefficient script written? ). Then you can follow the steps below to get the detail PDF render trace:

 

1. set a breakpoint on method CL_FP_PDF_OBJECT~EXECUTE_INTERNAL. Render your PDF as usual. The breakpoint should be triggered.

In the debugger callstack you can also know how the PDF render is triggered from ABAP webdynpro layer.

clipboard2.png

2. Change the variable _adstrace's content to 4 in debugger. The source code line 125 gives you a hint that you can just set a user parameter to avoid the manual change on _adstrace in debugger each time. 

clipboard3.png

System->Own Data:

clipboard4.png

And maintain the parameter value as 04.

clipboard5.png

3. Debug until you reach line 218. Click F6 to step over it.

clipboard6.png

Download the PDF binary code stored in variable l_soapresponse-rp_streams into your local laptop:

clipboard7.png

Open the local PDF, click the attachment icon as below, then you can find all types of useful information there:

 

1. the original form template

 

2. the runtime performance trace file (trace.txt)

 

3. the xml data file for the pdf (xfd.xml)

 

4. detail information raised by ADS server during PDF render time (error.pdf)

clipboard8.png

The error.pdf contains all kinds of information including warning messages raised by ADS, which could be used to improve your form template design.

clipboard9.png


New book: "100 Tips and Tricks for Web Dynpro ABAP"

$
0
0

Two weeks ago SAP Press published the following book in German:

 

 

"Web Dynpro ABAP - 100 Tipps und Tricks"

 

 

 

9783836222747.jpg

 

 

 

More about the content:

 

Wenn es darum geht, komplexe Benutzeroberflächen mit Web Dynpro ABAP effizient zu gestalten, kann Ihnen kaum einer etwas vormachen. Doch trotz Ihrer Erfahrung fragen Sie sich ab und zu, ob sich manche Aufgaben nicht noch besser lösen lassen? Die 100 Expertentipps in diesem Buch zeigen Ihnen, wie’s geht! Blättern Sie ein wenig und lesen Sie zum Beispiel, wie Sie Swap Root Element richtig einsetzen, neue Layout-Typen verwenden oder die Performance Ihrer Anwendungen optimieren. Darüber hinaus finden Sie Tipps zum Floorplan Manager. Mit diesem Buch haben Sie stets noch ein *** im Ärmel!


Aus dem Inhalt:

• Architektur und Komponenten von Web-Dynpro-Anwendungen

• Web-Dynpro-Context verwenden

• User-Interface-Elemente einbauen

• Mit Tabellen arbeiten

• Im Editor arbeiten

• Fehler beheben

• Web-Dynpro-Anwendungen analysieren

• Anwendungen mit Web Dynpro anpassen, konfigurieren und erweitern

• Administration

• Mit dem Floorplan Manager arbeiten

 

You can order the book and find out more information at

http://www.sap-press.de/3334

I'm looking forward for your Feedback.

 

Best regards

Dominik Ofenloch

How to get mandatory attribute list of ALV in Web dynpro ABAP

$
0
0

Hi,

 

Welcome, I will not take much time of yours

-------------------------------------

 

I have come across the scenario, where we need to check mandatory attributes of alv in Web dynpro abap.

 

In complex applications we may have many views with alv table data and we need to check mandatory attributes of alv tables accordingly.

 

We all know that,..... we can not perform the mandatory checks as we do for normal view fields by using methd CHECK_MANDATORY_ATTR_ON_VIEW of class CL_WD_DYNAMIC_TOOL,

instead, we need to use method CHECK_MANDATORY_ATTRIBUTES.

 

Problem:

The method CHECK_MANDATORY_ATTRIBUTES requires the attributes list, for which the mandatory check has to happen .

 

Oh, then

how to get the mandatory attributes from alv table by using VIEW reference?.

 

Then, isn't it a good idea,

          if we have a method which does the trick i.e. getting alv table mandatory attribute list by using VIEW reference.

 

Every alv table is embedded into an internal view called VIEW_TABLE and it contains all the columns details of alv during runtime.

 

Now, how to reach/get reference of  VIEW_TABLE element  from view ?

         We do get the reference of VIEW_TABLE by using recursive call of our method.

   

 

Okay, we got some idea of how we are going to get the columns of alv table using VIEW reference.

 

Now, its time to get into some coding part

 

Create a method GET_ALV_MANDATORY_ATTR as below

 

Parameters

params.PNG

 

GET_ALV_MANDATORY_ATTR

METHOD get_alv_mandatory_attr .

 

  "Define Data
  DATA:
    lt_view_elements  TYPE wdr_element_tab,
    lt_children       TYPE wdr_view_for_area_tab,
    ls_children       TYPE wdr_view_for_area_line,
    lo_wdr_view       TYPE REF TO cl_wdr_view,
    lo_wd_view        TYPE REF TO if_wd_view,
    lo_wdr_component  TYPE REF TO cl_wdr_component,
    lo_wd_column      TYPE REF TO cl_wd_table_column,
    lv_column_name    TYPE string,
    lv_node_path      TYPE string,
    lv_str            TYPE string,                          "#EC NEEDED
    lo_input_field    TYPE REF TO cl_wd_input_field,
    lt_ext_mapping    TYPE wdr_reverse_mapped_node_infos,
    ls_ext_mapping    TYPE wdr_reverse_mapped_node_info,
    ls_attr           LIKE LINE OF ct_attr_list.


  FIELD-SYMBOLS:
             <fs_view_element> TYPE wdr_element_line.

  "Get the delegating view reference and view elements
  lo_wdr_view ?= io_wd_view.

  lt_children = lo_wdr_view->children.

 

  "loop over to the view elements till the actual ALV table
  LOOP AT lt_children INTO ls_children.

 

    "Get the view object with table entries

    IF ls_children-view_object->get_id( ) EQ 'VIEW_TABLE'.

 

      lt_view_elements = lo_wdr_view->get_elements( ).


      "Loop over the view elements, set the properties


      LOOP AT lt_view_elements ASSIGNING <fs_view_element>.

 

        "if the element is an UI element proceed further to property
        "settings

 

        IF ( <fs_view_element>-view_element->_definition_name
                                            EQ 'INPUT_FIELD' ).

 

          lo_input_field ?= <fs_view_element>-view_element.

 

          IF lo_input_field->get_state( ) EQ 1.


            lo_wd_column ?= <fs_view_element>-view_element->_parent.


            lv_column_name = lo_wd_column->get_id( ).

            lo_wdr_component ?=
                      <fs_view_element>-view_element->_component.

 

            "Get external mapping details of interface controller

            lt_ext_mapping = lo_wdr_component->get_external_mappings( ).
            READ TABLE lt_ext_mapping INTO ls_ext_mapping INDEX 1.
            " Get node path
            SPLIT ls_ext_mapping-path AT '.'
                  INTO: lv_str lv_node_path.

 

            CLEAR ls_attr.
            ls_attr-node_path = lv_node_path.
            ls_attr-element_index = 0.
            ls_attr-attribute_name = lv_column_name.

            APPEND ls_attr TO ct_attr_list.

 

          ENDIF.
        ENDIF.

      ENDLOOP.

 

    ELSE.
      " Pass the next view object for recursive call
      lo_wd_view ?= ls_children-view_object.

   

     get_alv_mandatory_attr(
        EXPORTING
            io_wd_view = lo_wdr_view
        CHANGING
          ct_attr_list = ct_attr_list
    ).

 

    ENDIF.


  ENDLOOP.
ENDMETHOD.

 

Note:  The below statement

<fs_view_element>-view_element->_definition_name

                                            EQ 'INPUT_FIELD'

 

I have given an example of check for a column editor of type input field.

 

You can also check for CHECKBOX, TEXT_EDIT,DROPDOWN_BY_KEY, DROPDOWN_BY_IDX, etc

 

 

Hope this blog is helpful for those looking for getting mandatory columns of ALV table in Webdynpro ABAP using VIEW reference.

 

 

I appreciate your comments/suggestions/feedback.

 

Please award points if useful

Step by step about how to develop user defined value help

$
0
0


For input attribute totally five input help mode could be selected. In most of time we would always like to leverage the existing dictionary search help defined in DDIC. However if existing one could not fulfill our requirement, we have to develop our own value help by ourselves.

http://farm6.staticflickr.com/5492/11335713166_6e345e0939_o.png


I have used a simple example to demonstrate how to use "Freely Programmed" input help mode.

I have one consumer component ZCONSUMER, and one component ZUSER_HELP.
ZCONSUMER just have one input field for post ID and post description. When click value help of Post ID, the view of ZUSER_HELP will be opened and there is a SQL select to fetch the description according to post ID from database table.

 

http://farm8.staticflickr.com/7369/11335713086_6a508d0bef_o.png

1. in ZUSER_HELP, create the context node with attribute ID for post id, and description for post description. Since I use external mapping for data transfer from consumer component to value help provider component, so I mark the flag "Input Element(Ext.)". Define the node as interface node.

 

http://farm8.staticflickr.com/7428/11335780363_2e56ff9e0a_o.png

2. Implement the standard component interface IWD_VALUE_HELP. Redefine the method SET_VALUE_HELP_LISTENER. Also include your own value help view into the interface view WD_VALUE_HELP.

http://farm6.staticflickr.com/5503/11335642695_ba0efd36b4_o.png

In the method SET_VALUE_HELP_LISTENER, I select the post description from database table and store it to attribute DESCRIPTION.
The listener reference is also stored into member variable of component controller for later usage.

method SET_VALUE_HELP_LISTENER .   data: lv_id type socialdata-internal_id,         lv_text type socialdata-socialposttext.   wd_this->mr_listener = listener.   data(lo_node) = wd_context->get_child_node( IF_COMPONENTCONTROLLER=>wdctx_post ).   CHECK lo_node IS NOT INITIAL.   lo_node->get_attribute( EXPORTING name = 'ID' IMPORTING value = lv_id ).   SELECT SINGLE socialposttext INTO lv_text from socialdata where internal_id = lv_id.   CHECK sy-subrc = 0.   lo_node->set_attribute( name = 'DESCRIPTION' value = lv_text ).
endmethod.

3. Draw a button in value help view to close the value help popup window once clicked. Just use the reference stored in step2 to close window.
method ONACTIONCLOSE .
  wd_comp_controller->mr_listener->close_window( ).
endmethod.

 

4. in consumer component ZCONSUMER, create component usage to ZUSER_HELP, and create context node POST. Choose Input help mode Freely Programmed and choose component usage ZUSER_DEFINE_HELP from value help.

http://farm3.staticflickr.com/2856/11335738714_8032846b54_o.png

Create an interface controller usage on component usage ZUSER_DEFINE_HELP and finish the context node mapping, or else you will meet with runtime error

"External mapping of Node ZUSER_HELP#COMPONENTCONTROLLER.CONTEXT.POST is Not Completed yet".

http://farm6.staticflickr.com/5493/11335642515_1852cde887_o.png

 

Now once clicked the value help icon of input field Post ID, the value help window provided by component ZUSER_HELP will pop up automatically.

http://farm8.staticflickr.com/7434/11335780243_5af7ea660a_o.png

And once close button is clicked, the description field of consumer component will be filled.

http://farm3.staticflickr.com/2858/11335738604_3bde2f0b4d_o.png

How to get mandatory attribute list of ALV in Web dynpro ABAP

$
0
0

Hi,

 

Welcome, I will not take much time of yours

-------------------------------------

 

I have come across the scenario, where we need to check mandatory attributes of alv in Web dynpro abap.

 

In complex applications we may have many views with alv table data and we need to check mandatory attributes of alv tables accordingly.

 

We all know that,..... we can not perform the mandatory checks as we do for normal view fields by using methd CHECK_MANDATORY_ATTR_ON_VIEW of class CL_WD_DYNAMIC_TOOL,

instead, we need to use method CHECK_MANDATORY_ATTRIBUTES.

 

Problem:

The method CHECK_MANDATORY_ATTRIBUTES requires the attributes list, for which the mandatory check has to happen .

 

Oh, then

how to get the mandatory attributes from alv table by using VIEW reference?.

 

Then, isn't it a good idea,

          if we have a method which does the trick i.e. getting alv table mandatory attribute list by using VIEW reference.

 

Every alv table is embedded into an internal view called VIEW_TABLE and it contains all the columns details of alv during runtime.

 

Now, how to reach/get reference of  VIEW_TABLE element  from view ?

         We do get the reference of VIEW_TABLE by using recursive call of our method.

 

 

Okay, we got some idea of how we are going to get the columns of alv table using VIEW reference.

 

Now, its time to get into some coding part

 

Create a method GET_ALV_MANDATORY_ATTR as below

 

Parameters

params.PNG

 

GET_ALV_MANDATORY_ATTR

METHOD get_alv_mandatory_attr .

 

  "Define Data
  DATA:
    lt_view_elements  TYPE wdr_element_tab,
    lt_children       TYPE wdr_view_for_area_tab,
    ls_children       TYPE wdr_view_for_area_line,
    lo_wdr_view       TYPE REF TO cl_wdr_view,
    lo_wd_view        TYPE REF TO if_wd_view,
    lo_wdr_component  TYPE REF TO cl_wdr_component,
    lo_wd_column      TYPE REF TO cl_wd_table_column,
    lv_column_name    TYPE string,
    lv_node_path      TYPE string,
    lv_str            TYPE string,                          "#EC NEEDED
    lo_input_field    TYPE REF TO cl_wd_input_field,
    lt_ext_mapping    TYPE wdr_reverse_mapped_node_infos,
    ls_ext_mapping    TYPE wdr_reverse_mapped_node_info,
    ls_attr           LIKE LINE OF ct_attr_list.


  FIELD-SYMBOLS:
             <fs_view_element> TYPE wdr_element_line.

  "Get the delegating view reference and view elements
  lo_wdr_view ?= io_wd_view.

  lt_children = lo_wdr_view->children.

 

  "loop over to the view elements till the actual ALV table
  LOOP AT lt_children INTO ls_children.

 

    "Get the view object with table entries

    IF ls_children-view_object->get_id( ) EQ 'VIEW_TABLE'.

 

      lt_view_elements = lo_wdr_view->get_elements( ).


      "Loop over the view elements, set the properties


      LOOP AT lt_view_elements ASSIGNING <fs_view_element>.

 

        "if the element is an UI element proceed further to property
        "settings

 

        IF ( <fs_view_element>-view_element->_definition_name
                                            EQ 'INPUT_FIELD' ).

 

          lo_input_field ?= <fs_view_element>-view_element.

 

          IF lo_input_field->get_state( ) EQ 1.


            lo_wd_column ?= <fs_view_element>-view_element->_parent.


            lv_column_name = lo_wd_column->get_id( ).

            lo_wdr_component ?=
                      <fs_view_element>-view_element->_component.

 

            "Get external mapping details of interface controller

            lt_ext_mapping = lo_wdr_component->get_external_mappings( ).
            READ TABLE lt_ext_mapping INTO ls_ext_mapping INDEX 1.
            " Get node path
            SPLIT ls_ext_mapping-path AT '.'
                  INTO: lv_str lv_node_path.

 

            CLEAR ls_attr.
            ls_attr-node_path = lv_node_path.
            ls_attr-element_index = 0.
            ls_attr-attribute_name = lv_column_name.

            APPEND ls_attr TO ct_attr_list.

 

          ENDIF.
        ENDIF.

      ENDLOOP.

 

    ELSE.
      " Pass the next view object for recursive call
      lo_wd_view ?= ls_children-view_object.

 

     get_alv_mandatory_attr(
        EXPORTING
            io_wd_view = lo_wd_view
        CHANGING
          ct_attr_list = ct_attr_list
    ).

 

    ENDIF.


  ENDLOOP.
ENDMETHOD.

 

Note:  The below statement

<fs_view_element>-view_element->_definition_name

                                            EQ 'INPUT_FIELD'

 

I have given an example of check for a column editor of type input field.

 

You can also check for CHECKBOX, TEXT_EDIT,DROPDOWN_BY_KEY, DROPDOWN_BY_IDX, etc

 

 

Hope this blog is helpful for those looking for getting mandatory columns of ALV table in Webdynpro ABAP using VIEW reference.

 

 

I appreciate your comments/suggestions/feedback.

Using a special tool while debugging in Web Dynpro ABAP

$
0
0


Hi, Welcome

 

I would like to demonstrate the scenario of using a special tool called "Web Dynpro" while debugging WDA applications.

 

While debugging Web dynpro applications, we would be looking for viewing the data filled at runtime in context nodes, along with available runtime objects of whole WDA component.

 

The new debugger application is having a special tool called "Web Dynpro", which helps in analyzing the WD context data at runtime along other runtime objects.

 

Pre-requisite:

Basic knowledge of Web Dynpro ABAP, OO ABAP

 

Scenario:

Here, I would like to demonstrate the simple application with a table filled with 3 rows of data as below

 

  • Creat a WDA component with a view V_MAIN
  • Create a context node with attributes FIRST_NAME & SECOND_NAME
  • Fill the data  in method WDDOINIT( )  of component controller & activate the component
  • Add an ui element TABLE and bind it to the context node of component controller
  • Creata an application and here is the out of our application

1.PNG

Now, I set "External Breakpoint" in method WDDOMODIFYVIEW( ) of view V_MAIN

 

When we run our application, the debugging window opens up as below

2.PNG

Choose your preferred desktop in debugging window & click on "New Tool" as shown in the above picture

 

Upon clicking on New tool button, a dialong box opens up as below

3.PNG

Choose  "Web Dynpro" option under "Special Tools" node ( as shown in above picture ) and now the web dynpro debugger window opens up as below

4_1.png

 

Here, we can see WD component structure with component controller, view, window information.

Chose component controller and then open the node DEMO_1, we can see the values filled inside the context node along with lead selection details

 

We can also, navigate into the context of view as below

5_1.png

Also, we can visit the component usages and analyze the data filled in respective context nodes.

 

This tool is very helpful for analysing context nodes and its data filled at runtime in complex applications

 

 

I appreciate any comments/feedback

Custom getter & setter methods in Webdynpro ABAP - Part 1

$
0
0

Hello... Welcome

 

While developing complex WDA applications, we may have to have many context nodes defined and its very much required to get and set data from/to these context nodes.

 

For getting and setting data from/to a context node, we need to follow the below process

 

  • Define data of type node ( element/elements )
  • Get the node reference by using node names
  • Get the elements using node reference
  • Get data / set data using element reference or node reference based on cardinality i.e. if cardinality is 0...1, 1..1 ( structure ) 0..n, 1...n ( table )

 

If we have many nodes in our application, say around 10-15 context nodes, we have to repeat above steps for each read/write data access

 

So, its better idea to have a common method for getting data from context node / for setting data to context node.

 

HELPER CLASS:

 

You would be wondering why this HELPER CLASS is needed ?,

 

It very much helpful to have all common methods in a class and it can be called from any view/ controller method.Hence,it is named as helper class to my application.

 

I have created the below 2 static methods in class ZCL_WD_HELPER_CLASS

  • GET_CTX_STAT_ATTR(  ) - Get static attributes / table data of context node
  • SET_CTX_STAT_ATTR(  ) - Set static attributes / table to context node

 

 

Now, let us look at these methods signature & logic

 

 

Method: GET_CTX_STAT_ATTR(  ).

 

Signature:

get.PNG

Logic:

GET_CTX_STAT_ATTR

METHOD get_ctx_stat_attr.
  DATA lo_nd                TYPE REF TO if_wd_context_node.
  DATA lo_nd_struct_descr   TYPE REF TO cl_abap_structdescr.
  DATA lo_nd_info           TYPE REF TO if_wd_context_node_info.
  DATA lo_stat_data         TYPE REF TO data.
  DATA lv_node_name         TYPE string.
  DATA lv_type_name         TYPE string.
  DATA lv_index             TYPE i.
  DATA lo_typedescr_target  TYPE REF TO cl_abap_typedescr.

  FIELD-SYMBOLS: <lt_stat_attr>     TYPE STANDARD TABLE,
                 <ls_stat_attr>     TYPE any.
  "----------------------------------------------------
  "Purpose: Get data from context node of given controller context
  "----------------------------------------------------
  CLEAR: ed_error_message,
          ed_stat_attr.

  "===================================


  "check if type of target is table
  lo_typedescr_target =
  cl_abap_typedescr=>describe_by_data( p_data = ed_stat_attr ).
  IF lo_typedescr_target IS NOT BOUND.
    RETURN.
  ENDIF.


  "check if context is supplied
  IF io_context IS  BOUND.
    lv_node_name = id_node_name.
    TRANSLATE lv_node_name TO UPPER CASE.


    TRY.
        "read node
        lo_nd = io_context->get_child_node( name = lv_node_name ).
        IF lo_nd IS BOUND.

          " Return if node is not dirty, and caller wants values only if dirty
          IF ib_only_if_dirty = abap_true AND
             lo_nd->is_changed_by_client( ) = abap_false.
            RETURN.
          ENDIF.

          "get node info
          lo_nd_info = lo_nd->get_node_info( ).
          IF lo_nd_info IS BOUND.

            "get the type descriptor of node
            lo_nd_struct_descr =
            lo_nd_info->get_static_attributes_type( ).
            "check if type name is DDtype
            IF lo_nd_struct_descr IS BOUND AND
               lo_nd_struct_descr->is_ddic_type( ) EQ abap_true.

              lv_type_name = lo_nd_struct_descr->get_relative_name( ).

              "============================================
              "based on node cardinality & supplied index,
              " create data type & get data from context

              IF lo_nd_info->is_multiple( ) EQ abap_true AND
                 id_index = 0.

                "============================================
                "return if target data type is not of kind - table

                IF  lo_typedescr_target->kind NE
                    lo_typedescr_target->kind_table.
                  ed_error_message = 'Data mismatch against context node'.
                  RETURN.
                ENDIF.

                "create data object based cardinality
                CREATE DATA lo_stat_data TYPE TABLE OF (lv_type_name).

                ASSIGN lo_stat_data->* TO <lt_stat_attr>.


                IF <lt_stat_attr> IS ASSIGNED.
                  lo_nd->get_static_attributes_table(
                   IMPORTING table = <lt_stat_attr> ).

                  ed_stat_attr = <lt_stat_attr>.
                ENDIF.
              ELSE.

                "============================================
                "return if target data type is not of kind - Structure
                IF  lo_typedescr_target->kind NE
                    lo_typedescr_target->kind_struct.
                  ed_error_message = 'Data mismatch against context node'.
                  RETURN.
                ENDIF.


                "Prepare lv_index, based on id_index
                IF id_index EQ 0.
                  lv_index = 1.
                ELSE.
                  lv_index = id_index.
                ENDIF.

                "create data object based cardinality
                CREATE DATA lo_stat_data TYPE (lv_type_name).

                ASSIGN lo_stat_data->* TO <ls_stat_attr>.

                IF <ls_stat_attr> IS ASSIGNED.
                  lo_nd->get_static_attributes(
                   EXPORTING index = lv_index
                   IMPORTING static_attributes = <ls_stat_attr> ).


                  ed_stat_attr = <ls_stat_attr>.
                ENDIF.
              ENDIF.
            ENDIF.
          ENDIF.
        ELSE.
          ed_error_message = 'Node does not exist in the provided context'.
        ENDIF.
      CATCH cx_root.                                     "#EC CATCH_ALL
        ##no_handler
        ed_error_message = 'Error occured during context node read'.
    ENDTRY.
  ELSE.
    ed_error_message = 'Context is not supplied'.
    RETURN.
  ENDIF.
ENDMETHOD.


Okay, now let us see how to use the method GET_CTX_STAT_ATTR( ) to get data from context node

 

Example:

Get data : Let us say we have a context node MY_NODE_T in component controller context with cardinality 0....n /1..n

 

DATA lt_my_node_t     TYPE wd_this->elements_my_node_t.  DATA lv_error_message TYPE string.  CALL METHOD zcl_wd_helper_class=>get_ctx_stat_attr    EXPORTING      io_context       = wd_context      id_node_name     = 'MY_NODE_T'
*     id_index         = 0
*     ib_only_if_dirty = ABAP_FALSE    IMPORTING      ed_stat_attr     = lt_my_node_t      ed_error_message = lv_error_message.

 

Get data : Let us say we have a context node MY_NODE_S in component controller context with cardinality 0....1 / 1...1

 

DATA ls_my_node_s     TYPE wd_this->element_my_node_s.  DATA lv_error_message TYPE string.  CALL METHOD zcl_wd_helper_class=>get_ctx_stat_attr    EXPORTING      io_context       = wd_context      id_node_name     = 'MY_NODE_S'
*     id_index         = 0
*     ib_only_if_dirty = ABAP_FALSE    IMPORTING      ed_stat_attr     = ls_my_node_s      ed_error_message = lv_error_message.

 

Continued.......

Custom getter & setter methods in Webdynpro ABAP - Part 2

Custom getter & setter methods in Webdynpro ABAP - Part 2

$
0
0

Hello welcome again

 

Hope, you have gone through the below link for custom getter method GET_CTX_STAT_ATTR( )

Custom getter & setter methods in Webdynpro ABAP - Part 1

 

Now, let us look into to the method SET_CTX_STAT_ATTR( ).

 

Method: SET_CTX_STAT_ATTR( )

 

Signature:

set.PNG

Logic:

Header 1

METHOD set_ctx_stat_attr.
  DATA lo_nd                TYPE REF TO if_wd_context_node.
  DATA lo_nd_info          TYPE REF TO if_wd_context_node_info.
  DATA lv_type_name        TYPE string.
  DATA lv_node_name        TYPE string.
  DATA lo_nd_struct_descr  TYPE REF TO cl_abap_structdescr.


  "----------------------------------------------------
  "Purpose: set data to context node of given controller context
  "----------------------------------------------------
  CLEAR: ed_error_message.

  "===================================
  "check if context is supplied
  IF io_context IS  BOUND.
    lv_node_name = id_node_name.
    TRANSLATE lv_node_name TO UPPER CASE.
    TRY.
        "read node
        lo_nd = io_context->get_child_node( name = lv_node_name ).
        IF lo_nd IS BOUND.
          " check if dirty flag needs to be set
          IF id_set_dirty EQ abap_true.
            lo_nd->set_changed_by_client( abap_true ).
          ENDIF.
          "get node info
          lo_nd_info = lo_nd->get_node_info( ).
          IF lo_nd_info IS BOUND.
            lo_nd_struct_descr =
            lo_nd_info->get_static_attributes_type( ).
            IF lo_nd_struct_descr IS BOUND AND
              lo_nd_struct_descr->is_ddic_type( ) EQ abap_true.
              lv_type_name = lo_nd_struct_descr->get_relative_name( ).

              "based on node cardinality, bind data
              IF lo_nd_info->is_multiple( ) EQ abap_true.
              ctx_bind_table(
                  EXPORTING io_node = lo_nd
                            id_node_name = lv_node_name
                            id_stat_attr = id_stat_attr
                            id_nd_type_name = lv_type_name
                  IMPORTING ed_error_message = ed_error_message ).

              ELSE.
                ctx_bind_structure(
                  EXPORTING io_node = lo_nd
                            id_node_name = lv_node_name
                            id_stat_attr = id_stat_attr
                            id_nd_type_name = lv_type_name
                  IMPORTING ed_error_message = ed_error_message ).

              ENDIF.
              FREE lo_nd_info.
            ENDIF.
            FREE lo_nd.
          ELSE.
            ed_error_message = text-001.
          ENDIF.
        ENDIF.
      CATCH cx_root.                                    "#EC CATCH_ALL
        ##no_handler
        ed_error_message = text-004.
    ENDTRY.
  ELSE.
    ed_error_message = text-003."context is not supplied,
    RETURN.
  ENDIF.
ENDMETHOD.

 

Now let us create 2 private methods  as below

 

  • CTX_BIND_TABLE( ) - Bind table to context node - For Internal use only
  • CTX_BIND_STRUCTURE( ) - Bind structure to context node - For Internal use only

 

Method: CTX_BIND_TABLE( )

 

Signature:

bind_table.PNG

Logic:

CTX_BIND_TABLE

METHOD CTX_BIND_TABLE.
  DATA lo_str_descr      TYPE REF TO cl_abap_structdescr.
  DATA lo_tbl_descr      TYPE REF TO cl_abap_tabledescr.
*  DATA lo_stat_data      TYPE REF TO data.
  DATA lv_nd_type_name    TYPE string.
  DATA lv_id_type_name    TYPE string.
  DATA lv_temp_type_name  TYPE string.

  FIELD-SYMBOLS: <lt_stat_attr>    TYPE STANDARD TABLE.

 

  CLEAR: ed_error_message,
        lv_nd_type_name,
        lv_id_type_name,
        lv_temp_type_name.

 

  IF io_node IS BOUND.
    lv_nd_type_name = id_nd_type_name.
    TRANSLATE lv_nd_type_name TO UPPER CASE.
    "get the type name of data provided
    lo_tbl_descr ?=
      cl_abap_tabledescr=>describe_by_data( id_stat_attr ).
    IF lo_tbl_descr IS BOUND.
      "check if the data type provided and
      "node type are same
      lo_str_descr ?= lo_tbl_descr->get_table_line_type( ).
      IF lo_str_descr IS BOUND.
        lv_id_type_name = lo_str_descr->get_relative_name( ).
      ENDIF.


      "check if the type name is used from context node
      IF lv_id_type_name NE lv_nd_type_name.
        CONCATENATE 'ELEMENT' id_node_name
        INTO lv_temp_type_name SEPARATED BY '_'.
        TRANSLATE lv_temp_type_name TO UPPER CASE.

        IF lv_id_type_name EQ lv_temp_type_name.
          lv_id_type_name = lv_nd_type_name.
        ENDIF.
      ENDIF.


      IF lv_id_type_name EQ lv_nd_type_name.
        ASSIGN id_stat_attr TO <lt_stat_attr>.
        IF <lt_stat_attr> IS ASSIGNED.
          io_node->bind_table(
          EXPORTING new_items = <lt_stat_attr> ).
        ENDIF.
      ELSE.
        ed_error_message = 'Data mismatch against context node'.
      ENDIF.
      FREE lo_tbl_descr.
    ENDIF.
  ENDIF.
ENDMETHOD.

 

 

Method: CTX_BIND_STRUCTURE( )

 

Signature:

bind_str.PNG

Logic:

CTX_BIND_STRUCTURE

METHOD CTX_BIND_STRUCTURE.

 

  DATA lo_str_descr      TYPE REF TO cl_abap_structdescr.
*  DATA lo_stat_data      TYPE REF TO data.
  DATA lv_id_stat_attr_type_name    TYPE string.
  DATA lv_temp_type_name  TYPE string.
  DATA lv_nd_type_name    TYPE string.
  FIELD-SYMBOLS: <ls_stat_attr>    TYPE any.

 

  CLEAR: ed_error_message,
        lv_nd_type_name,
        lv_id_stat_attr_type_name,
        lv_temp_type_name.

 

  IF io_node IS BOUND.
    lv_nd_type_name = id_nd_type_name.
    TRANSLATE lv_nd_type_name TO UPPER CASE.
    "get the type name of data provided
    lo_str_descr ?=
    cl_abap_structdescr=>describe_by_data( id_stat_attr ).
    "check if the data type provided and node type are same
    IF lo_str_descr IS BOUND.
      lv_id_stat_attr_type_name = lo_str_descr->get_relative_name( ).
      "check if the type name is used from context node
      IF lv_id_stat_attr_type_name NE lv_nd_type_name.
        CONCATENATE 'ELEMENT' id_node_name
        INTO lv_temp_type_name SEPARATED BY '_'.
        TRANSLATE lv_temp_type_name TO UPPER CASE.
        IF lv_id_stat_attr_type_name EQ lv_temp_type_name.
          lv_id_stat_attr_type_name = lv_nd_type_name.
        ENDIF.
      ENDIF.
      IF lv_id_stat_attr_type_name EQ lv_nd_type_name.
        ASSIGN id_stat_attr TO <ls_stat_attr>.
        IF <ls_stat_attr> IS ASSIGNED.
          io_node->set_static_attributes(
          EXPORTING index = 1
                    static_attributes = <ls_stat_attr> ).
        ENDIF.
      ELSE.
        ed_error_message = 'Data mismatch against context node'.
      ENDIF.
      FREE lo_str_descr.
    ENDIF.
  ENDIF.
ENDMETHOD.


Now, let us see how to bind data to context node by using method SET_CTX_STAT_ATTR( ).

 

Example:

Set data : Let us say we have a context node MY_NODE_T in component controller context with cardinality 0....n /1..n

DATA lt_my_node_t     TYPE wd_this->elements_my_node_t.  DATA lv_error_message TYPE string.    CALL METHOD zcl_wd_helper_class=>set_ctx_stat_attr    EXPORTING      io_context       = wd_context    " WD Context ref      id_node_name     = 'MY_NODE_T'    " Ctx Node Name      id_stat_attr     = lt_my_node_t
*     id_set_dirty     = ABAP_FALSE    IMPORTING      ed_error_message = lv_error_message.

Set data : Let us say we have a context node MY_NODE_S in component controller context with cardinality 0...1 /1..1

 

  DATA ls_my_node_s     TYPE wd_this->elements_my_node_s.  DATA lv_error_message TYPE string.    CALL METHOD zcl_wd_helper_class=>set_ctx_stat_attr    EXPORTING      io_context       = wd_context    " WD Context ref      id_node_name     = 'MY_NODE_s'    " Ctx Node Name      id_stat_attr     = ls_my_node_s
*     id_set_dirty     = ABAP_FALSE    IMPORTING      ed_error_message = lv_error_message.

 

 

Hope this helps for those who are looking for a common logic in place to get and set data from/to context node in WDA applications

 

 

I appreciate your comments/feedback


Custom timeout page for Web Dynpro applications

$
0
0

     Sometimes, users tend to open a lot of WD applications in multiple tabs. After some time (depending on SAP Basis configuration) the session is automatically closed by the application server (Web AS), which will result in a timeout. From a user's perspective this is confusing.


Requirement:

     Create a timeout page for system idles. The standard SAP response is:


     Instead, the system should return a custom (company-specific) page with both F5 (Refresh) functionality and a big "Refresh" button. For example:

timeout.png

     In transaction SICF both short dumps and session timeouts are treated as application errors:

sicf.png

     If you choose to implement an explicit response page, this will be shown for all kinds of application errors. But we don't want that, we only want to see a custom page for timeouts.

     The explicit page can be written in HTML+CSS, but a major issue is that it completely ignores JavaScript. This means, you cannot test the error type and switch between different responses.

  

Solutions:

     After trying multiple alternative, like redirecting to another URL and test the system tag <%=MESSAGE%>, I've found a working solution which is actually quite simple (Occam's razor states: "The simplest answer is usually the right one"):

     1. Create the .html page in any suitable program (Notepad++, or even a BSP application if you want to have the code available inside the system).

BSP.png

     2. You need to copy-paste the code inside an OTR long text using transaction SOTR_EDIT. (This is how the explicit pages are created in SICF)

 

     3. You'll have to create a modification in the core WD class CL_WDR_CLIENT_ABSTRACT_HTTP for method PREPROCESS_REQUEST. (This cannot be enhanced as you need access to instance attributes which is not possible inside pre-/post exits, so you'll need an access key)

wdr.png

     Here, instead of writing the code directly, I chose to call a static method in a customer class. Also, I do this because I don't want to use this timeout page in all applications. I've created a customizing table where I store the WD application name and a flag for 'Active', for all applications that should use this functionality.

 

method handle.

 
data:
    lr_server   
type ref to cl_http_server,
    lt_path      
type string_table,
    ls_appl      
type ytpf_t_appl_list,                       "#EC NEEDED
    ls_page     
type icf_response_page,
    lv_index    
type i,
    lv_service 
type string.

lr_server ?= ir_server
.
 
if lr_server is bound.

     "cl_wdr_task=>application->name can NOT be used here, as the instance is already destroyed...
   
split lr_server->m_runtime_memory_id at `/` into table lt_path[].

   
if not lt_path[] is initial.
     
describe table lt_path[] lines lv_index.
     
read table lt_path[] into lv_service index lv_index. refresh lt_path[].

     
if sy-subrc is initial.
       
translate lv_service to upper case.

 

        select single service_name active
                            
from ytpf_t_appl_list
                            
into corresponding fields of ls_appl
                            
where service_name eq lv_service
                                
and active       eq abap_true.

       
if sy-subrc is initial.
          ls_page
-body = `2C768A4E40741EE3A7A55C5708059340` "SOTR automatically generated GUID

          ir_server->set_page(
           
exporting
              response_page_type   
= ir_server->co_page_error_type
              response_option_page
= ls_page
           
exceptions
              invalid_parameter       
= 1
              document_not_found  
= 2
             
others                           = 3 ).

       
endif.
     
endif.
   
endif.
 
endif.

endmethod.

 

At runtime, if the application error type is a session timeout the explicit page is replaced with the custom page stored in the OTR long text.

This works both in IE and NWBC.

 

I've also started a discussion some time ago: Custom timeout page in SICF

 

Give it a shot and provide some feedback!

 

Tudor

WD ABAP, Search Help and ABAP Structures - A Knot

$
0
0

Background on Search Help, Structures - how its tied together to work in WD

 

Consider having multiple UI elements in a Form or table with couple them tied to automatic F4 helps. When you select a value from F4 the corresponding details / values of other fields are filled in the Form or Table. How is this done? We have our context nodes and attributes which are tied to some structures mostly. This structure in turn have Search Helps tied to them. There is a mapping done at the structure level to the fields from the Search Help. Classic !!! When this is setup properly then BINGO in WD ABAP we do not need to do anything and the values are automatically populated to the fields based on the F4.

 

Couple of Example Scenarios

 

1) Country Code and Description

2) PERNR and UserName Details

3) Order No and Descirption

4) Company Code and Description

.....and the list goes endless

 

Why this BLOG?

 

The F4 help implementation as such is a direct one when DDIC is used and there is no modifications to the standard structure. But often we end up handling with SAP standard components delivered with the business packages. One such requirement came to us to map one of the field and its description to a custom search help instead of the standard one. The Description field was read only and the code is the one that can be selected. Right away oh yeah this falls under a classic examples we saw above but the only difference is its in the standard component. We built a custom search help and then in our WD we made a call in one of our POSTEXIT's to use this custom search help through a sample code below -

 

Data: lo_nd_attrib type ref to if_wd_context_node,      lo_nd_attrib_info type ref to if_wd_context_node_info.
*  Get the Node and Attribute Information
lo_nd_attrib = wd_context->path_get_node( path = `Node PATH` ).
lo_nd_attrib_info = lo_nd_attrib->get_node_info( ).
* Set the custom search help that need to be executed for the context attribute
lo_nd_attrib_info->set_attribute_value_help( name = 'ATTRIBUTE_NAME' value_help_mode = '121' value_help = 'ZCUSTOM_SEARCHHELP' ).

Issue Faced:

 

Only the code was being populated back but the description was not mapped to the corresponding field and it was blank. I raised a question in our forum to get inputs on how this can be achieved. Enhancing F4 Search Help Issue - Standard Component

 

Thanks to Ramakrishnappa Gangappa for helping me in this thread with couple options that we discussed on achieving this solution.

 

Thought Process after hitting Roadblocks

 

From the discussion we had in the thread above I was left with either build an OVS or somehow handle the F4 close event in WDABAP Domodifyview. We are not on SAP 7.31 so there is no listeners like the register_on_enter_for_f4.

Then I came across the document written byChris Paineon Firing a WDA event on using a Search Help - how to do it, without an NDA


and thought ok this is the way I might need to approach the solution so I get the code back and through the listener classes I can handle the context elements...do a select statement to get the description based on the code selected from the F4. Yuppie !!! his blog worked like a charm and I was able to complete the requirement given .


Still Not Convinced

 

Got the solution but was not able to move on as there got to be some way that SAP provides us these values back to the front end instead taking all these approaches. Then, with the help of my colleagues and thanks a lot to them ( Mahesh Square - 2 guys but the combo had the same name ) who are core ABAPers and I wanted to check the Search Help Exit for the callcontrol-step = 'RETURN’


Tagging Magesh Basavaraj and Mahesh YS


And the SOLUTION We FOUND WAS


Basically, the standard search Help when it returns the values back there is an output flag which is set to 'X' and sent back. This was taken as the reference and we implemented the below code in our search help exit to achieve the solution !!!


DATA: shinterface TYPE DDSHIFACE.
FIELD-SYMBOLS: <lf_desc> TYPE DDSHFPROP.
IF callcontrol-step = 'RETURN'.  CLEAR: shinterface.
* A Mapping between the Search help field and the structure field has to be done here for all fields that need to carry data to Webdynpro    shinterface-SHLPFIELD = 'F4 Field'.    shinterface-VALFIELD  = 'ABAP STRUCTURE-FIELD'.    shinterface-F4FIELD   = 'X'.    APPEND shinterface TO shlp-INTERFACE.    LOOP AT SHLP-FIELDPROP ASSIGNING <lf_desc>.
* From the Search Help populate the output flag for fields that need to carry the data to Webdynpro      IF <lf_desc>-FIELDNAME = 'F4 Field_1' OR <lf_desc>-FIELDNAME = 'F4 Fild_2'.        <lf_desc>-SHLPOUTPUT = 'X'.      ENDIF.    ENDLOOP.
ENDIF.

Your Comments and critics are most welcome !!!

Open a new Window in Webdynpro as an action of a Button Click

$
0
0

Make two components of Web Dynpro ABAP, suppose one for flight Booking and the other for Customer details : Take two Webdynpro Components separately, Example: ZZ_CALLING_APPLICATION and ZZ_CALLED_APPLICATION. The navigation PDF is attached.

 

 

STEP 1: CREATE A WEBDYNPRO COMPONENT (SAY: ZZ_CALLING_APPLICATION) THAT WILL TAKE THE “Date on Which Record Was Created” MEANS AEDAT AND A BUTTON NAMED SHOW PURCHASE ORDER, AND A TABLE THAT WILL SHOW THE DETAILS OF PURCHASE ORDER OF THE MENTIONED DATE FROM EKKO TABLE.



img_1.jpg


STEP 2: CREATE AN ANOTHER COMPONENT (SAY: ZZ_CALLED_APPLICATION) WHERE TAKE A TABLE WITH ELEMENTS OF EKPO TABLE.




img_2.jpg


 

STEP 3: GOTO THE CALLING APPLICATION, SELECT THE TABLE AND GOTO THE EVENT “ON LEAD SELECTION” IN PROPERTY AND CREATE AN ACTION, SAY: ON_LEAD_SELECT.


img_3.jpg



PROPERTIES:


  img_4.jpg


STEP 4: DOUBLE CLICK ON THE EVENT NAME I.E. , ON_LEAD_SELECT AND WRITE THE CODE FOR THE ACTION TO OPEN THE SECOND APPLICATION FROM THE FIRST ONE ONCE THE USER SELECTS THE LEFT HAND SIDE OF THE DESIRED ROW.


img_5.jpg



THE PIECE OF CODE IS:


METHOD onactionon_lead_select .
DATA lo_nd_ekko_node TYPE REF TO if_wd_context_node.
DATA lo_el_ekko_node TYPE REF TO if_wd_context_element.
DATA ls_ekko_node TYPE wd_this->element_ekko_node.
DATA lv_ebeln LIKE ls_ekko_node-ebeln.
* navigate from <CONTEXT> to <EKKO_NODE> via lead selection
lo_nd_ekko_node = wd_context->get_child_node( name = wd_this->wdctx_ekko_node ).

* @TODO handle not set lead selection
IF lo_nd_ekko_node IS INITIAL.
ENDIF.

* get element via lead selection
lo_el_ekko_node = lo_nd_ekko_node->get_element(  ).

* @TODO handle not set lead selection
IF lo_el_ekko_node IS INITIAL.
ENDIF.

* alternative access  via index
* lo_el_ekko_node = lo_nd_ekko_node->get_element( index = 1 ).
* @TODO handle non existant child
* IF lo_el_ekko_node IS INITIAL.
* ENDIF.

* get single attribute
lo_el_ekko_node->get_attribute(
EXPORTING
name = 
`EBELN`
IMPORTING
value = lv_ebeln ).

DATA: lv_url
TYPE string.



CALL METHOD cl_wd_utilities=>construct_wd_url
EXPORTING
application_name =
'ZZ_CALLED_APPLICATION'
IMPORTING
out_absolute_url = lv_url.

DATA:lv_ebeln_out
TYPE string.

lv_ebeln_out = lv_ebeln.


*NOW ATTATCH THE VALUE TO THE URL AT THE RUN TIME.

CALL METHOD cl_http_server=>append_field_url
EXPORTING
name  =
'EBELN'
value = lv_ebeln_out
CHANGING
url   = lv_url.

*GENERATE THE WINDOW TO OUTPUT THE URL.

DATA:lv_comp1
TYPE REF TO if_wd_component.

lv_comp1 = wd_comp_controller->WD_GET_API( ).

DATA: lr_window_manager
TYPE REF TO if_wd_window_manager.

CALL METHOD lv_comp1->get_window_manager
RECEIVING
window_manager = lr_window_manager.

DATA: lr_window
TYPE REF TO if_wd_window.

CALL METHOD lr_window_manager->create_external_window
EXPORTING
url    = lv_url
title  = 'PURCHASE ITEM DETAILS'
RECEIVING
window = lr_window.

CALL METHOD
lr_window->open( ).


ENDMETHOD.




STEP 5: GOTO THE SECOND COMPONENT I.E., ZZ_CALLED_APPLICATION AND GOTO METHOD WDDOINIT ( ) , Controller Initialization Method, AND RIGHT THE PIECE OF CODE TO INITIALIZE THE DATA IN THE SECOND COMPONENT.



img_6.jpg



img_7.jpg


THE CODE IS:


method wddoinit .

DATA: LV_VAL
TYPE STRING.

DATA: LWA_EKPO
TYPE EKPO.

DATA: LT_EKPO
TYPE TABLE OF EKPO.

LV_VAL = WDR_TASK=>CLIENT_WINDOW->GET_PARAMETER(
'EBELN' ).




DATA lo_nd_ekpo_node TYPE REF TO if_wd_context_node.
DATA lo_el_ekpo_node TYPE REF TO if_wd_context_element.
DATA ls_ekpo_node TYPE wd_this->element_ekpo_node.
DATA LT_ekpo_node TYPE wd_this->elementS_ekpo_node.
* navigate from <CONTEXT> to <EKPO_NODE> via lead selection
lo_nd_ekpo_node = wd_context->get_child_node( name = wd_this->wdctx_ekpo_node ).


SELECT * FROM
EKPO
INTO TABLE LT_ekpo_node
WHERE EBELN = LV_VAL.

CALL METHOD lo_nd_ekpo_node->bind_table
EXPORTING
new_items            = LT_ekpo_node.



endmethod.




STEP 6 AND OUTPUT: CREATE THE WEB DYNPRO APPLICATION FOR BOTH THE COMPONENTS, AND ACTIVATE THEM AS WELL AS RUN THE FIRST. SELECT ONE DATE, ALL THE PURCHASE ORDER WILL GET OPENED OF THE SELECTED DATE FROM THE TABLE. THEN CLICK ON THE LEFT HAND SIDE OF ROW THAT YOU NEED TO SELECT FOR PURCHASE ITEM DETAILS, AND THE SECOND APPLICATION WILL GET OPENED WITH THE PURCHASE ITEM DETAILS FROM THE EKPO DB TABLE. THE SCREENSHOTS OF THE OUTPUT IS DEFINED BELOW:


img_8.jpg



img_9.jpg



img_10.jpg


CLICK ON THE LEFT HAND SIDE OF THE ROW YOU WANT TO SELECT.



img_11.jpg




img_12.jpg



THANKS & REGARDS,

 

JOYJIT BISWAS

Stateful(ish) Web Dynpro IFrames with Server Side Cookies

$
0
0

The Requirement

I recently had a requirement to embed a web based map within a Web Dynpro application to search for customers and display markers for each result found on the map.  I know there is an existing component for mapping but it's a little bit restrictive in some areas and not in line with our organisations grand plan.  Suffice to say we opted against using it and decided on Leaflet.js.  It's OpenSource and free from any vendor specific lock in (I.e. Nokia, Google, ESRI, etc).

 

The Approach

The only way for us to achieve integration with a Javascript based web map with a Web Dynpro application in NW 7.3 is via a BSP application embedded with an IFrame (but from NW 7.4 it may be possible with HTML5 integration but I've not tried it).

 

IFrames have long been a contentious subject in web development.  Most developers believe them to be evil and quick search in google can point you to a fair few posts around this. Things were so bad SAP banished them from ABAP WD (I don't know the version this happened from) deprecating it's from the language.  However in relatively recent turn of events the IFrame is back and from NW 7.03 and you can use them without fear of persecution (well almost).

 

But what about security?

In terms of security the web map has the same origin and can utilise the same authentication procedures as the Web Dynpro Application it is embedded in.

 

OK. But how can I react to the search event?

Now the SAP Help states that an IFrame should be used with caution, as the WebDynpro and the embedded content are effectively two independent applications.  Take a look at the SAP Help for more info.

 

IFrame -  Web Dynpro ABAP - SAP Library

 

As such you cannot really react to events raised from the Web Dynpro within the embedded IFrame.  You can however re-call the page, which will result in the page being rebuilt.  This may sound terrible, but bare in mind that depending on the type of content being loaded on the page , a lot of the static content should be cached after the first load, so subsequent reloads may not be so costly. 

 

On a side note as of NW 7.4 WebSockets support was introduced to ABAP.  In theory I believe it should be possible to use this to react to events triggered in ABAP within Javascript.  Unfortunately it's something I have not had a chance to try out, but hopefully in the next evolution of this it will happen....


I can't get the page to reload...

Yep. After looking at the APIs and searching the forums I could not find a way to trigger an IFrame refresh within the standard WebDynpro APIs. I'm not sure why this is not possible, but hey, that's just the way it is.  Thankfully there is a simple work around.

 

All you need to do is pass a changing request parameter in the IFrame URI for the BSP Web Map. This forces the framework and thus the browser into thinking the content has changed and results in the page refreshing.  I used a simple counter in the Web Dynpro code I wrote to get the URI for the map, that increments each time the search results were updated.

 

Please note nothing in the code for the BSP web map reacts to this additional parameter and as such it has no effect on the actual application processing.

 

METHOD get_map_uri.

  DATA: l_url         TYPE agr_url2,

        l_counter     TYPE char10,

        lt_url_params TYPE tihttpnvp,

        lo_bsp_runtime TYPEREFTO cl_bsp_runtime.

 

  FIELD-SYMBOLS: <http_param>TYPE ihttpnvp.

 

  APPENDINITIALLINETO lt_url_params ASSIGNING<http_param>.

  <http_param>-name = 'view'.

  <http_param>-value = 'AddressSearch'.

 

  APPENDINITIALLINETO lt_url_params ASSIGNING<http_param>.

  <http_param>-name = 'gui'.

  <http_param>-value = 'webdynpro'.

 

  " Add the optional sessionId param if passed

  IF im_session_id ISNOTINITIAL.

    APPENDINITIALLINETO lt_url_params ASSIGNING<http_param>.

    <http_param>-name = 's'.

    <http_param>-value = im_session_id.

  ENDIF.

 

  " Added a counter to fudge url param and trigger refresh of iframe, which works

  wd_this->g_counter = wd_this->g_counter + 1.

  l_counter = wd_this->g_counter.

  CONDENSE l_counter.

 

  APPENDINITIALLINETO lt_url_params ASSIGNING<http_param>.

  <http_param>-name = 'c'.

  <http_param>-value = l_counter.

 

  " Currently defaulting this to HTTPS but need a better way to identify this

  cl_bsp_runtime=>if_bsp_runtime~construct_bsp_url(EXPORTING    in_protocol = 'HTTP'

                                                                 in_application = 'ZEI_MAP'

                                                                 in_page = 'START.HTM'

                                                                 in_parameters = lt_url_params

                                                       IMPORTING out_abs_url = re_map_uri  ).

 

ENDMETHOD.

 

And then there is the session handling...

So how can I access the search results in my map from the WebDynpro each time the search results change.


At this point I should probably point out that I wrote a set of Restful APIs using BSP to generate GeoJSON that can be consumed by the web based map. For now that is all a little off topic for this blog and a much bigger subject in itself, as we need throw in a mix of Javascript, BSP, XML, JSON, HTTP and Simple Transformations to make it happen...

 

So let's get back on track..I don't want to embed a heap of content into the request body of the map URI called from the Web Dynpro only to then push the same content back to the server in a follow up request to retrieve the actual map data for obvious reasons.  Instead to get the search results map data I used something called server side cookies. 


They have actually been around for ages, but I only recently discovered they existed thanks to the main man of ABAP Thomas Jungwho mentioned it in a forum post.  These little gems can be used to store and retrieve large datasets on the server, independent of the session and persist them up until a specified expiry time has passed or can be explicitly deleted.  They are also super easy to implement. 

 

Server-Side Cookies and Data Persistency (SAP Library - Business Server Pages)

 

Two important fields for a server side cookie are the session ID and user ID and both must be specified when creating and retrieving them.


To get a unique session ID for my current WD application session I make a call to function module TH_GET_SESSION_ID. I subsequently use this session id to set my server side cookie for the authenticated user.  Next I set the URI of the IFrame to the web based map and also pass this session id as request parameter. 


In the web map I have some javascript code to retrieve the session id from the application request URI. I finally make the call to the Restful APIs to GET the map content and again pass this same session id as a request parameter.  Using the session ID and the user ID of the authenticated user (which is the same user as was authenticated by the Web Dynpro) I am able to retrieve the server side cookie containing the search results and use this to create the map data to pass back to the embedded web map.


Note that when setting the time a server side cookie be realistic.  Don't set huge timeouts.  In my scenario, nobody is going to click a button and wait for a response greater than one minute.  So persisting the server side cookies any longer than that makes no sense. 

 

The Conclusion

Things are not so bad with the old IFrames if used responsibly.  You'll be surprised at what you can achieve.

 

Here is a pic of the map I created and embedded within a WebDynpro ABAP FPM based search for addresses.  The map zooms to best dimensions to display all the search results on the map, each time a search is triggered.

 

Map1.PNG

 

It works nicely in Chrome, Firefox, Safari and with a little extra work on the Javascript side also works in IE (SAP dropped an IE7 compatibility mode bombsell setting in the page header, which causes havoc with JS as a lot of functionality was not around then).

HCM Process and Forms:Hiding sensitive employee information in the process overview

$
0
0

SAP standard uses WDA applications ASR_PROCESS_EXECUTE and ASR_PD_PROCESS_EXECUTE for handling HCM Process and Forms applications. These applications can also be configured in SWFVISU to launch P&F work items from UWL.

 

User can access information on people involved in the process from this application using link as shown below. On clicking process's user ID, we see information like Marital Status, Address etc. listed. If there is a requirement to remove this information for all HCM P&F Processes ( without impacting the standard functionality at any other place ), it can be achieved using  WDA component configuration, application configuration and SWFVISU without any coding change.

 

IMG1.jpg.png

 

Technical help shows application and component used.

IMG2.JPG

Create a custom application configuration and mark fields like marital status, birth date etc. as invisible UI elements.

 

Img 4.png

Create a custom application configuration and specify component configuration created in step above for address component used by the application.

Img 3.jpg

 

Once done, the final step required will be to specify corresponding custom application configuration in SWFVISU per details below.

 

 

Tasks

Application and application configuration to use

TS04000018

TS04000019

TS04000020

ASR_PD_PROCESS_EXECUTE/ < Name of application configuration for PD processes >

TS17900100

TS17900101

TS17900102

ASR_PROCESS_EXECUTE/ <name of application configuration for PA processes >

 

IMg 6.png

Viewing all 107 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>