Quantcast
Channel: Web Dynpro ABAP
Viewing all 141 articles
Browse latest View live

Business Graphics Runtime Customization

$
0
0

Business Graphics can be easily customized at design time, but sometimes customizing parameters are not known until runtime. For example, graph title that includes selection criteria. This is where Business Graphics runtime customization come into play.


During runtime further customizing setting can be made in addition to ones made at design time. This is done using IF_WD_BUSIN_GRAPHICS_MTD_HNDL Business Graphics method handler.

 

I created a demo application that compares number of occupied and empty seats across airlines for selected flight date range (SAP Flight data model is used). Flight date selection is displayed in graph title

 

Define flight date range and click on Copy

Defining Selection Criteria.jpg

Voilà

Business Graphics.jpg

Below are step by step instructions of the demo application implementation:

 

1. Create ZCL_BUS_GR_DEMO class that implements data retrieval logic

 

CLASS zcl_bus_gr_rt_cust DEFINITION
 
PUBLIC
 
INHERITING FROM cl_wd_component_assistance
  FINAL
 
CREATE PUBLIC .

*"* public components of class ZCL_BUS_GR_RT_CUST
*"* do not include other source files here!!!
PUBLIC SECTION.

 
TYPES:
   
BEGIN OF s_sflight,
         carrid            
TYPE s_carr_id,
         carrname          
TYPE s_carrname,
         seatsmax          
TYPE s_seatsmax,
         seatsocc          
TYPE s_seatsocc,
         seatsocc_tooltip  
TYPE string,
         seatsempty        
TYPE i,
         seatsempty_tooltip
TYPE string,
      
END OF s_sflight .
 
TYPES:
    t_sflight
TYPE STANDARD TABLE OF s_sflight WITH DEFAULT KEY .
 
TYPES:
    t_fldate
TYPE RANGE OF s_date .
 
TYPES:
   
BEGIN OF s_selection,
      fldate
TYPE t_fldate,
   
END OF s_selection .

 
CLASS-METHODS get_t_sflight
   
IMPORTING
      !it_fldate
TYPE t_fldate OPTIONAL
    RETURNING
     
VALUE(rt_sflight) TYPE t_sflight .
*"* protected components of class ZCL_BUS_GR_DEMO
*"* do not include other source files here!!!
PROTECTED SECTION.
*"* private components of class ZCL_BUS_GR_DEMO
*"* do not include other source files here!!!
PRIVATE SECTION.
ENDCLASS.

CLASS zcl_bus_gr_rt_cust IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_BUS_GR_RT_CUST=>GET_T_SFLIGHT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_FLDATE                      TYPE        T_FLDATE(optional)
* | [<-()] RT_SFLIGHT                     TYPE        T_SFLIGHT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_t_sflight.
DATA: w_percent(3) TYPE p DECIMALS 1.
DATA: w_i(13) TYPE c.
DATA: wa_sflight TYPE s_sflight.

 
SELECT carrid SUM( seatsmax ) AS seatsmax SUM( seatsocc ) AS seatsocc
 
INTO CORRESPONDING FIELDS OF TABLE rt_sflight
 
FROM sflight
 
WHERE fldate IN it_fldate
 
GROUP BY carrid.

 
LOOP AT rt_sflight INTO wa_sflight.
    wa_sflight
-seatsempty = wa_sflight-seatsmax - wa_sflight-seatsocc.
*
   
SELECT SINGLE carrname
   
INTO wa_sflight-carrname
   
FROM scarr
   
WHERE carrid = wa_sflight-carrid.
   
IF sy-subrc <> 0.
     
CLEAR: wa_sflight-carrname.
   
ENDIF.
*
    wa_sflight
-seatsocc_tooltip = w_percent = wa_sflight-seatsocc * 100 / wa_sflight-seatsmax.
   
WRITE: wa_sflight-seatsocc TO w_i.
   
SHIFT w_i LEFT DELETING LEADING SPACE.
   
CONCATENATE wa_sflight-carrname cl_abap_char_utilities=>cr_lf 'Occupied' w_i ' (' wa_sflight-seatsocc_tooltip '%)' INTO wa_sflight-seatsocc_tooltip.
   
REPLACE: 'Occupied' WITH 'Occupied ' INTO wa_sflight-seatsocc_tooltip,
            
'( ' WITH '('               INTO wa_sflight-seatsocc_tooltip,
            
' %)' WITH '%)'             INTO wa_sflight-seatsocc_tooltip.
*
    wa_sflight
-seatsempty_tooltip = w_percent = wa_sflight-seatsempty * 100 / wa_sflight-seatsmax.
   
WRITE: wa_sflight-seatsempty TO w_i.
   
SHIFT w_i LEFT DELETING LEADING SPACE.
   
CONCATENATE wa_sflight-carrname cl_abap_char_utilities=>cr_lf 'Empty' w_i ' (' wa_sflight-seatsempty_tooltip '%)' INTO wa_sflight-seatsempty_tooltip.
   
REPLACE: 'Empty' WITH 'Empty ' INTO wa_sflight-seatsempty_tooltip,
            
'( ' WITH '('         INTO wa_sflight-seatsempty_tooltip,
            
' %)' WITH '%)'       INTO wa_sflight-seatsempty_tooltip.
*
   
MODIFY rt_sflight FROM wa_sflight TRANSPORTING seatsocc_tooltip carrname seatsempty seatsempty_tooltip.
 
ENDLOOP.

ENDMETHOD.
ENDCLASS.

 

 

2.1.     Create ZBUS_GR_RT_CUST component

Create ZBUS_GR_RG_CUST Component 1.jpg

2.2.     Add ZCL_BUS_GR_RT_CUST assistance class and SELECT_OPTIONS usage of WDR_SELECT_OPTIONS component

Create ZBUS_GR_RG_CUST Component 2.jpg

 

3.1.     Add SFLIGHT context node to MAIN view with cardinatlity 0..n

Add SFLIGHT Context Node to MAIN View.jpg

3.2.     Add CARRID, CARRNAME, SEATSMAX, SEATSOCC, SEATSOCC_TOOLTIP, SEATSEMPTY and SEATSEMPTY_TOOLTIP attributes to SFLIGHT node of types S_CARR_ID, S_CARRNAME, S_SEATSMAX, S_SEATSOCC, STRING, S_SEATSFRE and STRING respectively

 

4.1.     Add CUSTOMIZING node to MAIN view context with cardinality 1..1

CUSTOMIZING Node of MAIN View.jpg

4.2.     Add XML attribute of type XSTRING to CUSTOMIZING node

 

 

5.     Define MAIN view layout

 

5.1.     Create 2 trays to arrange screen elements: one for flight date selection and another one for chart.

Set caption texts for the trays to Selection and Business Graphics respectively. Set layout of ROOTUIELEMENTCONTAINER to MatrixLayout. Set Layout Data for both trays to MatrixLayout

 

Trays.jpg

 

5.2.     Add VIEWCONTAINER ViewContainerUIElement under TRAY_SELECT_OPTIONS tray

ViewContainerUIElement.jpg

 

5.3.     Add BusinessGraphics element under Business Graphics tray. Map SeriesSource property, set height and width

BusinessGraphics.jpg

 

 

5.3.1.     Add Category element under BusinessGraphics element. Map Description and Tooltip properties of category element.

Category.jpg

 

5.3.2     Add Series element under BusinessGraphics element. Set Label and map pointSource

Occupied Series.jpg

5.3.3     Update Occupied Point element mapping Label, Tooltip, ValueSource properties

Occupied Point.jpg

5.3.4.     Add Occupied NumericValue element and map its Value property

Occupied NumberValue.jpg

 

5.3.5.     Add Series element under BusinessGraphics element. Set Label and map pointSource

Empty Series.jpg

 

5.3.6.     Update Empty Point element mapping Label, Tooltip, ValueSource properties

Empty Point.jpg

5.3.7.     Add Empty NumericValue element and map its Value property

Empty NumericValue.jpg

5.4.     Customize BusinessGraphics element to set chart type to Stacked_Column and show series labels

Business Graphics Design Time Customization.jpg

Design Time Customization Stacked Column.jpg

Design Time Customization Show Labels.jpg

 

6.     Add SELECT_OPTIONS Componet Use to MAIN view

 

Add SELECT_OPTION Component Use to MAIN View.jpg

 

7.     Add SHOW_SELECTION attribute of type STRING to MAIN view

MAIN View Attributes.jpg

 

8.     Define MAIN view methods

MAIN View Methods.jpg

8.1.     Define SET_SELECTION method that set default flight date selection

SET_SELECTION Method Signature.jpg

METHOD set_selection.
DATA: field TYPE REF TO data.
DATA: interface TYPE REF TO iwci_wdr_select_options.
DATA select_optionsTYPE ref to if_wd_select_options.
FIELD-SYMBOLS: <field> TYPE ANY.

 
interface = wd_this->wd_cpifc_select_options( ).
  select_options
= interface->init_selection_screen( ).
  select_options
->set_global_options( i_display_btn_cancel = abap_false ).
* Delete Fields
  select_options
->remove_selection_screen_item( 'FLDATE' ).
* Create Fields
 
field = select_options->create_range_table( 'S_DATE' ).
 
ASSIGN field->* TO <field>.
  <field>
= is_selection-fldate.
  select_options
->add_selection_field( i_id = 'FLDATE' it_result = field ).

ENDMETHOD.

 

8.2.     Define GET_SELECTION method that reads flight date selection

GET_SELECTION Method Signature.jpg

METHOD get_selection.
DATA: w_fieldnameTYPE fieldname.
DATA: wa_selection_screen_item TYPE if_wd_select_options=>t_selection_screen_item,
      wt_selection_screen_item
TYPE if_wd_select_options=>tt_selection_screen_item.
DATA: interface_select_options TYPE REF TO iwci_wdr_select_options.
DATA: select_optionsTYPE ref to if_wd_select_options.
DATA: node TYPE REF TO if_wd_context_node.
DATA: component TYPE REF TO if_wd_component_usage.
DATA: interface_alvTYPE REF TO iwci_salv_wd_table.
FIELD-SYMBOLS: <f1> TYPE ANY,
               <f2>
TYPE ANY.

  interface_select_options ?= wd_this
->wd_cpifc_select_options( ).
  select_options
= interface_select_options->init_selection_screen( ).

  select_options
->get_selection_screen_items(
   
IMPORTING et_selection_screen_items = wt_selection_screen_item ).
 
LOOP AT wt_selection_screen_item INTO wa_selection_screen_item.
   
CONCATENATE 'RS_SELECTION-' wa_selection_screen_item-m_id INTO w_fieldname.
   
ASSIGN (w_fieldname) TO <f1>.
   
ASSIGN wa_selection_screen_item-mt_range_table->* TO <f2>.
    <f1>
= <f2>.
 
ENDLOOP.

ENDMETHOD.

 

8.3.     Define INITIALIZE_SELECT_OPTIONS method that creates SELECT_OPTIONS component use and set default flight date selection

 

METHOD initialize_select_options.
DATA: ws_fldate TYPE LINE OF wd_assist->t_fldate.
DATA: ws_selection TYPE wd_assist->s_selection.
DATA: component_usage TYPE REF TO if_wd_component_usage,
     
interface TYPE REF TO iwci_wdr_select_options.

  component_usage
wd_this->wd_cpuse_select_options( ).
 
IF component_usage->has_active_component( ) IS INITIAL.
    component_usage
->create_component( ).
 
ENDIF.
*
 
