ALV Advanced — Layouts, Variants, User Commands, Events, Export

ALV Advanced: Layouts, Variants, User Commands, Events, Export
ABAP Reports Series · Blog 10 of 15

ALV Advanced: Layouts, Variants, User Commands, Events, Export

Intermediate · 25 min read · Needs Blogs 5 and 6

In Blogs 5 and 6 you built a working ALV. Real reports need more: remembered layouts, subtotals, buttons, and clicks that do something. This blog adds all of them to one report. Every snippet here is an optional parameter of REUSE_ALV_GRID_DISPLAY.

1. ALV layout (IS_LAYOUT)

The layout controls how the grid looks and behaves as a whole. It is a structure of type slis_layout_alv.

DATA gs_layout TYPE slis_layout_alv.

gs_layout-zebra             = 'X'.
gs_layout-colwidth_optimize = 'X'.
gs_layout-box_fieldname     = 'SEL'.
FieldEffect
zebraAlternating row shading for easier reading
colwidth_optimizeEach column is as wide as its content
box_fieldnameAdds a selection checkbox column. The named field (a 1-character field of your table) receives 'X' for selected rows.
no_inputThe whole grid is display-only
cell_mergeRepeated values in a column are shown once
detail_popupDouble-click or detail icon shows the row in a popup

Pass it with is_layout = gs_layout. For box_fieldname, add the field to your table type: sel TYPE c LENGTH 1.

2. Variants: saving user layouts

A variant stores a user’s grid settings: column order, hidden columns, widths, sorting and filters. Users save them from the toolbar (Layout > Save) and reload them later.

DATA gs_variant TYPE disvariant.

gs_variant-report = sy-repid.         " which program the variant belongs to
gs_variant-handle = 'MAIN'.           " optional: separates several grids in one program

CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
  EXPORTING
    ...
    i_save     = 'A'
    is_variant = gs_variant
  ...
i_saveWho may save variants
'A'User-specific and global (all users) variants
'U'Only user-specific variants
'X'Only global variants
' 'No saving at all
Where are they stored?

In the table LTDX (with LTDXT for texts). You do not write to it yourself, ALV does.

Both are needed

Without i_save the Save button is missing. Without is_variant-report, ALV cannot find the variants it saved.

3. Sort and subtotals (IT_SORT)

Presets a sort order when the grid opens. With subtot you get a subtotal every time the value changes.

DATA: gt_sort TYPE slis_t_sortinfo_alv,
      gs_sort TYPE slis_sortinfo_alv.

gs_sort-spos      = 1.            " priority
gs_sort-fieldname = 'VBTYP'.
gs_sort-tabname   = 'GT_VBAK'.
gs_sort-up        = 'X'.          " ascending
gs_sort-subtot    = 'X'.          " subtotal on every change
APPEND gs_sort TO gt_sort.
CLEAR gs_sort.

gs_sort-spos      = 2.
gs_sort-fieldname = 'ERDAT'.
gs_sort-tabname   = 'GT_VBAK'.
gs_sort-down      = 'X'.          " descending
APPEND gs_sort TO gt_sort.
  • Pass with it_sort = gt_sort.
  • Subtotals need a numeric column with do_sum = 'X' in the field catalog (Blog 6).
  • Amounts in different currencies are totalled separately, because the catalog has cfieldname.

4. Filter (IT_FILTER)

A preset filter hides rows when the grid opens. The user can still remove it in the toolbar.

DATA: gt_filter TYPE slis_t_filter_alv,
      gs_filter TYPE slis_filter_alv.

gs_filter-tabname    = 'GT_VBAK'.
gs_filter-fieldname  = 'VBTYP'.
gs_filter-sign0      = 'I'.
gs_filter-optio      = 'EQ'.
gs_filter-valuf_int  = 'C'.        " show only category C
APPEND gs_filter TO gt_filter.

Pass with it_filter = gt_filter.

Check the structure in your system

Field names of SLIS_FILTER_ALV are worth confirming in SE11. In many cases the better design is to filter in the WHERE clause, so unwanted rows are never read at all.

5. ALV events and callbacks

ALV can call your program when something happens. You register a callback by giving ALV the name of a form in your program.

ParameterForm is called whenTypical use
i_callback_top_of_pageThe header is drawnTitles and selection info (Blog 6)
i_callback_pf_status_setThe toolbar is builtCustom buttons
i_callback_user_commandThe user clicks a button or double-clicksActions
i_callback_html_top_of_pageA rich HTML header is drawnLogos, formatted headers
Older style: IT_EVENTS

