3

I have an easy to use function module to create an ALV grid for almost any type of table, especially without a DDIC type. Editing is supported as well.

Basically it creates a field catalog by RTTI and instantiates the standard CL_GUI_ALV_GRID class in a fixed internal Dynpro.

The problem: The F4 search help is not working when the column is not part of a DDIC structure or transparent table. The reason is that the standard ALV overwrites the field REF_FIELD in the field catalog if it is empty.

* Excerpt from LVC_FCAT_COMPLETE_NEW in LSLVCF02
if not <ls_fcat>-ref_table is initial
   and <ls_fcat>-ref_field is initial
   and r_fcat_complete eq abap_false.
  <ls_fcat>-ref_field = <ls_fcat>-fieldname.
endif.

But to get the search help for a data element using the function module DD_SHLP_GET_HELPMETHOD (internally used by CL_GUI_ALV_GRID in method F4) TABNAME must contain the data element name and FIELDNAME must be initial.

If I clear REF_FIELD in the debugger after it has been assigned everything works as expected.

I know that the documentation of the field catalog includes the feature to leave out the REF_FIELD name if it is identical to FIELDNAME. But the automatism does not make sense for non DDIC structures.

Any idea how to get rid of this behavior without a modification? Preferably without writing my own F4 invocation routine for each type of search help in the (undocumented) ONF4 event handler.

Unfortunately it is almost impossible to provide a working test case because of the required Dynpro stuff. But I can provide the ABAP part. It assumes the existence of Dynpro 500 with a container control named CC_ALV.

" test table
TYPES: BEGIN OF t_test,
         date  TYPE dats,
         time  TYPE time,
         werks TYPE werks_d,
       END OF t_test.
DATA it_data TYPE STANDARD TABLE OF t_test.
APPEND VALUE #( date = '20180102' time = '123059' werks = '2020' ) TO it_data.

" field catalog
DATA it_fc TYPE lvc_t_fcat.
APPEND VALUE #( fieldname = 'DATE' f4availabl = abap_true ref_table = 'DATS' ) TO it_fc.
APPEND VALUE #( fieldname = 'TIME' f4availabl = abap_true ref_table = 'TIMS' ) TO it_fc.
APPEND VALUE #( fieldname = 'WERKS' f4availabl = abap_true ref_table = 'WERKS_D' ) TO it_fc.

" show ALV
DATA: r_alv       TYPE REF TO cl_gui_alv_grid.
CREATE OBJECT r_parent
  EXPORTING
    container_name = 'CC_ALV'.
CREATE OBJECT r_alv
  EXPORTING
    i_parent = r_parent.
r_alv->set_table_for_first_display(
  EXPORTING is_layout = VALUE #( edit = abap_true )
  CHANGING  it_fieldcatalog = it_fc
            it_outtab = it_data ).
CALL SCREEN 500.
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
Marcel
  • 1,688
  • 1
  • 14
  • 25

3 Answers3

1

I found a solution, although it is somewhat ugly. Better solution are still welcome.

CLASS lcl_alv_util DEFINITION FINAL CREATE PRIVATE.
  PUBLIC SECTION.
    INTERFACES if_alv_rm_grid_friend.
    CLASS-METHODS enable_f4_in_fcat
      IMPORTING r_alv TYPE REF TO cl_gui_alv_grid.
ENDCLASS.
CLASS lcl_alv_util IMPLEMENTATION.
  METHOD enable_f4_in_fcat.
    DATA wa_fc TYPE lvc_s_fcat.
    MODIFY r_alv->m_cl_variant->mt_fieldcatalog FROM wa_fc TRANSPORTING ref_field
      WHERE tabname IS INITIAL AND ref_field IS NOT INITIAL AND ref_table IS NOT INITIAL.
  ENDMETHOD.
ENDCLASS.

The method lcl_alv_util=>enable_f4_in_fcat has to be called after set_table_for_first_display and before the Dynpro is invoked by CALL SCREEN. Furthermore you need to ensure that the field TABNAME is filled for all members of a DDIC structures because this is used to distinguish between DDIC based and not DDIC based structure fields.

Alternatively you might call enable_f4_in_fcat only if you have a local line type. But this will not cover the case when some of the columns are part of DDIC structure where the standard implementation actually works, i.e. when the local type refers to a DDIC structure by INCLUDE TYPE or nested.

In fact I simply clear REF_FIELD if there is no TABNAME supplied. Because REF_FIELD is only read when F4 is actually pressed, doing this after set_table_for_first_display is sufficient. But the hack with if_alv_rm_grid_friend to access the private field m_cl_variant has some bad aftertaste.