interface = wd_this->wd_cpifc_select_options( ).
*
  ws_fldate
-sign   = 'I'.
  ws_fldate
-option = 'EQ'.
  ws_fldate
-high = sy-datum.
  ws_fldate
-low  = ws_fldate-high - 365.
 
APPEND ws_fldate TO ws_selection-fldate.
  set_selection
( ws_selection ).

ENDMETHOD.

 

 

8.4.     Define EXECUTE event handler method for ON_EXECUTE event of SELECT_OPTIONS component use. Purpose of this method to get data when user execute the program for specified flight date selection

 

METHOD execute.
DATA: ws_selection TYPE wd_assist->s_selection.
DATA: wt_sflight TYPE wd_this->elements_sflight.
DATA: node_sflight TYPE REF TO if_wd_context_node.

  wd_this
->show_selection = abap_true.
  ws_selection
= get_selection( ).
*
  node_sflight
= wd_context->get_child_node( wd_this->wdctx_sflight ).
  wt_sflight
= wd_assist->get_t_sflight( ws_selection-fldate ).
  node_sflight
->bind_table( wt_sflight ).

ENDMETHOD.

 

 

8.5.     Define CUSTOMIZE_BUSINESS_GRAPHICS method. What this code is doing:

  • Gets IF_WD_BUSIN_GRAPHICS_MTD_HNDL Business Graphics method handler
  • Changes Business Graphics customizing XML template adding title caption
  • Assings it CUSTOMIZING.XML context attribute
  • Calls ADD_DIRECT_CUSTOMIZING method passing CUSTOMIZING.XML context attribute

 

CUSTOMIZE_BUSINESS_GRAPTHICE Method Signature.jpg

METHOD customize_business_graphics.
DATA: w_selectionTYPE string.
DATA: w_fldate(10) TYPE c.
DATA: wa_fldateTYPE LINE OF wd_assist->t_fldate.
DATA: ws_selectionTYPE wd_assist->s_selection.
DATA: w_titleTYPE string.
DATA: business_graphicsTYPE REF TO cl_wd_business_graphics.
DATA: busin_graphics_mtd_hndl TYPE REF TO if_wd_busin_graphics_mtd_hndl.
DATA: w_customizing   TYPE string VALUE
       
'<?xml version="1.0" encoding="utf-8" ?>' &
         
'<SAPChartCustomizing version="2.0">' &
           
'<Elements>' &
             
'<ChartElements>' &
               
'<Title>' &
                 
'<Caption></Caption>' &
               
'</Title>' &
             
'</ChartElements>' &
           
'</Elements>'  &
         
'</SAPChartCustomizing>',
      w_customizing_x
TYPE xstring.
DATA: out_convTYPE REF TO cl_abap_conv_out_ce.
DATA: node_customizingTYPE REF TO if_wd_context_node.


* Get Selecton
  node_customizing
= wd_context->get_child_node( wd_this->wdctx_customizing ).
  ws_selection
= get_selection( ).
 
IF wd_this->show_selection= abap_true.
   
IF NOT ws_selection-fldate[] IS INITIAL.
     
READ TABLE ws_selection-fldateINTO wa_fldateINDEX 1.
     
WRITE: wa_fldate-low TO w_fldate.
     
CONCATENATE 'from' w_fldate INTO w_selection SEPARATED BY SPACE.
     
WRITE: wa_fldate-high TO w_fldate.
     
CONCATENATE w_selection 'to' w_fldate INTO w_selection SEPARATED BY SPACE.
   
ENDIF.
    wd_this
->show_selection= abap_false.
 
ENDIF.
* Customize Business Graphics
  business_graphics ?= ir_view
->get_element( 'BUSINESSGRAPHICS' ).
  busin_graphics_mtd_hndl ?= business_graphics
->_method_handler.
  w_title
= 'Occupied vs Empty Seats by Airline'.
 
CONCATENATE w_title cl_abap_char_utilities=>cr_lf w_selection INTO w_title.
 
CONCATENATE '<Caption>' w_title'</Caption>' INTO w_title.
 
REPLACE REGEX '<Caption><\/Caption>' IN w_customizing WITH w_title.
  out_conv
= cl_abap_conv_out_ce=>create( encoding = 'UTF-8' ).
  out_conv
->convert( exporting data   = w_customizing
                    
importing buffer = w_customizing_x).
  node_customizing
->set_attribute( name = 'XML'
                                  
value = w_customizing_x).
  busin_graphics_mtd_hndl
->clear_direct_customizing( ).
  busin_graphics_mtd_hndl
->add_direct_customizing(                                                   

   i_customizing_ctx_path = 'CUSTOMIZING.XML'

 

   i_customizing_ctx_type = if_wd_busin_graphics_mtd_hndl=>mc_add_cust_xml_xstring ).

ENDMETHOD.

 

Hint: to get customizing XML string template just customize Business Graphic element at design time and look at customizing XML for the component

 

Dummy Title.jpg

Design Time Customization.jpg

MIME Repository.jpg

 

 

8.6.     Implement WDDOINIT method calling INITIALIZE_SELECT_OPTIONS method

METHOD wddoinit .

  initialize_select_options
( ).

ENDMETHOD.

 

 

8.7.     Implement WDDOMODIFVIEW method calling CUSTOMIZE_BUSINESS_GRAPHICS method

METHOD wddomodifyview.

  customize_business_graphics
( view ).

ENDMETHOD.

 


9.     Embed WND_SELECTION_SCREEN view of SELECT_OPTIONS component use into VIEWCONTAINER element of MAIN view

Embed WND_SELECTION_SCREEN of SELECTION_OPTION Usage  into VIEWCONTAINER element ot MAIN view.jpg

 

10.     Create ZBUS_GR_RT_CUST application

ZBUS_GR_RT_CUST Application.jpg


Text following image in table

$
0
0

Text following image in table


Hi,


In my project, I have facing a problem to add a text following an image in the table within a single column.


Solution:

  • Make a table column UI element as Link to Action.
  • It will provide the option to add the image following to the text.

  Example: Image_text_blog.JPG  

Select All option in SAP ABAP Webdynpro Table

$
0
0

Select All option in SAP ABAP Webdynpro Table


Hi All,

 

Usually SAP not provided default Select all option in Webdynpro Table like below.

 

Select All        Select None

select_all1.jpgselect_all2.jpg

 

We can achive that through below following steps:


  • Create Table UI element in ABAP Webdynpro.
  • Bind the source data for the Table UI.
  • Table’s  first column should be select option.
  • So first cloumn UI element should be checkbox and define action method for that checkbox also.
  • The caption of that first cloumn should be bind with UNCHECK checkbox image (SAP not provide any UNCHECK checkbox image, so bind custom image).
  • Whenever user clicks that UNCHECK check box write proper code for CHECK all the records & change the caption image as CHECKED checkbox through action method.
  • Using this illustion effect we can achive the CHECK (Select All) or UNCHECK (Select None) funtionality in Webdynpro Table UI element.

Easy maintenance of message texts for customer

$
0
0

Easy maintenance of message texts for customer


HI All,


In my project we are maintaining message texts in custom table & global constants in class attributes.

It helps the customer to change their particular application message texts without touching the code.

And it is reusable also.

SAP Users Role change

$
0
0

SAP Users Role change


Basically SAP users have one or more roles.

 

In SAP User Management we can’t just add, delete or edit the roles which are assigned to the particular user.

 

We are assigning the roles to the user while creating the new user using BAPI ‘BAPI_USER_LOCACTGROUPS_ASSIGN’ . 

 

SAP doesn’t have any BAPI or RFC for changing the user’s roles separately.

 

Solution:

  • If you want to add the additional roles to the user, then first read the users previous assigned roles from the system & add this additional new roles to the previous roles list and call the BAPI ‘BAPI_USER_LOCACTGROUPS_ASSIGN’ and pass the previous roles list which is having new roles also.
  • Same way if you want to delete some roles of the user, then remove the particular roles from the user’s previous roles list and call the BAPI ‘BAPI_USER_LOCACTGROUPS_ASSIGN’ and pass new roles list.

Creative Use of IFrame UI Element

$
0
0

Web Dynpro ABAP provides an extensive set of UI Elements. In most cases standard UI Elements suit developer needs. If not, there is an option to create your own UI element, for example, with the help of HTML5 islands or Adobe Flash Islands. If you do not have Flex Builder knowledge or your system is not on right release level (7.31 SP5 for HLTML5 island) then IFrame UI Element is the only choice.

 

Lets say you have a requirement to display notes that users add to a document in form of a chat. Standard UI Elements like Table, FormattedTextView or TextView can not satisfy the requirement. It is easy to model Chat UI Element with the help of IFrame UI Element, InputField UI Element and some basic knowlege of HTML, CSS, JavaScript, XML and XSLT.

 

What it takes is:

1) Transform notes internal table into XML using Simple Transformation;

2) Tranform XML into HTML using XSLT transformation;

3) Save HTML document in repository;

4) Map HTML document URL into Source property of IFrame UI Element.

 

Here is how modeled Chat UI Element looks:

Modeled Chat UI Element.jpg

It is easy to using Modeled Chat UI Element - just key in text and press enter:

It is easy to using Modeled Chat UI Element - just key in text and press enter.jpg

 

Below are step by step instructions how to implement the demo application:

1) In trx. XSLT_TOOL create ZIFRAME_DEMO_ST Simple Transformation that transforms note internal table data into XML

Create ZIFRAME_DEMO_ST Simple Tranformation 1 of 2.jpg

In Source Cde tab add following code:

 

<?sap.transform simple?>
<tt:transform xmlns:tt=
"http://www.sap.com/transformation-templates">

<tt:root name=
"NOTE"/>

<tt:template>
<ZIFRAME_DEMO>
  <tt:loop ref=
".NOTE" name="line">
    <NOTE>
      <CREATED_BY>
          <tt:value ref=
"$line.CREATED_BY" />
      </CREATED_BY>
      <CREATED_ON>
          <tt:value ref=
"$line.CREATED_ON" />
      </CREATED_ON>
      <CREATED_AT>
          <tt:value ref=
"$line.CREATED_AT" />
      </CREATED_AT>
      <NOTE>
          <tt:value ref=
"$line.NOTE" />
      </NOTE>
    </NOTE>
  </tt:loop>
</ZIFRAME_DEMO>
</tt:template>

</tt:transform>

 

2) In trx. XSLT_TOOL create ZIFRAME_DEMO_XSLT XSLT Transformation that transforms XML to HTML

Create ZIFRAME_DEMO_XSLT XSLT Transformation.jpg

In Source Cde tab add following code:

 

<xsl:transform version="1.0"
  xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform"
  xmlns:sap=
"http://www.sap.com/sapxsl"
>

<xsl:strip-space elements=
"*"/>


<xsl:template match=
"/">
  <html>
