Altius Community

Altius Consulting Community
Welcome to Altius Community Sign in | Join | Help
in Search

Adam Adshead

  • Developing Accessible Web Applications with SAP Web Dynpro

    The emergence of the Internet has provided the ability to access web applications across the world and to a vast number of people. Keeping this in mind web applications should have a Universal Design that does not exclude any potential users. In this blog I will give a brief overview of the current accessibility directives for web technologies and then describe how some of Web Dynpro’s features can assist in building more accessible web applications.

    In many countries accessibility to information technology has been led by initiatives, laws and regulations. The most notable is the Web Accessibility Initiative (WAI) which is part of the World Wide Web Consortium (W3C). The initiative provides an international set of guidelines, technical reports, educational materials and other documents that help to improve different aspects of web accessibility. There is also section 508 of the US Rehabilitation Act that has laid out a set of rules designed to help web developers make their sites accessible. SAP has set out some specific Accessibility Guidelines for Web Dynpro to improve accessibility when building web applications.

    Web Dynpro has built-in accessibility checks that are carried out automatically on performing a syntax check. These checks are there to make sure that all user interface (UI) elements have some property set to make them easy to read. For example the Label and Button elements have a check that if the Text property was not filled, then the Tooltip property should be. These accessibility checks will not prevent the application from being compiled, but they will display a warning so the developer can correct them. A full list of these checks can be found on SAP’s help page under UI Element Checks. It is worth noting that these are not carried out when the application is in a temporary development package ($TMP). If you wish to ignore these warnings they can be switched off on the Web Dynpro component properties by un-checking the highlighted check box.

    clip_image003

    Web Dynpro has an accessibility mode that provides additional keyboard accessibility functions and will allow use of a screen reader if one is connected to the user’s computer. To set accessibility mode on, you need to post fix ‘?sap-accessibility=X’ to the URL of the page, or add the WDAccessibility parameter to the application and specify ‘X’ as a value.

    clip_image005

    clip_image007

    Web Dynpro applications are fully keyboard compliant, meaning the user can interact with them using only a keyboard. The developer is not offered the option to configure tab order, this will be defined automatically by the Web Dynpro framework. The order is top to bottom, left to right, within each grouping of elements. Common shortcuts are used like the tab key for navigation, control Z and control Y for undo and redo respectively. A full list of these keyboard commands can be found on SAP’s help page.

    Screen readers are accommodated in Web Dynpro by a few attributes on UI elements. The Accessibility Description is usually found on elements that group other elements, like the Tab Strip or Transparent Container. This property is used to include a title for elements that may not have a visible header. The Label has a similar property called Label For to describe its associated element. Also the Tooltip text is another useful property which is read by screen readers. This should be used to display the UI element’s semantic information. Be careful when setting this though, it is best to add short concise descriptions rather than more lengthy texts that could be confusing. Tooltips should not be used for some elements like the Label because they will not be read by screen readers. Here, it is best to add the tooltip to the object the label is pointing to, i.e. Input fields, list boxes etcetera.

    clip_image009

    To test accessibility texts SAP provides a quick method using an additional ‘sap-accessibility-debug=X’ URL parameter. This needs to be added along with the ‘sap-accessibility=X’ parameter. When this is set, the accessibility text will be displayed in a window at the bottom of the browser. The text will be associated to each element you select on the page. The order of accessibility text will be:

    • Text of the Label
    • Type of the Element
    • Value of the field
    • State of the current field (read-only, modifiable, inactive, not available)
    • Tooltip Text
    • Tutor is additional information about how to use the element.

    It is advised to test each element’s accessibility text is easy to understand while this is active. The Accessibility Guidelines for Web Dynpro provides a full list of other accessibility features that should also be tested, see the section titled ‘Manual Tests at Runtime’.

    In conclusion, Web Dynpro offers the tools to make your web applications accessible to as many users as possible. All of these features are very straight forward to use and in the situation the developer might miss some helpful text, the framework will warn them. I have included a list of useful resources below.

     

    References

    Universal Design - http://en.wikipedia.org/wiki/Universal_design

    Web Accessibility Initiative - http://en.wikipedia.org/wiki/Web_Accessibility_Initiative

    Section 508 of the Rehabilitation Act - http://www.access-board.gov/sec508/guide/act.htm

    Accessibility Guidelines for Web Dynpro - http://www.sapdesignguild.org/resources/Accessibility_Guideline_WebDynpro_external_Version.pdf

    UI Element Checks - http://help.sap.com/saphelp_nw04s/helpdata/en/19/e64941bfb4de2be10000000a1550b0/content.htm

    Keyboard Commands - http://help.sap.com/saphelp_nw04s/helpdata/en/47/60a081df4b3d31e10000000a42189c/frameset.htm

  • Creating a WebDynpro Tree Component based on an InfoObject Hierarchy

    Background

    This blog describes how to create a custom Web Dynpro Tree component based on an InfoObject hierarchy. The tree will use a recursive context node to configure its size at runtime. This will have the benefit that the Web Dynpro tree reflects any future changes made to the underlying InfoObject, reducing future maintenance.

     

    The Data we are Modelling

    An SAP InfoObject is a characteristic that can be stored in a dimension of a cube, such as company code, product, fiscal year etc. InfoObject's can contain master data as attributes, texts or hierarchies. These are all setup in transaction RSA1, under Modelling. The screenshot below shows the hierarchy tab of an InfoObject. The hierarchy has three master data tables:

    1. Hierarchy table
    2. Hierarchy SID tab
    3. SID HierarchyStruc

    clip_image003

    We will be using the Hierarchy table to read the structure of the hierarchy into a Web Dynpro context node. The screenshot below shows the structure of this table.

    clip_image005

    The fields we will use from the hierarchy table to build the tree’s structure are:

    • NodeId
    • NodeName, and
    • ParentId.

    We will also create a join onto the Texts table to retrieve a description of the data. You can find the name of the Texts table by looking at the ‘Master data/texts’ tab of the same InfoObject in transaction RSA1. Note this will need to be an outer join onto the texts table if you require text nodes in your hierarchy. Text nodes have an entry in the hierarchy table but not in the Texts table, so an inner join would not find these records.

     

    Build Overview

    The tree will be built at runtime, level by level, when the user requests it. This means that on initialising the view, only the root node is created. The rest of the tree will be built when the user clicks to display the next level. This event triggered is called OnLoadChildren, we will assign an action to this in the step by step guide.

    I have tried building the entire tree on initialising the Web Dynpro view and then binding it to the context node. I would not recommend this approach though as it is more complex because it requires a routine to iterate through the master data hierarchy, building up the structure.

     

    Step by Step Guide

    Step One

    First we create our model of the data using the Web Dynpro context nodes and attributes. The first node will be the root, with a subsequent parent node and its attributes. The parent node will have a recursive node that points to itself, this allows a dynamic number of levels.

    Two context nodes will be created, one to model the tree and the other to hold data for the currently selected node. The Selection node will be identical to the Parent node with the exception of the recursive node.

    clip_image007

    The Parent context node’s cardinality property will need to be set to 1..n. This allows the node to support multiple children. All other context nodes will have the default properties.

    The attribute's data types are shown below.

      image

    Step Two

    We can now create our tree component and bind it to our data model.

    On the Web Dynpro view, insert a Tree component called TREE and then insert a Tree Node Type component called TREE_NODE within the tree. The TREE component will be mapped to the root of our data model and the TREE_NODE will display the hierarchy we read from the InfoObject.

    I have made the following changes to the default properties of the TREE and TREE_NODE components:

    image

     image

    The data source property is bound to the path of the context node. The Has Children property specifies whether the node can be expanded to display its children and the Text property is mapped to the description, this will show the user friendly name of the node.

    Step Three

    In this step we will create the required methods and actions.

    All required code is found at the end of this blog split into Methods and Actions. The tables below give a brief description of what these methods/actions are used for:

    image

    image

    The following tables display the method’s and action’s parameters.

    image

    image

    Step Four

    Now the actions have been created, we can assign them to our tree component. These are done on the Tree Node Type components of the tree.

    image

     

    The tree should now be complete. This component can be applied to any hierarchy that has been created with the simple adjustment to the name of the hierarchy table and the root node.

     

    Methods

       1: method WDDOINIT .
       2:   DATA:
       3:     lr_current_node    type ref to if_wd_context_node,
       4:     lr_current_element type ref to if_wd_context_element.
       5:  
       6:   lr_current_node    = wd_context->get_child_node( 'ROOT' ).
       7:   lr_current_element = lr_current_node->get_lead_selection( ).
       8:   create_node(
       9:     exporting
      10:       cur_element = lr_current_element
      11:  
      12:       node_name   = 'PARENT'). 
      13: endmethod.
      14:  
      15: method CREATE_NODE .
      16:   DATA:
      17:     lr_cur_node type ref to if_wd_context_node.
      18:  
      19: * create the new node by requesting it as a child node
      20:   lr_cur_node = cur_element->get_child_node( node_name ).
      21:  
      22: * create its elements
      23:   create_element(
      24:     exporting
      25:       cur_element  = cur_element
      26:       cur_node     = lr_cur_node
      27:       node_name    = node_name ).
      28: endmethod.
      29:  
      30: method CREATE_ELEMENT .
      31:   DATA:
      32:     ls_parent             TYPE                  wd_this->element_parent,
      33:     wa_parent             TYPE                  wd_this->element_parent,
      34:     itab_parent           TYPE TABLE OF         wd_this->element_parent,
      35:     lr_cur_element        TYPE REF TO           if_wd_context_element,
      36:     loop_counter          TYPE                  i.
      37:  
      38: **************************************************************************** 
      39: *  Add code to select data from hierarchy and text data into itab_parent 
      40: ****************************************************************************
      41:  
      42:    SORT itab_parent BY PARENT_ID.
      43:  
      44:   IF NODE_NAME = 'PARENT'.
      45:     " Set Root Node
      46:     READ TABLE itab_parent
      47:       INTO ls_parent
      48:       WITH KEY NAME = [root node name].
      49:  
      50:     lr_cur_element = cur_node->create_element( ).
      51:     lr_cur_element->set_attribute( name = 'NAME' value = ls_parent-NAME ).
      52:     lr_cur_element->set_attribute( name = 'DESCRIPTION' value = ls_parent-description ).
      53:     lr_cur_element->set_attribute( name = 'ID' value = ls_parent-ID ).
      54:     lr_cur_element->set_attribute( name = 'HAS_CHILDREN' value = abap_true ).
      55:     cur_node->bind_element( new_item = lr_cur_element set_initial_elements = abap_false ).
      56:    ELSE.
      57:     " Set CHILD Node
      58:     CUR_ELEMENT->get_static_attributes(
      59:       IMPORTING
      60:         static_attributes = ls_parent ).
      61:  
      62:     loop_counter = 0.
      63:  
      64:     LOOP AT itab_parent INTO wa_parent
      65:       WHERE PARENT_ID = ls_parent-ID.
      66:  
      67:       " Determine if node has children
      68:        READ TABLE itab_parent
      69:          TRANSPORTING NO FIELDS
      70:          WITH KEY PARENT_ID = wa_parent-ID BINARY SEARCH.
      71:  
      72:        IF SY-SUBRC = 0.
      73:          wa_parent-has_children = abap_true.
      74:        ELSE.
      75:          wa_parent-has_children = abap_false.
      76:        ENDIF.
      77:  
      78:        lr_cur_element = cur_node->create_element( ).
      79:        lr_cur_element->set_attribute( name = 'NAME' value = wa_parent-name ).
      80:        lr_cur_element->set_attribute( name = 'DESCRIPTION' value = wa_parent-description ).
      81:        lr_cur_element->set_attribute( name = 'ID' value = wa_parent-id ).
      82:        lr_cur_element->set_attribute( name = 'HAS_CHILDREN' value = wa_parent-has_children ).
      83:  
      84:        " Only set the initial element on first child
      85:        IF loop_counter = 0.
      86:          cur_node->bind_element( new_item = lr_cur_element set_initial_elements = abap_true ).
      87:        ELSE.
      88:          cur_node->bind_element( new_item = lr_cur_element set_initial_elements = abap_false ).
      89:        ENDIF.
      90:  
      91:        loop_counter = loop_counter + 1.
      92:     ENDLOOP.
      93:   ENDIF.
      94: endmethod.
     

    Actions

       1: method ONACTIONLOAD_CHILDREN .
       2:  
       3:   DATA:
       4:     lr_context_element type ref to if_wd_context_element.
       5:  
       6: * get the context element at which we are supposed to do load the children
       7:   lr_context_element = wdevent->get_context_element( 'CONTEXT_ELEMENT' ).
       8:  
       9: * create the child nodes, if necessary
      10:   create_node(
      11:     exporting
      12:       cur_element = lr_context_element
      13:       node_name   = 'CHILD' ).
      14:  
      15: endmethod.
      16:  
      17:  
      18: method ONACTIONSELECT_NODE .
      19:   DATA:
      20:     ls_parent             TYPE        wd_this->element_parent,
      21:     lo_nd_selection       TYPE REF TO if_wd_context_node,
      22:     lo_el_selection       TYPE REF TO if_wd_context_element.
      23:  
      24:   CONTEXT_ELEMENT->get_static_attributes(
      25:     IMPORTING
      26:       static_attributes = ls_parent ).
      27:  
      28:   lo_nd_selection = wd_context->get_child_node( name = wd_this->wdctx_selection ).
      29:   lo_el_selection = lo_nd_selection->get_element(  ).
      30:   lo_el_selection->set_static_attributes(
      31:     EXPORTING
      32:       static_attributes = ls_parent ).
      33: endmethod.

     

    Technorati Tags: ,,,,
  • Integrating SAP’s Business Information Warehouse with Web Dynpro

     

    Recently I have been working with SAP’s Web Dynpro for ABAP to create a customised workflow application that is integrated with the Business Information (BI) Warehouse. When considering how to implement the workflow application we first looked at SAP’s off the shelf Status and Tracking System (STS) that is included with BW Business Planning and Simulation. STS met most of our needs but was too rigid when trying to enhance it. To meet our needs we created the web application using Web Dynpro which offers a blank canvas that is completely customisable and can offer a very attractive and user friendly interface.

    The development environment is part of the ABAP Development Workbench allowing it access to the ABAP dictionary like any other ABAP object. This gives us full access to our SAP BI system as well as the rest of the Netweaver 2004s suite.

     

    clip_image002

     

    Web Dynpro is based on the Model View Controller (MVC) architecture to separate the content, logic and layout providing good reusability if you need a similar application used across different business areas. The Web Dynpro component sits on SAP’s Portal offering further functionality to the information repositories and portal services. Below is a screenshot of one of several Web Dynpro components created. This component allows opening a workbook from Business Explorer’s (BEx) Analyzer, sending emails to a dynamic list of users and saving settings to database tables.

     

    image 

     

    We’ve found the final application to be very robust and the performance has been good. The development environment offers a flexible way of storing information in memory using a concept of context nodes as data structures. These structures are adhoc and can be quick to implement if you are copying from similar nodes or a table's structure. Context nodes can also be recursive allowing them to be created at runtime from ABAP code.

  • Using BEx Analyzer's API via VBA

    Introduction

    Netweaver 7.0 exposes the interface for Business Explorer’s (BEx) Analyzer in Visual Basic for Access (VBA) code. This blog describes how we can use this interface via VBA code held in our workbooks.

     

    Why might we want to do this?

    The VBA language  is now in its 15th year of use, it is rich in functionality and offers a wide range of integration with multiple applications and data sources  including the web. Combining this with BEx Analyzer we can automate our tasks between data from a variety of sources and SAP’s Business Intelligence Warehouse. The use of VBA to work with the Application Programming Interface (API) can also be used to work around some of the limitations that we may have with BEx Analyzer's front end.

    Let’s start by looking at the API which comprises of four modules and one class:

    · Common: Usable methods and functions that execute BEx Analyzer’s features.

    · ConnectionHandling: A set of functions used for handling connections.

    · xBExapi: Error handling and drill down state information.

    · xBExPrec: Status information.

    · BExEventHandler: Event handlers to work with Excel’s events.

    clip_image001

     

    To use this interface you first need to create an instance of the class. This is done by executing BEx Analyzer’s add-in, which returns an object of type BExApplication.

    Set BEx = Application.Run("BExAnalyzer.xla!GetBEx")

    Two of the most useful methods provided are BExGet and BExSet, used to read and write data to InfoProviders. To use these methods you are required to pass the address of the data you wish to return/alter as parameters. Below is the header information of these methods to show how these are formed:

    BexGetData(iDataProv As String, ParamArray iParam() As Variant)

    BexSetData(iValue As Double, iDataProv As String, ParamArray iParam() As Variant)

     

    Another useful feature of the API to note is how BEx Messages can be accessed and used. These contain the information that we can see in the status bar of the worksheet and the more detailed information shown if you double click the status message. The API exposes these messages through the Messages function. An example of how these messages can be used is to test whether data was saved back to the InfoProviders. This can be accomplished with the following code:

    Dim obBExMessage As BExMessage

    Dim sTextToFind as String

    sTextToFind = “data was saved”

    For Each obBExMessage In BEx.Messages

    If InStr(1, LCase(obBExMessage.Text), LCase(sTextToFind)) > 0 Then

    bDataSaved = True

    Exit For

    End If

    Next obBExMessage

    This is just a snippet of the automation you can provide using BEx Analyzer’s API via VBA. The best way to learn what else can be achieved would be to read through the API’s Common Module functions and methods.

     

  • Converting a Standard InfoCube to a Real-Time InfoCube while Maintaining Data

    There could be a couple of reasons why you might wish to convert your Standard InfoCube to a Real-Time InfoCube:

    - your user's needs may change and you require the data to be kept closer to real-time, or

    - the amount of data you are loading increases and you're finding the InfoCube's write performance is simply too slow.

    The Real-Time InfoCube supports parallel write access making it much faster compared to the Standard InfoCube. This can be combined with a daemon service that is scheduled to check the InfoSource for any changes, if found the delta is quickly updated.

    How to convert:

    1. Go to the ABAP Editor (SE80) and select Edit Object

    clip_image002

    2. Execute the program 'sap_convert_normal_trans'

    clip_image002[4]

    3. Enter the InfoCube's name and decide the direction of the conversion.

    clip_image002[6]

    Once the InfoCube has been converted it will be ready and any data you previously had in the InfoCube will remain intact.

    Technorati Tags:
    Technorati Tags:
    Technorati Tags: