Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert

Introduction


When implementing my openSource based RAP Generator I had the requirement that on the object page on item level fields should be read-only based on data that I had entered in the object page on header level.

So on the item level I had a mixture of fields that are read only by default and some that are read only based on the instance features.

So in my behavior definition I had something like this:
field ( features : instance ) MandFieldInstfeat;
field ( mandatory ) MandFieldBdef;

Though on the UI level we find that the fields are marked accordingly as read-only or mandatory based on the values being entered on header level















Header object page Item object page




"1" is entered on header level

--> the field MandFieldInstfeat is read-only.
"2" is entered on header level



--> the field MandFieldInstfeat is mandatory.

There is no out of the box support (so far) in RAP to validate the input of the user.

Code to control instance features


The method get_instance_features( ) is used by the RAP framework to determine which fields in the object page have to be set read-only or mandatory for each instance.
  METHOD get_instance_features.

" get the root node(s). In a Fiori Elements UI this
" will be just one entry. But when being called via EML or
" as an API several instances of HeaderMand can be requested

READ ENTITIES OF ZI_HEADERMand IN LOCAL MODE
ENTITY iTEMmAND BY \_HeaderMand
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(HeaderMands).

" Read all associated child nodes and set the field MandFieldInstfeat
" to either read-only or mandatory based on the value of the field Mynumber
" in the root node

LOOP AT HeaderMands INTO DATA(HeaderMand).
READ ENTITIES OF ZI_HEADERMand IN LOCAL MODE
ENTITY HeaderMand BY \_ItemMand
ALL FIELDS
WITH VALUE #( ( %tky = HeaderMand-%tky ) )
RESULT DATA(ItemMands).

result = VALUE #( FOR ItemMand IN ItemMands
( %tky = ItemMand-%tky
%field-MandFieldInstfeat = COND #( WHEN HeaderMand-Mynumber = 2
THEN if_abap_behv=>fc-f-mandatory
ELSE if_abap_behv=>fc-f-read_only )
) ).
ENDLOOP.
ENDMETHOD.

 

Code to validate mandatory fields


The tricky thing is that we have to write code that finds out which fields

  1. have been defined as mandatory in the behavior defintion and

  2. have been defined as mandatory based on the features of our instance


and check whether data that has been entered by the user or the caller of the API for these fields.

While static settings as they are defined in the behavior definition are quite easy to spot it becomes more complicated if the status of a field can change dynamically, for example based on the content of another field of our business object.

GET PERMISSIONS


Whether a field of an entity is mandatory or not have to be retrieved using the statement GET PERMISSIONS.

This is (as I have to admit) not obvious because one would only expect to retrieve authorizations rather than the information whether a field is read-only, or mandatory.

The GET PERMISSIONS statement needs as an input a structure that must be typed with TYPE STRUCTURE FOR PERMISSIONS REQUEST. This structure (here called permission_request) contains a dynamic structure %field that contains the field names of our request. Using RTTI we can retrieve the field names dynamically in the internal table components_permission_request.

The result of the permission request contains instance specific information for each instance which is based on the (features : instance) statement such as:
field ( features : instance ) MandFieldInstfeat;

is stored in an internal table.

The static information which is based on statements such as
field ( mandatory ) MandFieldBdef;

is stored in a structure.

 
 METHOD mandatory_fields_check.

DATA permission_request TYPE STRUCTURE FOR PERMISSIONS REQUEST ZI_ITEMMand.
DATA reported_zi_itemmand_li LIKE LINE OF reported-itemmand.

DATA(description_permission_request) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data_ref( REF #( permission_request-%field ) ) ).
DATA(components_permission_request) = description_permission_request->get_components( ).

LOOP AT components_permission_request INTO DATA(component_permission_request).
permission_request-%field-(component_permission_request-name) = if_abap_behv=>mk-on.
ENDLOOP.

" Get current field values
READ ENTITIES OF ZI_HeaderMand IN LOCAL MODE
ENTITY ItemMand
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(entities).

LOOP AT entities INTO DATA(entity).

GET PERMISSIONS ONLY INSTANCE FEATURES ENTITY ZI_ItemMand
FROM VALUE #( ( itemuuid = entity-ItemUUID ) )
REQUEST permission_request
RESULT DATA(permission_result)
FAILED DATA(failed_permission_result)
REPORTED DATA(reported_permission_result).

LOOP AT components_permission_request INTO component_permission_request.

"permission result for instances (field ( features : instance ) MandFieldInstfeat;) is stored in an internal table.
"So we have to retrieve the information for the current entity
"whereas the global information (field ( mandatory ) MandFieldBdef;) is stored in a structure

IF ( permission_result-instances[ itemuuid = entity-ItemUUID ]-%field-(component_permission_request-name) = if_abap_behv=>fc-f-mandatory OR
permission_result-global-%field-(component_permission_request-name) = if_abap_behv=>fc-f-mandatory ) AND
entity-(component_permission_request-name) IS INITIAL.

APPEND VALUE #( %tky = entity-%tky ) TO failed-itemmand.

"since %element-(component_permission_request-name) = if_abap_behv=>mk-on could not be added using a VALUE statement
"add the value via assigning value to the field of a structure

CLEAR reported_zi_itemmand_li.
reported_zi_itemmand_li-%tky = entity-%tky.
reported_zi_itemmand_li-%element-(component_permission_request-name) = if_abap_behv=>mk-on.
reported_zi_itemmand_li-%msg = new_message( id = '/DMO/CM_RAP_GEN_MSG'
number = 066
severity = if_abap_behv_message=>severity-error
v1 = |{ component_permission_request-name }|
v2 = | with semantic key: { entity-SemanticKey } | ).
APPEND reported_zi_itemmand_li TO reported-itemmand.

ENDIF.
ENDLOOP.

ENDLOOP.

 

RESULT


If the value "2" has been entered on header level and if as a result we have two mandatory fields on item level you will get the following error message if both fields are iniial.


because in the debugger we will find


and we have retrieved the field names as follows


 
6 Comments