Older programs get a list of all possible events with REUSE_ALV_EVENTS_GET, fill the form name for each, and pass it as it_events. The i_callback_* parameters do the same for the common events with less code. You will meet both.

6. Custom toolbar buttons

Adding your own button takes five steps.

  1. Open SE41 (Menu Painter). Choose program SAPLKKBL, status STANDARD, and click Copy status.
  2. Copy it to your own program with the name ZSTANDARD.
  3. In your copy, add a button in the application toolbar with function code ZREFR and text Refresh. Activate.
  4. Set i_callback_pf_status_set = 'SET_PF_STATUS', with a form that sets your status.
  5. Set i_callback_user_command = 'HANDLE_USER_COMMAND', with a form that reacts to your function code.
FORM set_pf_status USING rt_extab TYPE slis_t_extab.
  SET PF-STATUS 'ZSTANDARD' EXCLUDING rt_extab.
ENDFORM.

FORM handle_user_command USING pv_ucomm    TYPE sy-ucomm
                                ps_selfield TYPE slis_selfield.
  CASE pv_ucomm.
    WHEN 'ZREFR'.
      PERFORM get_data.
      ps_selfield-refresh = 'X'.     " redraw the grid with new data
    WHEN '&IC1'.                  " double-click on a row
      " ps_selfield-tabindex = row, ps_selfield-fieldname = column
  ENDCASE.
ENDFORM.
ps_selfield fieldContent
tabindexRow number in your output table
fieldnameColumn that was clicked
valueContent of the clicked cell
refreshSet to 'X' to redraw the grid after your action
row_stable / col_stableSet to 'X' so the grid keeps its scroll position on refresh

This is the ALV version of the double-click from Blogs 8 and 9, and it needs no offsets and no GET CURSOR.

7. Editable cells

To let users type in a column, set edit in its field catalog row.

ls_fcat-fieldname = 'ERNAM'.
ls_fcat-edit      = 'X'.         " this column is editable

" In a user command: first pull the typed values into your table
DATA lo_grid TYPE REF TO cl_gui_alv_grid.
CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'
  IMPORTING e_grid = lo_grid.
IF lo_grid IS BOUND.
  lo_grid->check_changed_data( ).
ENDIF.
  • Editing needs the grid display (REUSE_ALV_GRID_DISPLAY), not the list display.
  • Without check_changed_data( ), your table can still hold the old values when a button is pressed.
  • For validation per cell and rich editing, move to CL_GUI_ALV_GRID. Editing is the main reason to leave the function module.

8. Export to Excel

The grid toolbar already has Export > Spreadsheet and Local file. Users can export without any code from you.

When the program must create the file itself (for example to attach it to an email), use CL_SALV_TABLE, which can produce the Excel data directly:

" Sketch: Blog 15 introduces SALV in full
cl_salv_table=>factory(
  IMPORTING r_salv_table = DATA(lo_salv)
  CHANGING  t_table      = gt_vbak ).

DATA(lv_xlsx) = lo_salv->to_xml( xml_type = if_salv_bs_xml=>c_type_xlsx ).
" lv_xlsx is an xstring: save it with a download or attach it to an email
Which one to use?

For a normal report, rely on the built-in export. Write your own only when the file must be created without the user clicking, such as in a background job. Older code uses SAP_CONVERT_TO_XLS_FORMAT, which you can leave alone if it works.

9. GRID vs. LIST

REUSE_ALV_GRID_DISPLAYREUSE_ALV_LIST_DISPLAY
LookModern gridClassical list
Editable cellsYesNo
Toolbar, filter, sortFullLimited
Works in background jobsNo grid, falls back to a listYes
Use forDialog use (default)Spool and background output

10. Complete advanced ALV program

This brings together everything in this blog: layout with zebra and selection boxes, a variant, sort with subtotals, a header, a custom Refresh button, a Show selected button, and a double-click handler.

REPORT zalv_advanced.

TYPES: BEGIN OF ty_vbak,
         sel   TYPE c LENGTH 1,       " selection checkbox
         vbeln TYPE vbak-vbeln,
         erdat TYPE vbak-erdat,
         ernam TYPE vbak-ernam,
         vbtyp TYPE vbak-vbtyp,
         netwr TYPE vbak-netwr,
         waerk TYPE vbak-waerk,
       END OF ty_vbak.

