ABAP Display field symbol dynamic in alv - abap

I am pasting this program for example but i will never know the type of the table (here vbap and vbak).
My goals is to display my field symbol without knowing the types.
Is it possible ?
Here is my code :
REPORT ZTEST_FME_FOL.
type-pools slis .
FIELD-SYMBOLS : <mytable> TYPE ANY TABLE.
DATA : lv_alv_table TYPE REF TO cl_salv_table,
lv_funct TYPE REF TO cl_salv_functions,
lv_columns TYPE REF TO cl_salv_columns_table,
lv_column TYPE REF TO CL_SALV_COLUMN_table.
SELECT * from vbap INNER JOIN VBAK ON vbap~vbeln = vbak~vbeln UP TO 10 ROWS INTO TABLE <mytable>.
TRY.
cl_salv_table=>factory(
IMPORTING
r_salv_table = lv_alv_table
CHANGING
t_table = <mytable> ).
CATCH cx_salv_msg .
ENDTRY.
lv_funct = lv_alv_table->get_functions( ).
lv_funct->set_all( Abap_True ).
lv_columns = lv_alv_table->get_columns( ).
lv_alv_table->display( ).
Thanks in advance !

Depending on what you 're trying to do there's going to be more validation required than what I've done, but in essence this is what you need.
Using (dynamic) joins may be particularly tricky.
report zevw_test_dynamic_alv.
parameters: p_table type string obligatory.
field-symbols: <gt_table> type standard table.
data: gt_data type ref to data.
start-of-selection.
create data gt_data type table of (p_table).
assign gt_data->* to <gt_table>.
select * from (p_table) up to 10 rows
into table <gt_table>.
perform display_results using <gt_table>. "Your ALV stuff will be in here
You may even have to build the fieldcat manually and then use
call method cl_alv_table_create=>create_dynamic_table
exporting
it_fieldcatalog = gt_fieldcat[]
importing
ep_table = gt_data.
to get the data reference

Related

Display only certain fields in ALV

My table has around 300 columns and I want to display only 10 out of them with specifying which ones. I am working with CL_SALV_TABLE.
Can anybody help me with this problem or give me a hint? Thank you very much in advance!
You need to use the method SET_VISIBLE of the Column object (class CL_SALV_COLUMN). For more information, see the chapter "Set the Visibility of the Column" of page "Columns (General)".
This Minimal reproducible example shows only the columns SPRAS and LAISO from the table T002, all other ones are hidden:
DATA: t002_lines TYPE TABLE OF t002,
salv TYPE REF TO cl_salv_table,
columns TYPE salv_t_column_ref.
FIELD-SYMBOLS <column> TYPE salv_s_column_ref.
SELECT * FROM t002 INTO TABLE t002_lines.
CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = salv
CHANGING
t_table = t002_lines.
LOOP AT salv->get_columns( )->get( ) ASSIGNING <column>.
CASE <column>-columnname.
WHEN 'SPRAS' OR 'LAISO'.
<column>-r_column->set_visible( if_salv_c_bool_sap=>true ).
WHEN OTHERS.
<column>-r_column->set_visible( if_salv_c_bool_sap=>false ).
ENDCASE.
ENDLOOP.
salv->display( ).

Display an internal table?

I have to read some data from a table and display it. The program starts but I don't know how to display any of the data I've selected. I want to put it out as a table.
I honestly don't even know if the following code is correct.
REPORT ZT_THIEMANN_TEST.
types : begin of ts_output,
object_id type CRMD_ORDERADM_H-object_id,
created_by type CRMD_ORDERADM_H-created_by,
end of ts_output,
tt_output type table of ts_output.
PARAMETERS Mel_Nr TYPE CRMD_ORDERADM_H-Object_ID obligatory.
data gt_output type tt_output.
START-OF-SELECTION.
SELECT cm~object_id cm~created_by
from CRMD_ORDERADM_H as cm
into corresponding fields of table gt_output
where cm~object_id like Mel_Nr.
As Sandra said, you can check if your code/the select works by using the debugger.
You can output data different ways, but the easiest is using the class CL_SALV_TABLE. Without adding any additional features (such as a title, toolbar buttons, sorting, hotspots, etc.), the below code is how you can display your data using the oo alv grid.
...
DATA: go_alv TYPE REF TO cl_salv_table,
gx_salv_msg TYPE REF TO cx_salv_msg.
...
TRY.
cl_salv_table=>factory(
IMPORTING
r_salv_table = go_alv
CHANGING
t_table = gt_output ).
CATCH cx_salv_msg INTO gx_salv_msg.
MESSAGE 'error' TYPE 'E'.
ENDTRY.
go_alv->display( ).
If you need a real one-liner, just use ABAP demo output standard class cl_demo_output that can handle any type including internal tables:
SELECT *
FROM scarr
INTO TABLE #DATA(carriers).
cl_demo_output=>display( carriers ).