<head>
<script>
window.onload=toBottom;
function toBottom()
{
setTimeout(function(){window.scrollTo(0, document.body.scrollHeight);},250);
}
</script>
</head>

  <style>
    html {height: 100%; width:100%; padding:0px; margin:0px;}
    body {background-color:#e7eff7; height:100%; width:100%; padding:0px; margin: 0px;border-style:solid;border-width:1px;border-color:#A5ADB5;}
    table.props1 td { font-family:Arial,Helvetica,sans-serif; font-size: 0.7em; }
    table.props { background:#999999; }
    table.props td { background:#FFFFFF; padding:1 1; vertical-align:top; font:normal
10 verdana; padding-left=4px; padding-right=4px; }
    table.props th { background:#EEEEEE; padding:1 1; vertical-align:top; font:normal
10 verdana; padding-left=4px; padding-right=4px; }
  </style>

  <body >
  <table class=
"props1" width="100%">
    <xsl:for-each select=
"ZIFRAME_DEMO/NOTE">
      <tr>
      <td title=
"{CREATED_BY}" width="120p" style="color:#296394;vertical-align:top;"><xsl:value-of select="CREATED_BY"/>
      <br/><xsl:value-of select=
"CREATED_ON"/><xsl:text> </xsl:text><xsl:value-of select="CREATED_AT"/></td>
      <td valign=
"top"><xsl:value-of select="NOTE"/></td>
    </tr>
  </xsl:for-each>
  </table>
  </body>
  </html>
</xsl:template>

</xsl:transform>

 

Note: XSLT transformation formats output using HTML and CSS and also scrolls to last note using JavaScript

 

3) Create ZIFRAME_DEMO Component

ZIFRAME_DEMO Component.jpg

 

4) Add NOTE context node to MAIN view.

NOTE Context Node of MAIN View.jpg

Set cardinality of NOTE node to 0..n, then CREATED_BY, CREATED_ON, CREATED_AT and NOTE attributes of types NAME1, DATS, TIMS and STRING respectively

 

5) Add NOTE_URL attribute to MAIN view context. Set type to STRING.

NOTE_URL Context Attribute of MAIN View.jpg

 

6) Add NOTE_NEW attribute to MAIN view context. Set type to STRING

NOTE_NEW Context Attribute of MAIN View.jpg

 

7) On MAIN view set ROOTUIELEMENTCONTAINER UI Element layout to MatrixLayout

ROOTUIELEMENTCONTAINER UI Element of MAIN View.jpg

 

8) Add IFRAME UI element to MAIN view layout. Set Layout Data to MatrixHeadData, set width to 400px and map Source to MAIN.NOTE_URL

IFRAME UI Element of MAIN View.jpg

 

9) Add INPUTFIELD UI element. Layout Data to MatrixHeadData, set width to 400px, map Value to MAIN.NOTE_NEW, create ENTER action and assign it to onEnter event (it will be implemented later).

INPUTFIELD UI Element on MAIN View.jpg

 

10) Create GET_HTML method of MAIN view. This method Note data into XML and then into HTML.

GET_HTML Method of MAIN View.jpg

METHOD get_html.
DATA: w_xmlTYPE string.

* Transform Note data into XML
 
CALL TRANSFORMATIONziframe_demo_st
   
SOURCE note = it_note
   
RESULTXMLw_xml.
* Transform XML into HTML
 
CALL TRANSFORMATIONziframe_demo_xslt
   
SOURCEXMLw_xml
   
RESULTXMLrv_html.

ENDMETHOD.

 

11) Create GET_URL method in MAIN view. This method creates HTML document in respository and returns its URL.

GET_URL Method on MAIN View.jpg

METHOD get_url.
DATA: cached_responseTYPE REF TO if_http_response.
DATA: w_guidTYPE guid_32.
DATA: w_urlTYPE string.

* Creat response object
 
CREATE OBJECTcached_response
   
TYPE
      cl_http_response
   
EXPORTING add_c_msg        = 1.
 
TRY. " ignore, if compression can not be switched on
   
CALL METHOD cached_response->set_compression
     
EXPORTING  options = cached_response->co_compress_based_on_mime_type
       
EXCEPTIONS
         
OTHERS  = 1.
   
CATCH cx_root.
 
ENDTRY.
* Set response object header and data
  cached_response
->set_cdata( iv_html).
  cached_response
->set_header_field( name  = if_http_header_fields=>content_type
                                   
value = 'text/html' ).
  cached_response
->set_status( code = 200 reason = 'OK' ).
  cached_response
->server_cache_expire_rel( expires_rel = 3600 ).
* Generate URL
 
CALL FUNCTION 'GUID_CREATE'
     
IMPORTING
            ev_guid_32
= w_guid.
 
CONCATENATE '/sap/public/' w_guid'.' 'html' INTO rv_url.
* Cache the URL
  cl_http_server
=>server_cache_upload( url      = rv_url
                                      response
= cached_response ).

ENDMETHOD.

 

12) Implement WDDOINIT method of MAIN view. This method initializes IFRAME with notes

 

METHOD wddoinit.
DATA: w_html TYPE string,
      w_url 
TYPE string.
DATA: wa_note TYPE wd_this->element_note,
      wt_note
TYPE wd_this->elements_note.
DATA: node_note TYPE REF TO if_wd_context_node.
DATA: w_note_1 TYPE string,
      w_note_2
TYPE string,
      w_note_3
TYPE string,
      w_note_4
TYPE string,
      w_note_5
TYPE string,
      w_note_6
TYPE string.

 
CONCATENATE: 'Web Dynpro ABAP provides an extensive set of UI Elements.'
             
'In most cases standard UI Elements suit developer needs.'
             
'If not, there are options to create your own UI element,'
             
'for example, with the help of HTML5 islands or Adobe Flash Islands.'
             
'If you do not have Flex Builder knowledge or your system is not on right release level'
             
'(7.31 SP5 for HLTML5 island) then IFrame UI Element is your only option.' INTO w_note_1 SEPARATED BY SPACE,
             
'Lets say you have a requirement to display notes that users add to a document in form of a chat.'
             
'Standard UI Elements like Table, FormattedTextView or TextView can satisfy the requirement.'
             
'It is easy to model Chat UI Element with the help of IFrame UI Element and some basic knowlege of HTML, CSS, JavaScript, XML and XSLT.'
             
'What it takes:' INTO w_note_2 SEPARATED BY SPACE.
  w_note_3
'1) Serialize notes internal into XML form using Simple Transformation;'.
  w_note_4
'2) Tranform XML into HTML using XSLT transformation;'.
  w_note_5
'3) Save HTML document in repository;'.
  w_note_6
'4) Map HTML document URL into Source property of IFrame UI Element'.

* Set initial notes
  wa_note
-created_by = 'Uladzislau Pralat'.
  wa_note
-created_on = '20140924'.
  wa_note
-created_at = 135903.
  wa_note
-note      = w_note_1.
 
APPEND wa_note TO wt_note.
  wa_note
-note      = w_note_2.
 
APPEND wa_note TO wt_note.
  wa_note
-note      = w_note_3.
 
APPEND wa_note TO wt_note.
  wa_note
-note      = w_note_4.
 
APPEND wa_note TO wt_note.
  wa_note
-note      = w_note_5.
 
APPEND wa_note TO wt_note.
  wa_note
-note      = w_note_6.
 
APPEND wa_note TO wt_note.

  node_note
= wd_context->get_child_node( wd_this->wdctx_note ).
  node_note
->bind_table( wt_note ).
* Generate HTML
  w_html
= get_html( wt_note ).
* Generate URL
  w_url
= get_url( w_html ).
* Bind URL to IFrame
  wd_context
->set_attribute( name 'NOTE_URL'
                           
value = w_url ).

ENDMETHOD.

 

13) Implement ONACTIONENTER method of MAIN view to reach on ENTER action. This method adds new note to IFRAME and clears INPUTFIELD.

METHOD onactionenter.
DATA: w_htmlTYPE string,
      w_url 
TYPE string.
DATA: w_note_newTYPE wd_this->element_context-note_new.
DATA: ws_noteTYPE wd_this->element_note,
      wt_note
TYPE wd_this->elements_note.
DATA: node_noteTYPE REF TO if_wd_context_node.
DATA: element_noteTYPE REF TO if_wd_context_element.

* Get new note
  wd_context
->get_attribute( EXPORTING name  = 'NOTE_NEW'
                           
IMPORTING value= w_note_new).
* Add new note to context
  node_note
= wd_context->get_child_node( wd_this->wdctx_note).
  element_note
= node_note->create_element( ).
  ws_note-created_by
= 'Uladzislau Pralat'.
  ws_note-created_on
= sy-datum.
  ws_note-created_at
= sy-uzeit.
  ws_note
-note      = w_note_new.
  element_note
->set_static_attributes( ws_note).
  node_note
->bind_element( new_item            = element_note
                          set_initial_elements
= abap_false).
* Get all notes from context
  node_note
->get_static_attributes_table( IMPORTING table= wt_note ).
* Generate HTML
  w_html
= get_html( wt_note).
* Generate URL
  w_url
= get_url( w_html).
* Bind URL to IFrame
  wd_context
->set_attribute( name 'NOTE_URL'
                            value
= w_url).
* Clear new note
  wd_context
->set_attribute( name  = 'NOTE_NEW'
                            value
= SPACE ).

ENDMETHOD.

14) Create ZIFRAME_DEMO Application

Create ZIFRAME_DEMO Application.jpg

FPM TABBED GUIBB FOR BEGINNERS

$
0
0

hi every one in this blog i am going to show you how tabbed guibb works.

 

SCENARIO :  here tabbed guibb contains four tabs,each tab embeds one interface view of the component.however on the first tab contains the check boxes.

each check box is related to the visibility of the remaining tabs i.e if we click on the first check box TAB2 is visible or if we click on the second check box TAB3 is visible.

 

PLEASE SEE THE BELOW SCREEN SHOTS:


I USED FPM_OIF_COMPONENT.


WHEN THE COMPONENT LOADED.


18.1.jpg

 

NOW I ENABLE FIRST CHECK BOX

 

18.2.jpg

 

NOW I ENABLES ALL CHECK BOXES ONE BY ONE

 

18.3.jpg

 

NOW I DISABLE FOURTH CHECK BOX.

 

 

 

18.4.jpg

 

SO THIS IS MY REQUIREMENT LET US START.

 

WEBDYNPRO COMPONENT:  Z_DEMO_OBJECT1


IMPLEMENTED INTERFACES: 


1)IF_FPM_UI_BUILDING_BLOCK: when we add this interface automatically FPM methods (  FLUSH  - to send the data to  Central Data Model,NEEDS_FOR_CONFIRMATION  - to provide the data loss popup if data not saved ,PROCESS_EVENT - to process the fpm events,PROCESS_BEFORE_OUTPUT - to read the data to be displayed ,AFTER_FAILED_EVENT - to handle the failed events  ) are loaded in to the

COMPONENT CONTROLLER.



2) IF_FPM_TABBED_CONF_EXIT :  when we add this interface only OVERRIDE_CONFIG_TABBED method is added which is triggered after every fpm event raised.

 

                                                           


1.jpg

 

 

1.1.jpg

 

COMPONENT CONTROLLER :

 

2.jpg

 

3.jpg

 

4.jpg

 

 

CODE IN ACTIVE_FIRST_TAB:


types:
BEGIN OF ty_s_tab,
variant
TYPE string,
id TYPE string,
name
TYPE string,
END OF ty_s_tab .
types:
ty_t_tab
TYPE STANDARD TABLE OF ty_s_tab .

DATA:LV_VARIANT_ID TYPE STRING,
LT_TAB
TYPE TY_T_TAB,
LS_TAB
LIKE LINE OF LT_TAB.

CALL METHOD WD_THIS->GO_TABBED->GET_CURRENT_VARIANT
RECEIVING
RV_VARIANT_ID
= LV_VARIANT_ID.

TRY.
CALL METHOD WD_THIS->GO_TABBED->GET_TABS
EXPORTING
IV_VARIANT_ID
= LV_VARIANT_ID
IMPORTING
ET_TAB       
= LT_TAB.
CATCH CX_FPM_FLOORPLAN .
ENDTRY.