DATA: gt_vbak    TYPE STANDARD TABLE OF ty_vbak WITH DEFAULT KEY,
      gt_fcat    TYPE slis_t_fieldcat_alv,
      gt_sort    TYPE slis_t_sortinfo_alv,
      gs_layout  TYPE slis_layout_alv,
      gs_variant TYPE disvariant,
      gv_repid   TYPE sy-repid,
      gv_erdat   TYPE vbak-erdat.

SELECT-OPTIONS s_erdat FOR gv_erdat.
PARAMETERS     p_max   TYPE i DEFAULT 500.

INITIALIZATION.
  s_erdat-sign   = 'I'.
  s_erdat-option = 'BT'.
  s_erdat-low    = sy-datum - 30.
  s_erdat-high   = sy-datum.
  APPEND s_erdat.

START-OF-SELECTION.
  PERFORM get_data.

END-OF-SELECTION.
  IF gt_vbak IS NOT INITIAL.
    PERFORM build_fieldcat.
    PERFORM build_layout.
    PERFORM build_sort.
    PERFORM display_alv.
  ENDIF.

*---------------------------------------------------------------------*
FORM get_data.
  SELECT vbeln, erdat, ernam, vbtyp, netwr, waerk
    FROM vbak
    WHERE erdat IN @s_erdat
    ORDER BY erdat DESCENDING, vbeln
    INTO CORRESPONDING FIELDS OF TABLE @gt_vbak
    UP TO @p_max ROWS.

  IF sy-subrc <> 0.
    MESSAGE 'No sales orders found for your selection'
            TYPE 'S' DISPLAY LIKE 'E'.
  ENDIF.
ENDFORM.

*---------------------------------------------------------------------*
FORM add_col USING pv_field TYPE slis_fieldname
                    pv_text  TYPE scrtext_m
                    pv_len   TYPE i.
  DATA ls_fcat TYPE slis_fieldcat_alv.
  ls_fcat-fieldname = pv_field.
  ls_fcat-tabname   = 'GT_VBAK'.
  ls_fcat-col_pos   = lines( gt_fcat ) + 1.
  ls_fcat-seltext_s = pv_text.
  ls_fcat-seltext_m = pv_text.
  ls_fcat-seltext_l = pv_text.
  ls_fcat-outputlen = pv_len.
  APPEND ls_fcat TO gt_fcat.
ENDFORM.

FORM build_fieldcat.
  DATA ls_fcat TYPE slis_fieldcat_alv.
  CLEAR gt_fcat.

  PERFORM add_col USING 'VBELN' 'Sales Doc.' 12.
  PERFORM add_col USING 'ERDAT' 'Created on' 12.
  PERFORM add_col USING 'ERNAM' 'Created by' 12.
  PERFORM add_col USING 'VBTYP' 'Cat.'       5.

  ls_fcat-fieldname  = 'NETWR'.
  ls_fcat-tabname    = 'GT_VBAK'.
  ls_fcat-col_pos    = lines( gt_fcat ) + 1.
  ls_fcat-seltext_s  = 'Net value'.
  ls_fcat-seltext_m  = 'Net value'.
  ls_fcat-seltext_l  = 'Net value'.
  ls_fcat-outputlen  = 16.
  ls_fcat-cfieldname = 'WAERK'.
  ls_fcat-do_sum     = 'X'.
  APPEND ls_fcat TO gt_fcat.

  PERFORM add_col USING 'WAERK' 'Currency' 8.
ENDFORM.

FORM build_layout.
  gs_layout-zebra             = 'X'.
  gs_layout-colwidth_optimize = 'X'.
  gs_layout-box_fieldname     = 'SEL'.
ENDFORM.

FORM build_sort.
  DATA ls_sort TYPE slis_sortinfo_alv.
  CLEAR gt_sort.

  ls_sort-spos      = 1.
  ls_sort-fieldname = 'VBTYP'.
  ls_sort-tabname   = 'GT_VBAK'.
  ls_sort-up        = 'X'.
  ls_sort-subtot    = 'X'.
  APPEND ls_sort TO gt_sort.
  CLEAR ls_sort.

  ls_sort-spos      = 2.
  ls_sort-fieldname = 'ERDAT'.
  ls_sort-tabname   = 'GT_VBAK'.
  ls_sort-down      = 'X'.
  APPEND ls_sort TO gt_sort.
ENDFORM.