Creating a range for a field from internal table using RTTS

I want to create a function/custom class method that takes in 2 parameters:
1) IM_ITAB type ANY TABLE
2) IM_COMPONENT type STRING
and returns 1 parameter:
1) EX_RANGE type PIQ_SELOPT_T
So, algorithm is like this:
First of all, we check if the column with a component name at all exists
Then, we check that internal table is not empty.
Then, we loop through internal table assigning component and filling range table. Code is below.
METHODS compose_range_from_itab
IMPORTING
IM_ITAB type ANY TABLE
IM_COMPONENT type STRING
EXPORTING
EX_RANGE type PIQ_SELOPT_T.
...
METHOD compose_range_from_itab.
DATA: lo_obj TYPE REF TO cl_abap_tabledescr,
wa_range TYPE selopt,
lt_range TYPE piq_selopt_t.
FIELD-SYMBOLS: <fs_line> TYPE ANY,
<fs_component> TYPE ANY.
lo_obj ?= cl_abap_typedescr=>describe_by_data( p_data = im_itab ).
READ TABLE lo_obj->key TRANSPORTING NO FIELDS WITH KEY name = im_component.
IF sy-subrc IS INITIAL.
IF LINES( im_itab ) GT 0.
LOOP AT im_itab ASSIGNING <fs_line>.
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO <fs_component>.
wa_range-sign = 'I'.
wa_range-option = 'EQ'.
wa_range-low = <fs_component>.
APPEND wa_range TO lt_range.
ENDLOOP.
SORT lt_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_range COMPARING low.
ex_range[] = lt_range[].
ENDIF.
ENDIF.
ENDMETHOD.
But I want to improve the method further. If the imported internal table has, let's say, 255 columns, then it will take longer to loop through such table. But I need only one column to compose the range.
So I want to get components of internal table, then choose only one component, create a new line type containing only that component, then create internal table with that line type and copy.
Here is the pseudo code corresponding to what I want to achieve:
append corresponding fields of im_itab into new_line_type_internal_table.
How can I "cut out" one component and create a new line type using RTTS?
You are overcomplicating everything, you don't need RTTS for that.
DEFINE make_range.
ex_range = VALUE #( BASE ex_range ( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.
LOOP AT im_itab ASSIGNING FIELD-SYMBOL(<fs_line>).
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_field>).
CHECK sy-subrc = 0 AND <fs_field> IS NOT INITIAL.
make_range <fs_field>.
ENDLOOP.
And yes, as Sandra said, you won't gain any performance with RTTS, just the opposite.
Surprisingly, this variant turned out to be faster:
CLASS-METHODS make_range_variant_2
IMPORTING
sample TYPE table_type
column TYPE string
RETURNING
VALUE(result) TYPE range_type.
METHOD make_range_variant_2.
TYPES:
BEGIN OF narrow_structure_type,
content TYPE char32,
END OF narrow_structure_type.
TYPES narrow_table_type TYPE STANDARD TABLE OF narrow_structure_type WITH EMPTY KEY.
DATA narrow_table TYPE narrow_table_type.
DATA(mapping) =
VALUE cl_abap_corresponding=>mapping_table_value(
( kind = cl_abap_corresponding=>mapping_component srcname = column dstname = 'CONTENT' ) ).
DATA(mover) =
cl_abap_corresponding=>create_with_value(
source = sample
destination = narrow_table
mapping = mapping ).
mover->execute(
EXPORTING
source = sample
CHANGING
destination = narrow_table ).
LOOP AT narrow_table ASSIGNING FIELD-SYMBOL(<row>).
INSERT VALUE #(
sign = 'I'
option = 'EQ'
low = <row>-content )
INTO TABLE result.
ENDLOOP.
ENDMETHOD.
CL_ABAP_CORRESPONDING delegates to a kernel function for the structure-to-structure move, which apparently is faster than the ABAP-native ASSIGN COMPONENT [...] OF STRUCTURE [...] TO FIELD-SYMBOL [...]. The actual loop then seems to be faster because it uses fixed-name assignments.
Maybe somebody could verify.
I would not go for a Macro.
Data:
lr_data type ref to data.
FIELD-SYMBOLS:
<lv_component> TYPE any,
<ls_data> TYPE any.
CREATE DATA lr_data LIKE LINE OF im_itab.
ASSIGN lr_data->* TO <ls_data>.
"Check whether im_component exists
ASSIGN COMPONENT im_component OF STRUCTURE <ls_data> TO <lv_component>.
CHECK sy-subrc EQ 0.
LOOP AT im_itab INTO <ls_data>.
APPEND VALUE #( sign = 'I' option = 'EQ' low = <lv_component> ) TO ex_range.
ENDLOOP.

