Skip to Content
Technical Articles
Author's profile photo Andre Fischer

How to check mandatory fields in RAP


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

    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).
        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 )
                          ) ).


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.


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 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.

    " Get current field values
    ENTITY ItemMand
      WITH CORRESPONDING #( keys )
      RESULT DATA(entities).

    LOOP AT entities INTO DATA(entity).

                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.





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


Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Ramjee Korada
      Ramjee Korada

      Great Job Andre!

      this is another milestone to explore RAP.

      Author's profile photo Robson Soares
      Robson Soares

      Please, could you tell me if there is any way to replace the standard message with a custom message for the mandatory fields?

      The message displays the technical name of the field, which is not good for the end user.


      Author's profile photo Florian Halder
      Florian Halder

      Hi Andre Fischer ,


      first of all, thank you for this blog. I am surprised that this has to be done manually, although the framework knows that the field must be filled. But if I remember correctly, it was the same with Web Dynpro.

      Is it correct that you have created the method "mandatory_fields_check" as validation?

      I have an unmanaged scenario with draft. Actually, I interpret the documentation in such a way that the validations should also be executed there, since I can also define them in the behavior. But the debugger does not stop in my validation methods.

      Or am I wrong and the validation does not work with unmanaged scenario? If yes, do we have to do it in the check_before_save? Unfortunately we have no keys parameter there. I could get them with my buffer class, but I don't think that's so nice.


      Thanks Florian!