*---------------------------------------------------------------------*
FORM display_alv.
  gv_repid          = sy-repid.
  gs_variant-report = sy-repid.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      i_callback_program       = gv_repid
      i_callback_top_of_page   = 'ALV_TOP_OF_PAGE'
      i_callback_pf_status_set = 'SET_PF_STATUS'
      i_callback_user_command  = 'HANDLE_USER_COMMAND'
      is_layout                = gs_layout
      it_fieldcat              = gt_fcat
      it_sort                  = gt_sort
      i_save                   = 'A'
      is_variant               = gs_variant
    TABLES
      t_outtab                 = gt_vbak
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

  IF sy-subrc <> 0.
    MESSAGE 'ALV could not be displayed' TYPE 'S' DISPLAY LIKE 'E'.
  ENDIF.
ENDFORM.

*---------------------------------------------------------------------*
* Callbacks
*---------------------------------------------------------------------*
FORM alv_top_of_page.
  DATA: lt_header TYPE slis_t_listheader,
        ls_header TYPE slis_listheader.

  ls_header-typ  = 'H'.
  ls_header-info = 'Sales Orders: Advanced ALV'.
  APPEND ls_header TO lt_header.
  CLEAR ls_header.

  ls_header-typ  = 'S'.
  ls_header-key  = 'Records:'.
  ls_header-info = |{ lines( gt_vbak ) }|.
  APPEND ls_header TO lt_header.

  CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE'
    EXPORTING it_list_commentary = lt_header.
ENDFORM.

FORM set_pf_status USING rt_extab TYPE slis_t_extab.
  SET PF-STATUS 'ZSTANDARD' EXCLUDING rt_extab.
ENDFORM.

FORM handle_user_command USING pv_ucomm    TYPE sy-ucomm
                                ps_selfield TYPE slis_selfield.
  DATA lv_msg TYPE string.

  CASE pv_ucomm.

    WHEN 'ZREFR'.                      " custom Refresh button
      PERFORM get_data.
      ps_selfield-refresh    = 'X'.
      ps_selfield-row_stable = 'X'.
      ps_selfield-col_stable = 'X'.

    WHEN 'ZSHOW'.                      " custom Show selected button
      DATA(lv_count) = REDUCE i( INIT n = 0
                               FOR ls IN gt_vbak WHERE ( sel = 'X' )
                               NEXT n = n + 1 ).
      lv_msg = |{ lv_count } row(s) selected|.
      MESSAGE lv_msg TYPE 'I'.

    WHEN '&IC1'.                       " double-click
      READ TABLE gt_vbak INTO DATA(ls_row) INDEX ps_selfield-tabindex.
      IF sy-subrc = 0.
        lv_msg = |Order { ls_row-vbeln } created by { ls_row-ernam }|.
        MESSAGE lv_msg TYPE 'I'.
      ENDIF.

  ENDCASE.
ENDFORM.
Before you run it
  • Create status ZSTANDARD in SE41 by copying STANDARD from SAPLKKBL (section 6).
  • Add two buttons to its toolbar: ZREFR (Refresh) and ZSHOW (Show selected). Activate the status.
  • Tick some row boxes, press Show selected, then double-click a row.
  • Change the column order, then Layout > Save. Run the report again and load your layout.

11. Try it yourself

  • Turn off zebra and compare readability.
  • Set i_save = 'U', save a layout, and load it from another run.
  • Add a third sort level on ERNAM and watch the subtotals.
  • Add a third button, ZEMAIL, that only shows a message (no real email yet).
  • Make the column ERNAM editable and confirm that the changed value is in the table after pressing Show selected.

12. Common mistakes

  • i_save not set: users cannot save variants.
  • is_variant-report not set: saved variants cannot be found.
  • Wrong tabname in sort or filter: it is ignored. Use the output table name in capitals.
  • Forgetting i_callback_user_command: clicking a button does nothing.
  • refresh not set: the grid still shows old data after your change.
  • Status copied from the wrong place: the toolbar loses standard buttons. Copy STANDARD from SAPLKKBL.
  • Callback form missing or misspelled: ALV raises an error or ignores it. The form must be in the same program.
  • Editable cells without check_changed_data( ): typed values are not yet in your table.

Up next: Blog 11

Report Modularization. Your report is getting long. Learn to split it into FORM routines, function modules, includes, and local classes.

ABAP Reports: Zero to Hero · Blog 10 of 15
WhatsApp WhatsApp us
Call Now Button