Create dynamic ABAP internal table

On selection screen, the user needs to insert a table name, and I need to get first 3 fields from that table and display them in an ALV for the output. What I understand from reading tutorials is that I need to call method cl_alv_table_create=>create_dynamic_table, but I don't know how to create the fieldcatalog.
DATA: t_newtable TYPE REF TO data,
t_fldcat TYPE lvc_t_fcat,
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = t_fldcat
IMPORTING
ep_table = t_newtable.
I assume that the table name which user enters is a data dictionary table (like SFLIGHT). If yes, then you can generate the field catalog as follows.
data : it_tabdescr type abap_compdescr_tab,
wa_tabdescr type abap_compdescr.
data : ref_table_descr type ref to cl_abap_structdescr.
ref_table_descr ?= cl_abap_typedescr=>describe_by_name( p_table ).
it_tabdescr[] = ref_table_descr->components[].
loop at it_tabdescr into wa_tabdescr.
clear wa_fieldcat.
wa_fieldcat-fieldname = wa_tabdescr-name .
wa_fieldcat-datatype = wa_tabdescr-type_kind.
wa_fieldcat-inttype = wa_tabdescr-type_kind.
wa_fieldcat-intlen = wa_tabdescr-length.
wa_fieldcat-decimals = wa_tabdescr-decimals.
append wa_fieldcat to it_fieldcat.
endloop.
Here, "p_table" is the selection screen parameter containing the table
name.

How to use REUSE_ALV_FIELDCATALOG_MERGE function module?

