(Note: first I thought about asking this question, but now I think I found the answer myself, so this became a blog!
tl;dr: the answer is CDS + extend view!
🙂
)
[I write this from a partners point of view, but it applies to anyone writing code that might be extended in another system down the line].
I wrote a cool program to display a material list:
(get data is at the very end)
*&---------------------------------------------------------------------*
*& Report zz_jre_select_enahnce
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zz_jre_select_enahnce.
Types: gty_data type mara ,
gty_tab_data TYPE STANDARD TABLE OF gty_data .
*data, solely for select-options.
data: gso_mara type mara.
*Sel-Screen:
SELECTION-SCREEN BEGIN OF BLOCK sel_opt WITH FRAME TITLE text-t01.
SELECT-Options: so_matnr for gso_mara-matnr.
SELECTION-SCREEN END OF BLOCK sel_opt.
SELECTION-SCREEN BEGIN OF BLOCK mode WITH FRAME TITLE text-t02.
PARAMETERS: pa_disp TYPE flag RADIOBUTTON GROUP mode DEFAULT 'X',
pa_proc TYPE flag RADIOBUTTON GROUP mode.
SELECTION-SCREEN END OF BLOCK mode.
CLASS lcl_report DEFINITION.
PUBLIC SECTION.
METHODS: display_data CHANGING ct_data TYPE gty_tab_data.
METHODS: process_data IMPORTING it_data TYPE gty_tab_data.
ENDCLASS. "lcl_report DEFINITION
CLASS lcl_report IMPLEMENTATION.
METHOD process_data.
FIELD-SYMBOLS: <data> LIKE LINE OF it_data.
CHECK it_data IS NOT INITIAL.
LOOP AT it_data ASSIGNING <data>.
*do something
ENDLOOP.
ENDMETHOD. "process_data
METHOD display_data.
DATA: lr_alv TYPE REF TO cl_salv_table.
DATA: lr_functions TYPE REF TO cl_salv_functions_list,
lr_layout TYPE REF TO cl_salv_layout,
ls_key TYPE salv_s_layout_key.
TRY.
CALL METHOD cl_salv_table=>factory
EXPORTING
list_display = if_salv_c_bool_sap=>false
IMPORTING
r_salv_table = lr_alv
CHANGING
t_table = ct_data.
##NO_HANDLER.
CATCH cx_salv_msg .
ENDTRY.
lr_layout = lr_alv->get_layout( ).
ls_key-report = sy-repid.
lr_layout->set_key( ls_key ).
lr_layout->set_default( abap_true ).
lr_layout->set_save_restriction( if_salv_c_layout=>restrict_none ).
lr_functions = lr_alv->get_functions( ).
lr_functions->set_all( abap_true ).
CALL METHOD lr_alv->display.
ENDMETHOD. "display_data
ENDCLASS. "lcl_report IMPLEMENTATION
START-OF-SELECTION.
PERFORM start_of_selection.
FORM start_of_selection.
DATA: lt_data TYPE gty_tab_data,
lo_report TYPE REF TO lcl_report.
*by using a form-routine to get_data we can just use paramters and
*select-options inside.
PERFORM get_data CHANGING lt_data.
check lt_data is not initial.
CREATE OBJECT lo_report.
CASE abap_true.
WHEN pa_disp.
lo_report->display_data( changing ct_data = lt_data ).
WHEN pa_proc.
lo_report->process_data( EXPORTING it_data = lt_data ).
ENDCASE.
ENDFORM. "start_of_selection
FORM get_data CHANGING PT_DATA TYPE gty_tab_data.
select
matnr,
ernam,
ersda
from mara into CORRESPONDING FIELDS OF table @pt_data UP TO 500 ROWS
where matnr in @so_matnr
.
ENDFORM.
But I also want to give customers the chance to enhance it,
adding more fields to the select.
What's the best way to do it?
This would be nice but doesn't work:
FORM get_data_static_list CHANGING PT_DATA TYPE gty_tab_data.
select
matnr,
ernam,
ersda
*[enhancement-spot here would be nice, but is not possibel ]
from mara into CORRESPONDING FIELDS OF table @pt_data UP TO 500 ROWS
where matnr in @so_matnr
.
ENDFORM.
Put the whole select into an
enhancement-section:
FORM get_data_eh_sect CHANGING PT_DATA TYPE gty_tab_data.
ENHANCEMENT-SECTION ZZ_JRE_SELECT_ENAHNCE_SEL1 SPOTS ZZ_JRE_SELECT_ENAHNCE_SEL .
select
matnr,
ernam,
ersda
from mara into CORRESPONDING FIELDS OF table @pt_data UP TO 500 ROWS
where matnr in @so_matnr
.
END-ENHANCEMENT-SECTION.
ENDFORM.
Valid choice, but it gives
more freedom/options then I wanted to give (the whole select can be replaced/altered, not just fields added) . I agree that this can be view an advantage as well.
Build the
field list dynamically and provide an enhancement point to add more fields to it;
FORM get_data_dynamic_list_enhp CHANGING PT_DATA TYPE gty_tab_data.
data lt_fields type table of string.
lt_fields = value #(
( ` MATNR ,`)
( ` ERNAM ,`)
( ` ERSDA `)
).
*ENHACEMENT-Point HERE;
ENHANCEMENT-POINT ZZ_JRE_SELECT_ENAHNCE_SEL2 SPOTS ZZ_JRE_SELECT_ENAHNCE_SEL .
*ADD:
* ,
* [yourFild_1],
*....
*[yourfild_D]
select
(lt_fields)
from mara into CORRESPONDING FIELDS OF table @pt_data UP TO 500 ROWS
where matnr in @so_matnr
.
ENDFORM.
Valid, too; you could not only add to but also remove from the fields list..
But: we
lose all static checks, which I think is a big drawback.
(e.g. misspelling a fieldname will not give a syntax-error (which would be easy to find and solve) but cause trouble at runtime. )
My solution:
Move the field list to a
CDS View and select * from it:
@AbapCatalog.sqlViewName: 'ZZ_MARA1'
@AbapCatalog.compiler.compareFilter : true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Select from MARA for Demo'
define view zz_jre_sel_mara as select from mara {
matnr,
ernam,
ersda
}
FORM get_data_from_cds CHANGING PT_DATA TYPE gty_tab_data.
select
*
from zz_jre_sel_mara into CORRESPONDING FIELDS OF table @pt_data UP TO 500 ROWS
where matnr in @so_matnr
.
ENDFORM.
The CDS-view can be extended with a - well -
extend view:
@AbapCatalog.sqlViewAppendName: 'ZZ_MARA11'
@EndUserText.label: 'Extending zz_jre_sel_mara 1'
extend view zz_jre_sel_mara with zz_jre_sel_mara_ext1 {
mara.meins
// mara.[yy_yourfield_1]
// mara.[yy_yourfield_2]
}
And this it to show it actually works:
-> Indeed, MARA-MEINS is selected together with the other fields!
Ho do you tackle this problem? Do you (have to) care about your field lists being extendable?
best
Joachim