LOOP AT LT_TAB INTO LS_TAB.
IF SY-TABIX GT 1.
CALL METHOD WD_THIS->GO_TABBED->SET_TAB_VISIBLE
EXPORTING
IV_TAB_ID 
= LS_TAB-ID
IV_VISIBLE
= ' '.
CLEAR LS_TAB.
ENDIF.
ENDLOOP.

 

CODE ININITIALIZE_BOX:

 

  DATA lo_nd_check TYPE REF TO if_wd_context_node.
DATA lo_el_check type ref to if_wd_context_element.
DATA lt_check TYPE wd_this->Elements_check.
DATA ls_check TYPE wd_this->Element_check.
*  navigate from <CONTEXT> to <CHECK> via lead selection
lo_nd_check
= wd_context->get_child_node( name = wd_this->wdctx_check ).


*  @TODO handle non existant child
IF NOT lo_nd_check IS INITIAL.

do 3 times.
lo_el_check
= lo_nd_check->create_element( ).
lo_nd_check
->bind_element( new_item = lo_el_check set_initial_elements = abap_false ).

enddo.

ENDIF.

 

CODE IN OVERRIDE_CONFIG_TABBED


  DATA lv_VISIBLE TYPE BOOLE_D.
DATA lv_id TYPE string.
DATA lv_name  TYPE string.
CASE io_tabbed->mo_event->mv_event_id.
WHEN 'FPM_START'.
WD_THIS
->GO_TABBED = IO_TABBED.
wd_this
->active_first_tab(
*    lo_tabbed =                        " ref to if_fpm_tabbed
).

WHEN 'ADD_TAB'.
io_tabbed
->mo_event->MO_EVENT_DATA->get_value( EXPORTING iv_key = 'ID' IMPORTING ev_value = lv_id ).
io_tabbed
->mo_event->MO_EVENT_DATA->get_value( EXPORTING iv_key = 'NAME' IMPORTING ev_value = lv_name ).

CALL METHOD IO_TABBED->SET_TAB_VISIBLE
EXPORTING
IV_TAB_ID 
= LV_ID
IV_VISIBLE
= 'X'.
WHEN 'DELETE_TAB'.
io_tabbed
->mo_event->MO_EVENT_DATA->get_value( EXPORTING iv_key = 'ID' IMPORTING ev_value = lv_id ).
io_tabbed
->mo_event->MO_EVENT_DATA->get_value( EXPORTING iv_key = 'NAME' IMPORTING ev_value = lv_name ).

CALL METHOD IO_TABBED->SET_TAB_VISIBLE
EXPORTING
IV_TAB_ID 
= LV_ID
IV_VISIBLE
= ' '.



endcase.

 

CODE IN WDDOINIT :


wd_this->initialize_box().

 

 

VIEW CONTROLLER:


1.1.jpg

 

 

5.1.jpg

 

 

5.2.jpg

 

 

 

5.4.jpg

 

6.jpg

 

7.jpg

 

CODE IN ONACTIONON_CHECK_BOX :

 

types:
BEGIN OF ty_s_tab,
variant
TYPE string,
id TYPE string,
name
TYPE string,
END OF ty_s_tab .
types:
ty_t_tab
TYPE STANDARD TABLE OF ty_s_tab .

DATA:LV_VARIANT_ID TYPE STRING,
LT_TAB
TYPE TY_T_TAB,
LS_TAB
LIKE LINE OF LT_TAB,
LV_INDEX
TYPE I.

CASE ID.
WHEN 'TABLE_CHECK_BOX_EDITOR'.
DATA: lo_fpm TYPE REF TO if_fpm,
lo_event
TYPE REF TO cl_fpm_event.


CALL METHOD CONTEXT_ELEMENT->GET_INDEX
RECEIVING
MY_INDEX
= LV_INDEX.

DATA lo_nd_check TYPE REF TO if_wd_context_node.

DATA lo_el_check TYPE REF TO if_wd_context_element.
DATA ls_check TYPE wd_this->Element_check.
DATA lv_check_box TYPE wd_this->Element_check-check_box.

* navigate from <CONTEXT> to <CHECK> via lead selection
lo_nd_check
= wd_context->get_child_node( name = wd_this->wdctx_check ).

* @TODO handle non existant child
* IF lo_nd_check IS INITIAL.
* ENDIF.

* get element via lead selection
lo_el_check
= lo_nd_check->get_element( index = LV_INDEX ).
* alternative access  via index
* lo_el_check = lo_nd_check->get_element( index = 1 ).
* @TODO handle not set lead selection
IF lo_el_check IS INITIAL.
ENDIF.

* get single attribute
lo_el_check
->get_attribute(
EXPORTING
name
`CHECK_BOX`
IMPORTING
value = lv_check_box ).



CALL METHOD WD_COMP_CONTROLLER->GO_TABBED->GET_CURRENT_VARIANT
RECEIVING
RV_VARIANT_ID
= LV_VARIANT_ID.

TRY.
CALL METHOD WD_COMP_CONTROLLER->GO_TABBED->GET_TABS
EXPORTING
IV_VARIANT_ID
= LV_VARIANT_ID
IMPORTING
ET_TAB       
= LT_TAB.
CATCH CX_FPM_FLOORPLAN .
ENDTRY.

READ TABLE LT_TAB INTO LS_TAB INDEX LV_INDEX + 1.
IF lv_check_box = 'X'.
lo_fpm
= cl_fpm=>get_instance( ).
lo_event
= cl_fpm_event=>create_by_id( 'ADD_TAB' ).
lo_event
->MO_EVENT_DATA->set_value( iv_key  = 'ID' IV_VALUE = LS_TAB-ID ).
lo_event
->MO_EVENT_DATA->set_value( iv_key  = 'NAME' iv_value = LS_TAB-NAME ).
lo_fpm
->raise_event( io_event = lo_event ).
ELSEIF lv_check_box = ' '.
lo_fpm
= cl_fpm=>get_instance( ).
lo_event
= cl_fpm_event=>create_by_id( 'DELETE_TAB' ).
lo_event
->MO_EVENT_DATA->set_value( iv_key  = 'ID' IV_VALUE = LS_TAB-ID ).
lo_event
->MO_EVENT_DATA->set_value( iv_key  = 'NAME' iv_value = LS_TAB-NAME ).
lo_fpm
->raise_event( io_event = lo_event ).
ENDIF.
ENDCASE.


8.jpg



9.jpg

 

 

10.jpg

 

11.jpg

 

VIEWS  TAB2_VIEW  -------> TAB2

              TAB3_VIEW --------->TAB3

              TAB4_VIEW --------->TAB4

 

FOR APPLICATION CONFIGURATION .

15.jpg


16.jpg17.1.jpg17.2.jpg17.3.jpg



CHANGING PARTICULAR ROW EDITABLE ON LEAD SELECT IN LIST GUIBB

$
0
0

for the question raised from discussion

Re: Edit single row in list UIBB

 

Hi everyone someone raised question how to change the particular row content to editable on lead select so i worked on this and finally Mr.Jitin gave me an idea how can we achive this, i thought it may be helpful to everyone later so i created scenario for this.

 

SCENARIO:

 

9.1.jpg


WHEN I LOAD THE APPLICATION LIST GUIBB WILL DISPLAY THE DETAILS OF MATNR.WHEN WE CLICK ON CHECKBOX  FPM_GUIBB_LIST_ON_LEAD_SELECTI EVENT WILL BE TRIGGERED THEN THE PARTICULAR ROW WILL BE EDITABLE.

 

9.2.jpg

 

AFTER CHANGING THE VALUES WHEN YOU CLICK ON ENTER THEN FPM_GUIBB_LIST_CELL_ACTION IS TRIGGERED AND IT DISPLAYS THE SAVED DATA.( YOU CAN ADD CHECK CHANGE LOG INFORMATION THEN PROCEED WITH THIS ACTION IF CHANGES DONE OTHER WISE SIMPLY EXIT BUT IN THIS SCENARIO I DID NOT WRITTEN THAT CODE ).

9.3.jpg

 

NOW LET US START SCENARIO :

STEP1 : CREATE FEEDER CLASS

1.jpg

 

2.jpg

 

NOW GOTO INTERFACE TAB THEN ADD

IF_FPM_GUIBB_LIST(  IF_FPM_GUIBB AUTOMATICALLY ADDED ).

 

3.jpg

 

4.jpg

 

CODE IN METHODIF_FPM_GUIBB_LIST~GET_DEFINITION:

data:
lt_field_description
type fpmgb_t_listfield_descr,
ls_field_description
type fpmgb_s_listfield_descr,
ls_action_definition
type fpmgb_s_actiondef,
lt_comp
type abap_component_tab,
ls_comp
type abap_componentdescr.

eo_field_catalog ?= cl_abap_tabledescr
=>DESCRIBE_BY_DATA( lt_mara ).

ls_field_description
-name = 'MATNR'.
ls_field_description
-text = 'MATERIAL NUMBER'.
ls_field_description
-read_only_ref = 'MATNR_RO_REF'.
ls_field_description
-visibility = cl_wd_uielement=>e_visible-visible.
APPEND ls_field_description to lt_field_description.
ls_field_description
-name = 'MATNR_RO_REF'.
ls_field_description
-text = 'MATERIAL KEY'.
ls_field_description
-visibility = cl_wd_uielement=>e_visible-visible.
APPEND ls_field_description to lt_field_description.
ls_field_description
-name = 'MAKTX'.
ls_field_description
-text = 'MATERIAL DESCRIPTION'.
ls_field_description
-read_only_ref = 'MAKTX_RO_REF'.
ls_field_description
-visibility = cl_wd_uielement=>e_visible-visible.
APPEND ls_field_description to lt_field_description.
ls_field_description
-name = 'MAKTX_RO_REF'.
ls_field_description
-text = 'DESCRIPTION KEY'.
ls_field_description
-visibility = cl_wd_uielement=>e_visible-visible.
APPEND ls_field_description to lt_field_description.

et_field_description
= lt_field_description.

ls_action_definition-id = IF_FPM_GUIBB_LIST=>GC_FPM_EVENT_ON_LEAD_SEL.
ls_action_definition
-text = 'ON LEAD SELECT'.
ls_action_definition
-visible = cl_wd_uielement=>e_visible-visible.
APPEND ls_action_definition to et_action_definition.


CODE IN METHOD IF_FPM_GUIBB_LIST~GET_DATA :

   data:ls_fieldusage type fpmgb_s_fieldusage,
lt_fieldusage
type fpmgb_t_fieldusage,
lo_fpm
type REF TO if_fpm.

IF IV_EVENTID->MV_EVENT_ID = 'FPM_START'.
data:ls_mara like LINE OF lt_mara.

SELECT MATNR MAKTX FROM MAKT INTO CORRESPONDING FIELDS OF TABLE LT_MARA WHERE SPRAS = 'EN'.
loop at lt_mara into ls_mara.
ls_mara
-matnr_ro_ref = 'X'.
ls_mara
-maktx_ro_ref = 'X'.
MODIFY lt_mara from ls_mara.
clear:ls_mara.
endloop.
CT_DATA
= LT_MARA.
EV_DATA_CHANGED
= abap_true.
ELSEIF IV_EVENTID->MV_EVENT_ID = IF_FPM_GUIBB_LIST=>GC_FPM_EVENT_ON_LEAD_SEL.
REFRESH LT_MARA.
LT_MARA
= CT_DATA.
READ TABLE LT_MARA INTO LS_MARA INDEX CV_LEAD_INDEX.
LS_MARA
-MATNR_RO_REF = ' '.
LS_MARA
-MAKTX_RO_REF = ' '.
MODIFY LT_MARA FROM LS_MARA INDEX CV_LEAD_INDEX.