Marcel
  • 1,688
  • 1
  • 14
  • 25
  • The problem remains, since as soon as you change something in that field and trigger the next `PAI`, the field check `FORMAL_FIELD_CHECK_DDIC( )` of `CL_GUI_ALV_GRID` will throw an error like `Field MATNR- is not in ABAP Dictionary`. If you want an `F4` help based on the data element, I see no other way than registering on the `ONF4` event and implement an event handler calling `F4IF_DETERMINE_SEARCHHELP` yourself for the data element (`ROLLNAME`) and then `F4IF_START_VALUE_REQUEST`. I went this way (still not nice, but at least it works). – rplantiko Mar 17 '21 at 09:45
1

What concerns the code sample you provided, the ref fields are specified incorrectly and thus it's non-functional. This way it works like a charm:

APPEND VALUE #( fieldname = 'DATE' f4availabl = abap_true ref_table = 'BKPF' ref_field = 'BUDAT' ) TO it_fc.
APPEND VALUE #( fieldname = 'TIME' f4availabl = abap_true ref_table = 'BKPF' ref_field = 'CPUTM' ) TO it_fc.
APPEND VALUE #( fieldname = 'WERKS' f4availabl = abap_true ref_table = 'BSEG' ref_field = 'WERKS') TO it_fc.

What concerns non-DDIC fields, when you declare non-DDIC field based on arbitrary non-DDIC data element and/or on arbitrary domain ALV simply cannot determine what input help to call. See input help call hierarchy.

As I don't see your FM code, I cannot say something more definite. Otherwise give us more illustrative use-case.

Suncatcher
  • 10,355
  • 10
  • 52
  • 90
  • Unfortunately there is **no deterministic way** to get from type `DATS` to `BKPF-BUDAT` nor this relation is unique. You could choose any arbitrary `DATS` filed in any arbitrary DDIC structure witch might have a any non-standard F4 help. So **it is impossible to use this approach in generic code**. The task is to *invoke the F4 help associated with the DDIC data element* nothing else. – Marcel Dec 24 '18 at 09:32
0

You can do this using the command DESCRIBE FIELD HELP-ID to get ref_table and ref_field. Here there's an example.

TYPES: BEGIN OF tp_alv,
        rueck       TYPE afru-rueck,
        rmzhl       TYPE afru-rmzhl,
        vornr       TYPE afru-vornr,
        budat       TYPE afru-budat,
        werks       TYPE afru-werks,
        ltxa1       TYPE afru-ltxa1,
       END OF tp_alv.

DATA: tg_alv  TYPE TABLE OF tp_alv,
      tg_fcat TYPE lvc_t_fcat.

START-OF-SELECTION.

  PERFORM zf_fieldcat.

*&---------------------------------------------------------------------*
*&      Form  ZF_FIELDCAT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM zf_fieldcat .

  DATA: ol_elemdesc     TYPE REF TO cl_abap_elemdescr,
        ol_stdesc       TYPE REF TO cl_abap_structdescr,
        tl_fields       TYPE cl_abap_structdescr=>included_view,
        wl_fields       TYPE LINE OF cl_abap_structdescr=>included_view,
        wl_alv          LIKE LINE OF tg_alv,
        wl_fcat         LIKE LINE OF tg_fcat,
        vl_hlpid        TYPE string.

  FIELD-SYMBOLS: <fl_field>.
*--------------------------------------------------------------------*

  ol_stdesc ?= cl_abap_structdescr=>describe_by_data( wl_alv ).

  tl_fields = ol_stdesc->get_included_view( ).

  LOOP AT tl_fields INTO wl_fields.

    CLEAR: wl_fcat.

    wl_fcat-col_pos   = lines( tg_fcat ) + 1.
    wl_fcat-fieldname = wl_fields-name.

    IF wl_fields-type->kind EQ cl_abap_typedescr=>kind_elem.
      ol_elemdesc ?= wl_fields-type.

      IF ol_elemdesc->is_ddic_type( ) IS NOT INITIAL.
        wl_fcat-rollname  = ol_elemdesc->help_id.
        wl_fcat-edit_mask = ol_elemdesc->edit_mask.

        ASSIGN COMPONENT wl_fcat-fieldname OF STRUCTURE wl_alv TO <fl_field>.

        IF sy-subrc EQ 0.
          DESCRIBE FIELD <fl_field> HELP-ID vl_hlpid.
          SPLIT vl_hlpid AT '-' INTO wl_fcat-ref_table wl_fcat-ref_field.

        ENDIF.

      ELSE.
        wl_fcat-inttype  = wl_fields-type->type_kind.
        wl_fcat-intlen   = wl_fields-type->length.
        wl_fcat-decimals = wl_fields-type->decimals.

      ENDIF.
    ENDIF.

    APPEND wl_fcat TO tg_fcat.

  ENDLOOP.

ENDFORM.                    " ZF_FIELDCAT