I'm trying to use the function module REUSE_ALV_FIELDCATALOG_MERGE to pass the field label in ddic to display in the column header of the alv report.
But, that didn't work.
If I comment the I_STRUCTURE_NAME = 'TY_YNAH_CUS_OBJ_REQ' line, it give me runtime error state
The ABAP program lines are wider than the internal table.
But if I uncomment it ,the program still did not work
REPORT YALV_TEST.
tables sscrfields.
type-pools : slis.
"CREATE STRUCTURE -1
TYPES: BEGIN OF TY_YNAH_CUS_OBJ_REQ,
REQID TYPE YNAH_REQ_ID,
REQUESTOR TYPE YNAH_REQUESTOR,
BUSINESS_OWNER TYPE YNAH_BUS_OWN,
FUNCTIONAL_OWNER TYPE YNAH_FUNC_OWN,
REQNUM TYPE YNAH_SERVICE_REQ_NUM,
PROJECT_ID TYPE YNAH_PRO_ID,
SYSTEM_ID TYPE YNAH_SYS_ID,
FUNCTIONAL_AREA TYPE YNAH_FUNC_AREA,
REQUEST_DATE TYPE YNAH_REQ_DATE,
REQUEST_TIME TYPE YNAH_REQ_TIME,
END OF TY_YNAH_CUS_OBJ_REQ.
"defining internal table -2
DATA: IT_YNAH_CUS_OBJ_REQ type TABLE OF TY_YNAH_CUS_OBJ_REQ
* WA_YNAH_CUS_OBJ_REQ type TY_YNAH_CUS_OBJ_REQ.
DATA: it_fcat TYPE slis_t_fieldcat_alv ,
wa_fcat TYPE slis_fieldcat_alv,
gd_layout TYPE slis_layout_alv.
SELECTION-SCREEN BEGIN OF BLOCK menu WITH FRAME TITLE text-001.
SELECT-OPTIONS: s_proid FOR IT_YNAH_CUS_OBJ_REQ-PROJECT_ID.
PARAMETER p_sysid type TY_YNAH_CUS_OBJ_REQ-SYSTEM_ID.
SELECTION-SCREEN: BEGIN OF LINE,
pushbutton 33(8) BUT user-command search.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK menu.
initialization.
BUT = 'SEARCH'. END-OF-SELECTION.
"execute search function when user click search button
at selection-screen. "after processing user input
case SSCRFIELDS.
when 'SEARCH'.
SSCRFIELDS-UCOMM = 'ONLI'.
endcase.
"fetch data using select-4 START-OF-SELECTION.
SELECT *
FROM YNAH_CUS_OBJ_REQ "Database
INTO CORRESPONDING FIELDS OF TABLE IT_YNAH_CUS_OBJ_REQ "Into internal table
WHERE
PROJECT_ID in s_proid and
SYSTEM_ID eq p_sysid.
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = sy-repid
I_INTERNAL_TABNAME ='TY_YNAH_CUS_OBJ_REQ'
* I_STRUCTURE_NAME = 'TY_YNAH_CUS_OBJ_REQ'
* I_CLIENT_NEVER_DISPLAY = 'X'
I_INCLNAME = sy-repid
* I_BYPASSING_BUFFER = 'X'
* I_BUFFER_ACTIVE = CHANGING CT_FIELDCAT = it_fcat.
* EXCEPTIONS
* INCONSISTENT_INTERFACE = 1
* PROGRAM_ERROR = 2
* OTHERS = 3
* .
IF SY-SUBRC <> 0.
** Implement suitable error handling here
ENDIF.
The REUSE_*ALV* function modules are unsupported. I'd suggest switching to the CL_SALV_* classes. The documentation is better, there are more sample programs (DEMO_SALV_*) and you get support.
You need a dictionary structure if you want to get dictionary-based field descriptions (duh). If you assemble a structure type on the ABAP level using TYPE ... BEGIN OF ... END OF ..., as far as I know, the dictionary types for the individual fields are converted to ABAP types first and only then assembled into a structure type. Anyway, the dictionary reference of the original fields is lost. Instead of defining the structure of the output table in your code, use a dictionary structure.
You have some mistakes you might have not known (SAP is very confusing sometimes
and not transparent with error-messages). I got for you a working example of mine, have a look on it, especially on the comments.
First, data definition:
TYPE-POOLS slis. "import you need for REUSE_ALV_FIELDCATALOG_MERGE
DATA:
lt_fieldcat TYPE slis_t_fieldcat_alv,
BEGIN OF G_IT_MATERIAL occurs 0,
MATNR LIKE MARA-MATNR,
MTART LIKE MARA-MTART,
MAKTX_DE LIKE MAKT-MAKTX,
MAKTX_FR LIKE MAKT-MAKTX,
MAKTX_IT LIKE MAKT-MAKTX,
ERNAM LIKE MARA-ERNAM,
ERSDA LIKE MARA-ERSDA,
LAEDA LIKE MARA-LAEDA,
END OF G_IT_MATERIAL.
It is absolutely necessary that you define your local structure directly with LIKE, otherwise the parser from REUSE_ALV_FIELDCATALOG_MERGE will not find it.
Select your stuff:
SELECT ma~matnr ma~mtart ma~ernam ma~ersda ma~laeda
de~maktx as maktx_de fr~maktx as maktx_fr it~maktx as maktx_it
FROM mara as ma
LEFT JOIN MAKT as de ON de~matnr = ma~matnr AND de~spras = 'DE'
LEFT JOIN MAKT as fr ON fr~matnr = ma~matnr AND fr~spras = 'FR'
LEFT JOIN MAKT as it ON it~matnr = ma~matnr AND it~spras = 'IT'
INTO CORRESPONDING FIELDS OF TABLE g_it_material
WHERE ...
Create a field catalog dynamically:
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = sy-repid
I_INTERNAL_TABNAME = 'G_IT_MATERIAL'
I_INCLNAME = sy-repid
CHANGING
ct_fieldcat = lt_fieldcat
EXCEPTIONS
inconsistent_interface = 1
program_error = 2
OTHERS = 3.
IF sy-subrc <> 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
* WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
Now display the ALV grid:
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
it_fieldcat = lt_fieldcat "you could also give a structure
"i_structure_name = 'ZMM_SMATERIAL' "here instead of the fieldcat
TABLES
t_outtab = g_it_material
EXCEPTIONS
program_error = 1
OTHERS = 2.
Note that the parser also needs a max linesize of 72 chars.
There are several different text components provided by structure slis_fieldcat_alv that are used as column labels. The chosen text depends on the current column width (which itself usually depends on the length of the data displayed). Make sure that you change them all accordingly!
The usual technique is: By passing the I_STRUCTURE_NAME, you get a field catalog corresponding to this DDIC structure (the changing parameter ct_fieldcat). You then modify this internal table according to your needs and pass that modified table to the REUSE_ALV_GRID_DISPLAY.
In cases where I don't distinguish the different-sized text versions, I use the following macros to set all the text fields to the same value. The macros require a local work area ls_fieldcat (with the linetype of ct_fieldcat) and a local string variablelv_text` in order to work.
define set_field.
* Feld &1 für Anzeigefeld &2 den Wert &3 zuweisen
ls_fieldcat-&1 = &3.
modify ct_fieldcat from ls_fieldcat
transporting &1
where fieldname cp '&2'.
end-of-definition.
define set_text_direct.
lv_text = &2.
set_field seltext_s &1 lv_text.
lv_text = &2.
set_field seltext_m &1 lv_text.
lv_text = &2.
set_field seltext_l &1 lv_text.
end-of-definition.