CT_DATA
LT_MARA.
EV_DATA_CHANGED
= abap_true.
ELSEIF IV_EVENTID->MV_EVENT_ID = IF_FPM_GUIBB_LIST=>GC_GUIBB_LIST_ON_CELL_ACTION.
DATA:WA_MARA TYPE MAKT.
REFRESH LT_MARA.
LT_MARA
= CT_DATA.
READ TABLE LT_MARA INTO LS_MARA INDEX CV_LEAD_INDEX.
SELECT SINGLE * FROM MAKT INTO WA_MARA WHERE MATNR = LS_MARA-MATNR AND SPRAS = SY-LANGU.
IF SY-SUBRC = 0.
WA_MARA
-MAKTX = LS_MARA-MAKTX.
UPDATE MAKT SET MAKTX = WA_MARA-MAKTX WHERE MATNR = LS_MARA-MATNR AND SPRAS = SY-LANGU.
ELSE.
WA_MARA
-MANDT = SY-MANDT.
WA_MARA
-MATNR = LS_MARA-MATNR.
WA_MARA
-SPRAS = SY-LANGU.
WA_MARA
-MAKTX = LS_MARA-MAKTX.
WA_MARA
-MAKTG = LS_MARA-MAKTX.
INSERT MAKT FROM WA_MARA.
ENDIF.
lo_fpm
= cl_fpm_factory=>get_instance( ).
lo_fpm
->RAISE_EVENT_BY_ID( iv_event_id = 'FPM_START').
ENDIF.


STEP2: CREATE EMPTY WEBDYNPRO COMPONENT


5.jpg


NOW CREATE APPLICATION

   COMPONENT : FPM_OIF_COMPONENT.

   WINDOW       : FPM_WINDOW

   PLUG:   DEFAULT

5.1.jpg

STEP3: CONFIGURATION

  NOTE: WHILE DOING THE CONFIGURATION PARAMETER_LIST,INITIALIZATION,GET_DEFINITION WILL EXICUTE

             SO IF ANY CODE IN THOSE METHODS APPLICATION GOES TO DUMP.

6.jpg

 

7.jpg

NOW ENTER THE FEEDER CLASS NAME IF PARAMETERS ARE NOT DEFINED THEN IT WILL SHOW SOME SUSSES MESSAGE

7.1.jpg

ENTER THE FOLLOWING VALUES AS MENTIONED IN THE RECTANGULAR BOX ,NEXT MAINTAIN THE DISPLAY TYPE AS INPUTFIELD AS SHOWN BELOW,AND ONLY ADD MATNR,MAKTX FIELDS.CLICK ON THE LEAD SELECTION ACTION ASSIGNMENT  AS SHOWN BELOW THEN SELECT THE STANDARD LEAD SELECTION THEN EVENT FPM_GUIBB_LIST_ON_LEAD_SELECTI WILL BE TRIGGERED AUTOMATICALLY.


8.jpg



Semi-Dynamic Mass-Activation for Access Keys in WDA-Components

$
0
0

Hello folks!

 

About a year ago was the first time I had to deal with the topic Accessibility in great detail concerning the WebDynpro ABAP Technology. It was back then when our applications (90% standard with some tweaks and enhancements here and there) were tested against the WCAG 2.0 Standard and, of course, there was room for improvement to be found. One particular point of criticism was "Where are my access keys at, bro? Can't talk into my keyboard to navigate to where I want to, can I, bro?".

 

hello_computer.JPG

 

This situation and a hint from a co-worker made me pay attention to the UI-Property "activateAccessKey" for the first time. For a couple of applications that are bottom line programmed in Freestyle-UI, things weren't very hard to achieve and didn't require too much brainpower:

 

. . .
lo_el_ui_buffer ?= view->GET_ELEMENT( ID = 'Foobar' ).
IF lo_el_ui_buffer IS NOT INITIAL.     CALL METHOD lo_el_ui_buffer->SET_ACTIVATE_ACCESS_KEY EXPORTING VALUE = abap_true.
ENDIF.
. . .

 

Hooray for activated Access Keys! However, it didn't take long before the first GUIBB-based FPM-Application came around the corner where this approach doesn't work, because:

  • The UI-Elements' IDs are created generically and can change whenever the UI-Tree changes, so you can't address them statically in design time
  • You don't really want to program static stuff into the Generic UIBB FPM WDA Components, because ewwww

 

Thus I "designed" (it's pretty trivial actually, if you're much into dynamic programming) the following Class that can be implemented into a Post Exit of WDDOMODIFYVIEW. The Following picture shows what the Class does (note: the picture isn't accessible ). In Before: I only share the approach, I don't share the coding.

 

access_keys_visio.JPG

 

I have then created Enhancement Implementations for each Top-Level-GUIBB-Component and implemented Post Exits for WDDOMOIFY-View calling my class dependent on which application is used(so I'm still in control which Application benefits from this). Example for FPM_FORM_UIBB:

 

access_keys_form_uibb.JPG

And finally here's the result (example from the WDA based Leave Request):

 

access_keys_lea.JPG

 

Notice the underlined First Letters of the Labels? (the 4th Input field has an access key too, but the label has been changed and the Letter that has been assigned by the framework doesn't exist in the new label, in case you were wondering).

 

The downer of that whole approach is, that you have to touch the FPM UIBB Components once with means of an enhancement which is not very elegant. However, the preceding feeder classes do not know what UI-Element Types the fields from the field catalog will have, since this is decided later in the FPM Component Configuration where it's also not possible do declare anything access-key-wise so there is no other way (as far as I know).

 

That's it folks. Maybe this approach is going to be useful to some of you when the Accessibility-Bat comes around

 

Cheers, Lukas

Real-time notifications and workflow using ABAP Push Channels (websockets) Part 4: Creating a Web Dynpro ABAP Application for receiving notifications

$
0
0

This is Part 4 of the below series of blogs:

 

 

 

Now we are going to create a similar application to what we did in Part 3, however this time we are going to use APC (websockets) in a Web Dynpro ABAP application. We do this using a fairly new feature called HTML Islands.

 

 

Create a new Web Dynpro ABAP component called ZWDC_WF_INBOX_MINI

024.PNG

 

 

In the Component Controller create a new Node

025.PNG

 

 

Enter the following:
Node Name: WORKITEMS
Dictionary structure: SWR_WIHDR
Cardinality: 0..n
Init. Lead Selection: No

 

 

Then press the Add Attributes from Structure button

026.PNG

 

Select the WI_TEXT, WI_CD and WI_CT attributes and press the green tick

027.PNG

 

 

 

Create a new method GET_USER_WORKITEMS is the Component Controller and put the following code in it:

028.PNG

 

 

METHOD get_user_workitems .
     
DATA: lo_nd_workitems TYPE REF TO if_wd_context_node.

     
DATA: lt_workitems TYPE wd_this->elements_workitems.

      lo_nd_workitems
= wd_context->get_child_node( name = wd_this->wdctx_workitems ).

     
CALL FUNCTION 'SAP_WAPI_CREATE_WORKLIST'
          
TABLES
                worklist
= lt_workitems.

     
SORT lt_workitems BY wi_id DESCENDING.

      lo_nd_workitems
->bind_table( new_items = lt_workitems set_initial_elements = abap_true ).

ENDMETHOD.

 

 

Then add the following code to the WDDOINIT Method:

METHOD wddoinit .
      wd_this
->get_user_workitems( ).
ENDMETHOD.

 

 

In the V_MAIN View, go to Context and map WORKITEMS to CONTEXT by dragging and dropping it from the right side to the left side.

030.PNG

 

 

Go into Layout tab and start by changing the ROOTUIELEMENTCONTAINER Layout to a RowLayout:

031.PNG

 

 

Right click on ROOTUIELEMENTCONTAINER and click Insert Element.

032.PNG

 

 

 

Enter the following:
ID: WS_HTML_ISLAND
Typ: HtmlIsland

033.PNG

 

 

 

Select WS_HTML_ISLAND and change the height and width to 0px as we do not want this HTML Island to be visible.

034b.PNG

 

 

Now right click on WS_HTML_ISLAND and click on Insert Event.

035.PNG

 

 

Give the Event a name ON_MESSAGE and the press the Create button next to onAction to Create an event handler.

036.PNG

 

 

Enter the Action name as ON_MESSAGE and make sure to tick Transfer UI Event Parameters, then press the green tick.

037.PNG

 

 

Double click on the ON_MESSAGE action created to forward navigate into the method. Then paste in the code below

038.PNG

 

METHOD onactionon_mesage .
     
DATA: lo_api_controller     TYPE REF TO if_wd_controller.

      lo_api_controller ?= wd_this
->wd_get_api( ).

*   report message
      lo_api_controller
->get_message_manager( )->report_message( message_text = data
                                                                message_type
= if_wd_message_manager=>co_type_info
                                                                is_permanent
= abap_false  ).
* refresh work items
      wd_comp_controller
->get_user_workitems( ).
ENDMETHOD.

 

 

 

Go back into the Layout tab and right click on WS_HTML_ISLAND again and add a script this time.

039.PNG

 

 

Enter in websocket_wf_notify.js in the source field. We wil create and upload this javascript file afterwards.

040.PNG

 

 

Save the following source to a file name websocket_wf_notify.js and upload it as a MIME object for the webdynpro.

 

Source code:

 

var MySocket = { 

 

      init: function(callback){

            //Save the call back object to this object

            this.callback = callback;

            var that = this;

            var hostLocation = window.location, socket, socketHostURI, webSocketURI;

 

            if (hostLocation.protocol === "https:") {

                  socketHostURI = "wss:";

            } else {

                  socketHostURI = "ws:";

            }

            socketHostURI += "//" + hostLocation.host;

            webSocketURI = socketHostURI + '/sap/bc/apc/sap/zapc_wf_notify';

        

            try {

                  socket = new WebSocket(webSocketURI);

                  socket.onopen = function() { };

                  var that = this;

   

                  //Create function for handling websocket messages

                  socket.onmessage = function(wfNotify) {

                        // When a message is received fire an event to call the web dynpro code to post the message and

                        // refresh the worklist

                        that.callback.fireEvent('ON_MESSAGE', wfNotify.data);

                  };

   

                  socket.onclose = function() {

                  };

            } catch (exception) {

   

            }

      }

};

 

 

 

Right click on the web dynpro component and go to Create->Mime Object->Import.

041.PNG

 

 

Select the file you created in the previous step websocket_wf_notify.js and click open.

042.PNG

 

 

Then press save.

043.PNG

 

 

Right click on ROOTUIELEMENTCONTAINER again and Insert Element.

044.PNG

 

 

And enter MESSAGE_AREA and select MessageArea as the Type.

045.PNG

 

 

Make sure ROOTUIELEMENTCONTAINER is selected and then press the Wizard button

046.PNG

 

 

Select Table and press Continue.

047.PNG

 

 

Press Context to select the WORKITEMS context:

048.PNG

 

 

Select WORKITEMS and press the green tick.

049.PNG

 

 

No Need to change anything on the next screen, just press the green tick.

 

 

 

In the table properties change design to Alternating and set visibleRowCount to 25.

051.PNG

 

 

Now go into the Methods tab and select the WDDOMODIFYVIEW method.

 

 

And enter the following code to initialise the web socket when the view first loads:

 

METHOD wddomodifyview .
     
DATA: lo_html_island TYPE REF TO cl_wd_html_island.

     
IF first_time EQ abap_true.

           lo_html_island ?= view
->get_element( `WS_HTML_ISLAND` ).

           lo_html_island
->add_script_call( cl_wd_html_script_call=>new_call( )->variable( `MySocket` )->function( `init` )->add_callback_api( )  ).
     
ENDIF.
ENDMETHOD.

 

 

 

Right click on ZWDC_WF_INBOX_MINI and go to Create->Web Dynpro Application.

 

Enter an application name and Description and press the green tick.

 

054.PNG

 

Save and activate everything then right click the Web Dynpro application to run.

 

 

 

Now open the window next to the SAP GUI and create a new parked journal, which will go to my inbox for approval. On saving the Parked Journal document, the notification is immediately displayed in my browser window and the list is automatically refreshed.

 

Before saving:

056.PNG

 

After Saving - Inbox updated with new document automatically and notification displayed:

057.PNG

Dynamically Create/Modify UI elements of Standard components without Enhancing

$
0
0

Introduction

 

Generally, when we need to modify the properties of UI elements of standard component, we go to the corresponding component, Enhance the component and change the properties of the UI element in the Layout( by removing the element and adding our element) Or, create a pre/post-exit for WDDOMODIFYVIEW method and then change the properties through code.


Instead of enhancing the Standard component(sometimes, customers don't want to enhance the standard components, so..); we can use BAdI - WD_BADI_DOMODIFYVIEW


Here, I will just show a simple standard component and change the properties of UI elements without enhancing it.


Procedure

 

Let's take a simple Standard WDA component, say., displaying Flight List.

 

1.jpg

Let's say we need to restrict user not to enter the Depart.City or hide it.

4.jpg

 

For this, generally we go to the corresponding WDA component and enhance it and Remove the UI element or create a post-exit for WDDOMODIFYVIEW and hide the UI element via coding.

 

Now, here, without touching the standard component/enhancing the standard component, we will achieve this by just creating an implementation for BAdI - WD_BADI_DOMODIFYVIEW

 

** WD_BADI_DOMODIFYVIEW is a Filter dependent BAdI with filters COMPONENT_NAME and VIEW_NAME. We will create an implementation with filters values of the corresponding Component name and View Name.

 

Find the Component and View Name( by right click on the view -> Technical Help):

 

2.jpg

3.jpg

 

Find the ID of UI element: you can find it in the technical help -> view and View Elements tab:

5.jpg

 

Or, open the WDA component in SE80 and go to layout to find all the ID's of UI elements.

 

6.jpg

 

Implementation

Go to SE18 transaction and open the BAdI.

7.jpg

Check if already an implementation available for the corresponding component(in filter value), if not, create an Implementation by right clicking on the Implementations.

8.jpg

Enter the Enhancement Implementation and description and click on Ok.

9.jpg

Enter the BAdI implementation name, description and Implementation Class.

10.jpg

 

Now, Create the Filter combination for the BAdI implementation(which is the Standard Component name and View Name).

13.jpg

Note: If you don't create filter values, your implementation will be called for each Web Dynpro application( and may result in dump).

 

Finally, implement the method IF_WD_BADI_DOMODIFYVIEW~WDDOMODIFYVIEW of the BAdI implementation Class

11.jpg

 

Write your code in the method IF_WD_BADI_DOMODIFYVIEW~WDDOMODIFYVIEW of the implementation class.

 

if_wd_badi_domodifyview~wddomodifyview

METHOD if_wd_badi_domodifyview~wddomodifyview.

 

     DATA lr_ui_elem TYPE REF TO cl_wd_uielement.

 

     IF first_time = abap_true.

*     Hide Depart.City Label

       lr_ui_elem ?= view->get_element( 'CITYFROM_LABEL_1_CP' ).

       lr_ui_elem->set_visible( cl_wd_uielement=>e_visible-none ).

*     Hide Depart.City Input

       lr_ui_elem ?= view->get_element( 'CITYFROM_INPUTFIELD_1_CP' ).

       lr_ui_elem->set_visible( cl_wd_uielement=>e_visible-none ).

     ENDIF.

 

  ENDMETHOD.

 

Save and activate the BAdI Implementation and Class.

 

Result

Execute the application and we can see that the label and input of Depart.City is hidden!.

14.jpg

 

Conclusion

Here I demonstrated a simple use case. You can also assign/change value help to UI elements or change the label texts or enable or disable UI elements without enhancing the Standard component and just creating an implementation for the BAdI with the filter values.

 

You can also remove the UI elements or change the order/alignment of UI elements without enhancing the Standard component. For coding you can check this document for reference: Auto Align UI Elements Dynamically in Web Dynpro ABAP

 

Also, you can create multiple implementations with the same filter values.

 

Limitation

With this you can also create UI elements and assign Actions to the UI elements(for ex: Inputs/Buttons) but you need to create the corresponding On_Action method in the Component. This is just the alternative for dynamically manipulating the UI elements instead of enhancing and creating Exit for the WDDOMODIFYVIEW of the standard component(s).

WebDynpro Page Builder

$
0
0

A while back, I gave an internal course about WebDynpro for ABAP.

Since it was a non-official SAP course, I had to create my own course material, but this also opened up the door to focus on aspects normally not covered.

 

So as usual, everyone needed to get upto a certain level of understanding the basics, whilst I indoctrinated them with best-practices and guidelines.

 

Once everyone got the basics and managed to create simple webDynpro components, it was time to start focussing on specific content.

I noticed there was (finally) an upsurge in the use of the NetWeaver Business Client and Sidepanels. Often times, customers get the best practice roles, which come prepackaged with standard sidepanels. Pretty soon however, the need for custom sidepanels rises.

 

Athough creating a sidepanel is no rocket science, there still don't seem to be many developers that really have the hang of it. So I figured this was a good topic to get my class trained in. Also, When searching SCN for Page Builder, I didn't get a lot of hits, so time to put it in the spotlights.

 

Chips

Once you have your WebDynpro component created, you can turn it into a chip. In order to pass parameters to your Component, you an define inports and outports on your Chip. How to do that, is described in following help documentation. In itself, that's not too hard. There's just a couple of things you need to know:

  1. A parameter on a Chip always needs to be a DDIC STRUCTURE. A data element type will not be recognized. (aww)
  2. You can't test a Chip stand-alone
  3. on your port parameters, you must define TAGS. There's a button on your Chip definition, which you can easily overlook

WDA-PageBuilder-003.png

 

In order to test if your component is working correctly, add URL parameters on your component's window (you know, on the default plug handler) and use them to invoke that interface method of your component controller (you know, the inport)

That just makes your life a lot easier to test your component, as if it were a chip, because now you can just launch the application, add parameters, and it will behave as if it is a sidepanel that received parameters.

 

Sidepanel

Once you have your Chip, it's pretty easy to build a sidepanel. In SE80, go to the Webdynpro component WDR_CHIP_PAGE, and on the application, create a new Application configuration and make sure the Tagging parameters are checked.

WDA-PageBuilder-004.png

Top Tip: You can set these parameters globally with the WD_GLOBAL_SETTINGS application.

 

Add a Component configuration and don't alter the contents in the Config-editor. Just save it.

Instead, launch that new application configuration you just created, and use the button in the toolbar to go in Config mode.

WDA-PageBuilder-001.png

In the configuration mode, you can then add your Chip into the page.

WDA-PageBuilder-002.png

Save it, and you have your sidepanel, which you can now add into your PFCG role.

There's just one more step to make your sidepanel talk with your NWBC main application area. In the customizing, you must add your tagging information.

(only required if you use custom tags. if you use the SAP standard tags, than this is not required)

WDA-PageBuilder-005.png

 

You can use the NWBC property collector to find out which info you need to enter and then copy it into the table with your custom tag.

Note that this option only works when you embed a SAPGUI transaction. When using Webdynpro's as main application, you have to customize the Webdynpro application (add URL parameter &sap-config-mode=X)

 

You can then right click an element and add a Tag

WDA-PageBuilder-006.png

And there you have it, a working sidepanel

WDA-PageBuilder-007.png

Cockpits

All of howto create a sidepanel, has already been discussed and documented and there are tutorials out there. So actually, none of the above should be new to you. It's just a condensed form of all the available information with some Tips 'n Tricks.

 

But did you know that the Page Builder is not just for sidepanels?

You can actually use it to create complete Cockpits as well.

You see, you can embed multiple Chips in your page builder, and you can use those tags, to wire information from one Chip to another.

 

On top of that, the wiring will actually fire asynchronous loading of Chips (within the same session mind you), which will improve performance as opposed to complex applications, or FloorPlan Manager applications.

 

So that's what I had my class do. I gave each of them homework to create, a simple Webdynpro component, with some URL parameters.

The next day of the course, after teaching how to create a chip, each of them transformed their homework into a chip.

 

In the last excercise, I had them use the Page builder to wire all their Chips together into a full Purchasing cockpit, demonstrating how the page builder allows you to separate a complex application, into simple components, on which multiple engineers can work simultaneously.

 

WDA-PageBuilder-008.png

Remark: In NetWeaver 7.40, there seems to be a bug that causes the Port parameters not to appear in the Page builder Connection wiring. This bug makes it impossible to properly wire individual components.

I'm still looking for a note to fix that issue.

 

It boils down to the method CL_CHIP_PORT_HELPER~get_parameters_from_rtti

In there they use the CL_ABAP_STRUCTDESCR~get_components, which used to return a table with all Fields, but now it only returns the structure's own fields, and then the type of structure includes, but not the fields contained in the includes!!!

 

As a result, only the fields on the root level of the structure can be used as parameters.

 

Possible solution, use a flat structure with no includes for your port parameters, or SAP could update the implementation of the method CL_CHIP_PORT_HELPER~get_parameters_from_rtti to consider all fields of a structure.

Upload document into KM

$
0
0

Recently i was working on this requirement, and after searching SCN, i did not get a concrete set of steps to follow in orde to upload a document successfully into KM. This is a very common requirement these days, as customer needs to upload document for medical bills, expense receipts, vendor invoices etc for audit requirements.

 

I thought that this is my time to contribute back to the SCN community by giving my 2 cents. I cannot always look only for help.

 

Ok, so uploading the document into KM.

 

1. First thing that we need to have is the WSDL file for the KM server which we need to be able to create a web service in SAP. Once you have your hands on it, follow the below mentioned link to create the web service in ABAP.

 

Create consumer Web service

 

2. Once the proxy class is ready then we need to create a custom wrapper class to call the methods of the proxy class to upload add / delete / modify the documents.

Upload01.PNG

3. While uploading the document you need to create a reference of the logical port in the wrapper class in order to able to communicte to the webservice through that port. You can do that in the upload_document method.

 

Upload02.PNG

 

4. Now we can class the main proxy class method in order to upload the document by populating some information from the method interface.

Upload03.PNG

 

5. Certain fields such as content, length, document name, mime type, location path etc are supplied to the upload_document method interface.

 

6. Similarly in order to download the document from KM server use the method "get_content_metadata" of the proxy class created. For deleting use the method " delete_resource" of the prozy class and call it in the wrapper class.

 

7. Now in Web dynrpo, use the UI element FileUpload. With this UI element you will be able to browse for a file in your local machine i.e. browse button is inbuilt with this UI element.

 

8. Create a context with the following details.

     - Filepath(char255)

     - Filecontent(xstring)

     - URL(char255)

     - mimetype(char1)

 

9. Bind the above mentioend attributes to the UI element properties.

 

10. Add another button "Upload" and on action handler read the context attributes values and use them to call the below mentioned method of the wrapper class to upload the document.

Uplaod04.png

 

11. If everything is fine, we can display a successfull message.

 

12. We can add another set of button to remove, and download attachments.

 

I hope you all like the blog and it serves as a single point of reference for you and it helps you to upload the documents into KM without much hasle.

 

Ashish

Wdr_message_area

$
0
0

how to use the standard webdynpro component wdr_message_area  in custom webdynpro component.i would like to display messages at top of custom webdynpro component using wdr_message_area.

 

help me....

 

 

with regard's

Ravi

Code Snippet Series: Trimming Leading and Trailing Whitespace

$
0
0

This post is part of a series on code snippets. The complete list of posts in the series is available in the document Code Snippets: A Blog Series.

 

ABAP keyword CONDENSE is useful to remove leading and trailing space characters from a character string, however CONDENSE does not recognize other non-printing whitespace characters such as carriage returns, newlines and horizontal tabs.

 

Regular expressions give us a useful tool to recognize a wide variety of whitespace characters. The regular expression abbreviation [[:space:]], alternatively written as \s, represents the character set for all non-printing blank characters including space, carriage return, newline and horizontal tab.

 

The method below removes first trailing then leading whitespace characters from a changing parameter a_string of type string. This code may be used in any ABAP routine but is particularly useful for post-processing of user input in Web Dynpro UI elements such as a TextEdit.

 

METHOD trim_whitespace.

  DATA lv_strlen TYPE i.

  DATA lv_char TYPE string.

* Remove trailing whitespace from a_string

  DO.

      lv_strlen = strlen( a_string ) - 1.

      lv_char = a_string+lv_strlen(1).

      FIND REGEX '[[:space:]]' IN lv_char.

      CASE sy-subrc.

          WHEN 0.

              SHIFT a_string RIGHT DELETING TRAILING lv_char.

          WHEN OTHERS.

              EXIT.

      ENDCASE.

  ENDDO.

* Remove leading whitespace from a_string

  DO.

      lv_char = a_string+0(1).

      FIND REGEX '[[:space:]]' IN lv_char.

      CASE sy-subrc.

          WHEN 0.

              SHIFT a_string LEFT DELETING LEADING lv_char.

          WHEN OTHERS.

              EXIT.

      ENDCASE.

  ENDDO.

ENDMETHOD.


Secure transferring of parameters between WDA Applications

$
0
0

I need enough secure solution for transfer pernr number from one WDA application to Another.

We cant use parameter directly because experienced users can modify it and view restricted data.

 

Application must be completely independent without sharing interface controller variables.

 

 

Solution was found  in application HRESS_A_PERSINFO thanks to Bhaskar Tripathi's question http://scn.sap.com/message/15249282

 

 

WD component HRESS_C_PERNR_SELECTION uses Assistance Class CL_HRESS_AS_PERNR_SELECTION.

 

In Sender Apllication we write data to Memory and get random ID in  RV_MEM_ID.

 

CALL METHOD CL_HRESS_EMPLOYEE_SERVICES=>SET_PERNR_TO_MEMORY

   EXPORTING

     iv_pernr                  = lv_pernr

*     IV_DISP_CE_ASSIGTS_SCREEN =

*     IV_NON_EIC_MODE           =

   RECEIVING

     RV_MEM_ID                 = w_value

 

Then we construct URL and open second application.

 

* Get the URL of the called application

  CALL METHOD cl_wd_utilities=>construct_wd_url

    EXPORTING

      application_name = 'ZBHRWD_INC_CRiteria_ESS'

    IMPORTING

      out_absolute_url = w_url.

 

*Attach the parameters and its value with the URL that

* have to be passed to the 2nd application

  CALL METHOD cl_http_server=>append_field_url

    EXPORTING

      name  = 'PERNR_MEM_ID'

      value = w_value

    CHANGING

      url   = w_url.

 

In receiver application read the pernr by Memory ID

 

wd_assist->get_pernr_from_memory(

           exporting

           iv_pernr_mem_id      = wd_comp_controller->gv_memid

           IMPORTING

            ev_pernr = lv_pernr ).

 

In this case we need not to do authorization checks in receiver application.

Calling Transaction in SAP GUI

$
0
0

Calling SAP Transaction from WDA is a common requirement. There is a way to call SAP transaction in Web GUI. This is not an option in some cases.


Imagine a client that is using SAP GUI to run both SAP Transactions and WDAs. Such client wants to keep user interface consistent e.g. whenever WDA calls SAP transaction it needs to be run in SAP GUI (no jumps between SAP GUI and Web GUI).


There is an OOTB solution. Simply put, WDA needs to create SAP Shortcut and download it when user clicks on a link.

 

Below are screenshots of demo WDA that runs in SAP GUI and shows a list of SAP Flight model tables. Clicking on a table name from the list will call SE16 transaction in SAP GUI.

 

1. Call Z_WD_2_ABAP Transaction

Call Z_WD_2_ABAP Transaction.jpg

 

2. Click on a link

Click on a link.jpg

 

3. Confirm download

Confirm SAP Shortcut download.jpg

 

4. Voilà

Voilà.jpg

 

Below are step by step instructions how to create this demo WDA:

 

1. Create Z_WD_2_ABAP Component

Create Z_WD_2_ABAP Component.jpg

 

2. Create SFLIGHT context node in MAIN view. Set the context node cardinality to 0..1. Add two attributes: TABLENAME of type TABNAME and DESCRIPTION of type DDTEXT

Create SFLIGHT Context Node.jpg

 

3. Create VIEWCONTAINER ViewContainerUIElement on MAIN view

Create VIEWCONTAINER ViewContainerUIElement.jpg

 

4. Add ALV use of SALV_WD_TABLE Component to Z_WD_2_ABAP Component

Add ALV Component Use of SALV_WD_TABLE Component.jpg

 

5. Add ALV use of SAV_WD_TABLE Component to MAIN View

Add ALV Use of SALV_WD_TABLE to MAIN View.jpg

 

6. Embed TABLE view of SALV_WD_TABLE used component into VIEWCONTAINER element

Embed TABLE View of SALV_WD_TABLE Component into  VIEWCONTAINER Element.jpg

 

7. Implement WDDOINIT method of MAIN view

Note: code below populates ALV table with a list of SAP FLIGHT model tables

 

METHOD wddoinit.
DATA: wd_sflightTYPE wd_this->elements_sflight.
DATA: node_sflightTYPE REF TO if_wd_context_node.
DATA: wa_columnTYPE salv_wd_s_column_ref,
      wt_column
TYPE salv_wd_t_column_ref.
DATA: component      TYPE REF TO if_wd_component_usage,
      interface     
TYPE REF TO iwci_salv_wd_table,
      config         
TYPE REF TO cl_salv_wd_config_table,
      table_settings 
TYPE REF TO if_salv_wd_table_settings,
      std_functions 
TYPE REF TO if_salv_wd_std_functions,
      column_settings
TYPE REF TO if_salv_wd_column_settings,
      column         
TYPE REF TO cl_salv_wd_column,
      column_header 
TYPE REF TO cl_salv_wd_column_header,
      action         
TYPE REF TO cl_salv_wd_uie_link_to_action.

 
SELECT l~tabnameAS tablenamet~ddtextAS description
 
INTO CORRESPONDINGFIELDS OF TABLE wd_sflight
 
FROM ( dd02l AS l INNERJOIN dd02t AS t
                           
ON l~tabname= t~tabname)
                   
INNERJOIN tadirAS d
                           
ON l~tabname= d~obj_name
 
WHERE t~ddlanguage= 'E'
   
AND d~object    = 'TABL'
   
AND d~devclass  = 'SAPBC_DATAMODEL'.
  node_sflight
= wd_context->get_child_node( wd_this->wdctx_sflight).
  node_sflight
->bind_table( new_items= wd_sflight).

  component
wd_this->wd_cpuse_alv( ).
 
IF component->has_active_component( ) IS INITIAL.
    component
->create_component( ).
 
ENDIF.

  interface
= wd_this->wd_cpifc_alv( ).
  interface
->set_data( node_sflight).
  config
= interface->get_model( ).

  table_settings ?= config.
  table_settings
->set_selection_mode(cl_wd_table=>e_selection_mode-none ).
  table_settings
->set_visible_row_count(20 ).

  std_functions ?= config.
  std_functions
->set_view_list_allowed(abap_false).
  std_functions
->set_filter_filterline_allowed(abap_false).
  std_functions
->set_dialog_settings_allowed(abap_false).
  std_functions
->set_pdf_allowed(abap_false).
  std_functions
->set_export_allowed(abap_false).

  column_settings ?= config.
  wt_column
= column_settings->get_columns( ).
 
LOOP AT wt_columnINTO wa_column.
    column
= wa_column-r_column.
   
CASE wa_column-id.
   
WHEN 'TABLENAME'.
     
CREATE OBJECT action.
      action
->set_tooltip_fieldname( wa_column-id).
      action
->set_text_fieldname( wa_column-id).
      action
->set_type( cl_wd_link_to_action=>e_type-navigation ).
      column
->set_cell_editor( action ).
   
WHEN 'DESCRIPTION'.
      column_header
= column->get_header( ).
      column_header
->set_text('Description' ).
      column_header
->set_tooltip('Description' ).
      column_header
->set_ddic_binding_field(
        if_salv_wd_c_column_settings
=>ddic_bind_none).
   
ENDCASE.
 
ENDLOOP.

ENDMETHOD.


8. Create ON_CLICK event handler method for ON_CLICK Event of ALV usage

Create ON_CLICK Event Handler Method for ON_CLICK Event of ALV Usage.jpg

 

9.  Implement ON_CLICK event handler method

Program logic:

- Get clicked table name;

- Set trx. SE16 Table Name field to clicked table name;

- Create SE16 SAP Shortcut skipping first screen. See Note 103019 - SAPshortcut: Program parameters for more information.

- Download SAP Shortcut

 

METHOD on_click.
DATA: w_filenameTYPE string.
DATA: w_parameterTYPE text255.
DATA: w_shortcutTYPE xstring.
DATA: wt_shortcutTYPE soli_tab.
FIELD-SYMBOLS: <tablename> TYPE tabname.

* Get clicked table name
  ASSIGN r_param->value->* TO <tablename>.

* Set trx. SE16 Table Name field to clicked table name
  CONCATENATE 'DATABROWSE-TABLENAME=' <tablename> INTO w_parameter.
* Create SE16 SAP Shortcut skipping first screen
  CALL FUNCTION 'SWN_CREATE_SHORTCUT'
     
EXPORTING
            i_transaction  =
'*SE16'
            i_parameter   
= w_parameter
     
IMPORTING
            shortcut_table
= wt_shortcut.
  w_shortcut
= cl_bcs_convert=>raw_to_xstring(it_soli= wt_shortcut).
  CONCATENATE 'Table_' <tablename> '.sap' INTO w_filename.

 

* Dowload SAP Shortcut
  cl_wd_runtime_services
=>attach_file_to_response(
    i_filename     
= w_filename
    i_content       
= w_shortcut
    i_mime_type     
= 'sap' ).

ENDMETHOD.

 


10. Create Z_WD_2_ABAP Application

Create Z_WD_2_ABAP Application.jpg

 

11. Create Z_WD_2_ABAP parameter transaction

Create Z_WD_2_ABAP Transaction with parameters.jpg

Undocumented feature: How to use a Function Module as action handler in the POWL Inbox IBO_WDA_INBOX (CA-EPT-IBO)

$
0
0

Introduction

 

With the POWL Inbox (Web Dynpro Component name IBO_WDA_INBOX) customers can define custom tasks, actions and action properties just like with Business Workflow Workplace and UWL. SAP provides configuration at least for the most common ESS and MSS tasks. The POWL Inbox has two sets of configuration tables, SAP provided configuration and customer configuration tables. The most commonly used action handlers of the POWL Inbox are the Object Based Navigation (OBN) and Launchpad ones, OBJECTNAVIGATIONLAUNCHER and LAUNCHPADHANDLER respectively. There is a third one, the FUNCTIONMODULEACTIONHANDLER one. The last one isn't documented and I don't think that it is that apparent how to use it so this blog tries to address that.

 

Configuration

 

When defining actions, use FUNCTIONMODULEACTIONHANDLER as action type. When defining action properties use FUNCTIONMODULE as name and the function module you would like to invoke as value. Now this far most would have gotten just by reading the official documentation and using their gray cells, the tricky parts are to follow.

 

First thing you should know is that the function module to be used has to have generic (e.g. simple) import, export, tables and exceptions. For example LIKE isn't supported (only TYPE is) nor are complex types such as references (TYPE REF). The next thing to take notice of is that other action properties (besides FUNCTIONMODULE) that you define are considered as parameters of the function module. Let's say you define an action property named WI_ID with a value of WI_ID=${ITEM.EXTERNALID}. Doing so means your function module should have WI_ID as an import parameter (preferably of type SWW_WIID) to have the work item ID automatically passed to it. Another hard coded feature of the function module action handler is that it assumes to get error messages in a table named MESSAGE_LINES, similar to most SAP_WAPI function modules.

 

If you want to understand it in detail, have a look at the ABAP class CL_IBO_CH_WD_INB_ACTHDL_FM.

 

Conclusion

 

The function module action handler can be very useful. I used it myself to call a wrapper function module for SAP_WAPI_WORKITEM_COMPLETE in order to complete a work item just by clicking it. It's a shame that this feature might remain unnoticed by the masses if only relying on official documentation.

 

Links

 

The official documentation for the POWL Inbox can be found here. In order to learn more about the POWL Inbox, read POWL Inbox configurations for Manager Self-Service EhP5 and above and How to enable the existing Webdynpro based workflow inboxes to execute ALL tasks without config!.

Open Excel sheet from DMS

$
0
0

Original of this article is published on my personal site at oprsteny.com

 

In this article I'll show you how to retrieve an Excel sheet from SAP DMS (Document management System) where it is stored as "original" in a Document container.

 

Let's presume that:

  • we already have our document stored in DMS and we know the document's number, type, version and part (these are key fields we have to know to be able to retrieve the document)
  • We know how to create a webdynpro component/application
  • We have already created new WDY component/application with one Window containing one View where we placed the OfficeControl of type MS_EXCEL from the Integration layout controls.

 

1. Read document information (metadata)

 

DATA:  ls_document_data  TYPE bapi_doc_draw2,  ls_return         TYPE bapiret2,  lt_document_files TYPE TABLE OF bapi_doc_files2_keys.

FIELD-SYMBOLS:
  <ls_document_file> LIKE LINE OF lt_document_files.

* Specify our document key
ls_document_data-documenttype    = 'ZTP'. 
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'  EXPORTING    input         = '3000000000003'  IMPORTING    OUTPUT        = ls_document_data-documentnumber.
ls_document_data-documentversion = '00'.
ls_document_data-documentpart    = '000'.

* Read document info
CALL FUNCTION 'BAPI_DOCUMENT_GETLIST2'
      EXPORTING        select_documentdata = ls_document_data        getdocfiles         = 'X'      IMPORTING        return              = ls_return      TABLES        documentfiles       = lt_document_files.    IF ls_return-type CA 'EA'      OR lines( lt_document_files ) = 0.
*      RAISE EXCEPTION document_does_not_exist.    ENDIF.

* To simplify our example we read just the first file from 
* the document container
    READ TABLE lt_document_files ASSIGNING <ls_document_file> INDEX 1.

 

2. Read document contents (binary data)

 

DATA:  lt_cvapi_files   TYPE TABLE OF cvapi_doc_file,  lt_bapi_files    TYPE t_bapi_doc_files2,  lt_drao          TYPE dms_tbl_drao,  ls_message       TYPE messages,  lt_orblk         TYPE TABLE OF orblk,  lv_excel_xstring TYPE xstring  lv_data_size     TYPE i.

FIELD-SYMBOLS:
       TYPE drao,      TYPE orblk.

* Convert BAPI file structure to CVAPI file structure
APPEND <ls_document_file> TO lt_bapi_files.
CALL FUNCTION 'MAP2I_BAPI_FILE2_TO_API_FILE'  TABLES    bapi_doc_file = lt_bapi_files    api_doc_file  = lt_cvapi_files.

* Get binary data from system
* Content provider is set to 'TBL' 
* -> tabular data filled in lt_drao
CALL FUNCTION 'CVAPI_DOC_CHECKOUTVIEW'  EXPORTING    pf_dokar           = <ls_document_file>-documenttype    pf_doknr           = <ls_document_file>-documentnumber    pf_dokvr           = <ls_document_file>-documentversion    pf_doktl           = <ls_document_file>-documentpart    pf_content_provide = 'TBL'  IMPORTING    psx_message        = ls_message  TABLES    pt_files           = lt_cvapi_files    ptx_content        = lt_drao  EXCEPTIONS    error_message      = 1    OTHERS             = 2.

* Get the binary data and its length
LOOP AT lt_drao ASSIGNING <ls_drao>.  APPEND INITIAL LINE TO lt_orblk ASSIGNING <ls_orblk>.  <ls_orblk> = <ls_drao>-orblk.  IF lv_data_size IS INITIAL.    lv_data_size = <ls_drao>-orln.  ENDIF.
ENDLOOP.

* Convert binary data from itab to xstring
CALL FUNCTION 'SCMS_BINARY_TO_XSTRING'
  EXPORTING    input_length       = lv_data_size  IMPORTING    BUFFER             = lv_excel_xstring  tables    binary_tab         = lt_orblk.

 

3. Initialize the WDY Office Control

 

As we initially presumed - we have a WDY component with one View which contains the OfficeControlof type MS_EXCEL element in the Layout. Now we have to create a context Attribute where we will store the Excel binary data.

  1. In the View's Context tab create new Attribute of type XSTRINGand name it e.g. XLS_DATA
  2. In the View's Layout select the OfficeControl and bind its dataSourceto the context attribute XLS_DATA

 

If you reached this point, you already know how to read the Excel data, you know how to integrate OfficeControl to the WDY view and bind it to the view's Context attribute. Now we just have to fill the Context attribute with data we've already prepared before - you can put the following piece of code e.g. in the View's WDDOMODIFYVIEW method in case you want to initialize the Excel control in the WDY right from the start

 

wd_context->set_attribute(  EXPORTING    value = lv_excel_xstring    name  = 'XLS_DATA'
).

 

Now if you try to run your WDY application in browser, you should see the Excel being displayed within the browser window and loaded with data of the XLS sheet from your DMS document.

How to call a SAP GUI transaction from Webdynpro ABAP using NWBC

$
0
0

Introduction

When using Web Dynpro for ABAP, sometimes we have the need to call other functions or transactions in the SAP system landscape. In the "old days" where everything was done in ABAP and the user was calling the SAP system by using an SAP GUI  - this was easy; just call the requried function and a new session was launched in the GUI.

This has changed - several technologies for user UI development are possible, This means that whe could have a switch between technologies inside a Business Process.

 

The good news is that the NWBC can act as a framwork for this. Using the NWBC we can have an central application we all our SAP functions are processes inside, without having a lot of browser windows popping up etc.

 

This example shows how to develop a simple Webdynpro application, where the user can enter a Sales Order number and from the Dynpro call transaction VA03 in SAP GUI.

 

Prerequsites

SAP ERP System

Netweaver Business Client (setup and running)

Basic Web Dynpro Knowledge

 

How is it done?

The goal is reached by using Object-Based Navigation (OBN). OBN is used in Roles (PFCG) to assign an object to a function.

 

What basically happens is that the OBN call searches the Roles of the user calling a certain function and when found it launches the corresponding transaction (or other function). Because of that we will later se, that the OBN is very tightend to the Roles of the user (but NWBC is anyway)

 

 

Do the stuff

First of all we create the WebdynPro application. It could be a list of Sales Orders or anything, but in this example it´s just a simple screen with an input field and a button:

 

blog1.PNG

 

This is quite basic: an input field whe the user can enter a Sales Order number and a pushbutton to excute...

 

The interresting part is the code of the Action of the button:

blog2.PNG

 

The onAction event is implemented like this:

blog3.PNG

First part is done to retrieve the value of the Sales Order from the screen. Second part is the interesting one:

 

By using the IF_WD_PORTAL_INTEGRATION class we can exceute the call of the Business Transaction. Note! There is no SAP Portal involved here - it works without!

 

Four parameters are used here:

OBJECT_TYPE:                    This is the type of object called

OBJECT_VALUE_NAME        This is the name of the parameter passed to the call

OBJECT_VALUE                   This is the value passed from screen

OPERATION                         This is the operation to call

 

To fully understand the above coding i will goto the next step right now:

 

We will have to define a Role (or expand an existing one) in order to give the user the required functionality:

 

Call PFCG and create a role:

blog4.PNG

 

The role consist of a Root folder and a Subfolder (NWBC requires at least one lower level). First "pin" is the Web Dynpro Application created in step one - just basic call of a Web Dynpro application.

 

Second "pin" is the Sales Order display Transaction VA03. When you press the Other Node Details button you will notice the OBN part below

 

blog5.PNG

 

  This is where we apply our OBN part. Press Insert Method button

blog6.PNG

 

In here we can use a BOR object as the object. We choose BUS2032 (SalesOrder) and method Display

 

blog7.PNG

 

Next screen is for entering the parameters

blog8.PNG

 

This is where we pass the actual value from the screen to the transaction. Parameter ID (first column) is found by entering transaction and get the Scrren field name (F1->technical).

In the second column the value is intered - by using Curly bracktes we tell the system that we vil pass a variable value.

 

Note: the BOR object used is only for defining the naming of the Object type etc. No BOR object logic are called at runtime! In part 2 i will show how to use a none BOR value...

 

Now the Role are ready to use!

blog9.PNG

 

Save it and assign to a user.

 

Start NWBC

blo10.PNG

Execute the Web Dynpro App

blog11.PNG

Enter Sales Order number and press Button

blog12.PNG

 

So: the VA03 are called with a regular SAP GUI interface - no HTML GUI. We have done a Switch between technologies from Web Dynpro ABAP to SAP GUI.

 

What happened?

The system was told to call a Business Object called SalesOrder with the method Display (SalesOrder.Display). When that called was executed it searches the Roles assigned to the logged in user for an entry with the OBN assignment SalesOrder.Display.

 

When found in the Role, it executed the transaction assigned to that menu point and passed the value from the Screen field to the VBAL-VBELN fields in VA03.

Viewing all 141 articles
Browse latest View live


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