Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

OO SALV cl_salv_table - How to count number of records displayed?

Former Member

I have an ALV report using the cl_salv_table class.

In the top of list (method set_top_of_list ) I want to display the number of records displayed.

The number of records (or number of sales orders lines being display) will change as the user uses the ALV filters.

Using the event handler for after_salv_function I can trigger the refresh of the header. BUT how to I get access to the data that is being displayed in order to determine the row count?

1 ACCEPTED SOLUTION

naimesh_patel
Active Contributor

Alan,

When user applies the Filters, ALV framework only determines which data is up for display in the "REFRESH".

After Filters, it calls the method SOFT_REFRESH_TABLE_DISPLAY to refreshes the Display and apply the filters. Within this method, it calls the method SET_DATA_TABLE to get the required data in the ALV output format. This method actually, determines what goes on the screen in which order. It sets the values in the MT_DATA attribute which is protected to CL_GUI_ALV_GRID.

So, it doesn't leave us much of a choice:

In the event handler of the event AFTER_SALV_FUNCTION of class CL_SALV_EVENTS_TABLE, you can get access to the filter object by calling method GET_FILTERS. Once you have filters, you need to get access to filter on each column. Once you have the access all filter ranges, you can filter the data and determine the number of records. Something similar may help you.


  METHOD on_after_events.
    DATA: lo_filters TYPE REF TO cl_salv_filters.
    DATA: lo_filter TYPE REF TO cl_salv_filter.
    DATA: lv_filter_val TYPE salv_t_selopt_ref.
    DATA: lo_selopt TYPE REF TO cl_salv_selopt.
    DATA: lr_erdat TYPE RANGE OF vbak-erdat.
    DATA: lwa_erdat LIKE LINE OF lr_erdat.

    DATA: lt_data TYPE ty_t_vbak.

    lt_data = me->t_vbak.
    lo_filters = o_alv->get_filters( ).
    TRY.
        lo_filter = lo_filters->get_filter( 'ERDAT' ).
        lv_filter_val = lo_filter->get( ).

        LOOP AT lv_filter_val INTO lo_selopt.
          lwa_erdat-sign = lo_selopt->get_sign( ).
          lwa_erdat-option = lo_selopt->get_option( ).
          lwa_erdat-low = lo_selopt->get_low( ).
          lwa_erdat-high = lo_selopt->get_high( ).
          APPEND lwa_erdat TO lr_erdat.
        ENDLOOP.
        DELETE lt_data WHERE NOT erdat IN lr_erdat.

      CATCH cx_salv_not_found.
    ENDTRY.

  ENDMETHOD.                    "on_after_events

I am afraid that you need to do it for all columns or find something dynamic which can help you.

I have captured entire working example on my blog at [SALV Show Count of Displayed Rows|http://help-abap.zevolving.com/2011/09/salv-15-show-count-of-displayed-rows/]

Regards,

Naimesh Patel

Edited by: Naimesh Patel on Sep 26, 2011 10:23 PM - Added post link

6 REPLIES 6

Clemenss
Active Contributor
0 Kudos

Hi Alan,

really remarkable question.

In the good old days of function REUSE_ALV_GRID_DISPLAY we had an info button that shows a popup with number of rows and number of filtered out rows - allowing the user to subtract filtered from total and knowing the displayed count. That was lousy enough.

Starting with GUI_ALV_GRID they put the common ALV help behind the info button - very useful

OK, I checked the code:

CALL FUNCTION 'K_KKB_DATACOUNT_TABLE_GET'
      EXPORTING
           I_PRINT           = ' '
           I_LISTTYPE        = GT_STACK-LISTTYPE
           IS_LAYOUT         = GT_STACK-IS_LAYOUT
           IS_KEYINFO        = GT_STACK-IS_KEYINFO
           IT_FIELDCAT       = GT_STACK-IT_FIELDCAT
           IT_FILTERED       = GT_STACK-T_SFINFO
           IT_FILTERED_SLAVE = GT_STACK2-T_SFINFO_SLAVE
           IT_SUBTOTALS      = GT_STACK2-T_SFSAVE
      IMPORTING
           ET_FIELDCAT       = GT_INFO_COUNTTAB_FIELDCAT[]
      TABLES
           T_OUTTAB          = <LT_OUTTAB>
           T_OUTTAB_SLAVE    = <LT_OUTTAB_SLAVE>
           T_COUNTTAB        = GT_INFO_COUNTTAB_OUTTAB
      EXCEPTIONS
           OTHERS            = 0.

will put the results to table T_COUNTTAB . I_LISTTYPE will be 'S' for simple list, the other parameters you must fetch them using some of the many static public methods of class CL_SALV_CONTROLLER_METADATA.

I did not try it yet but I'm convinced it works.

If you are successful, please let me know. Thanks.

Regards

Clemens

Former Member
0 Kudos

Hi Clemens

That was a useful pointer and I've investigated using it but its not the solution.

From the inevstigations the inbound strictures (T_SFINFO and SFINFO_SLAVE) contain tne index if the outout list rows that have been filtered so in the function module it is basically a simple nuber of the rows in the output table less number of rows filtered.

IT_FILTERED = GT_STACK-T_SFINFO

IT_FILTERED_SLAVE = GT_STACK2-T_SFINFO_SLAVE

In the OO classes I cannot find an equivalent - either the count of the rows effected by the filter being applied or the index of the rows that have been filltered.

The filter class intance in CL_SALV_CONTROLLER_METADATA.contains details of the colmns filtered rather than the attributes of the data filtered.


CALL FUNCTION 'K_KKB_DATACOUNT_TABLE_GET'		
      EXPORTING		
           I_PRINT           = ' '		
           I_LISTTYPE        = GT_STACK-LISTTYPE                                Constant = S
           IS_LAYOUT         = GT_STACK-IS_LAYOUT	                      Type KKBLO_LAYOUT I(move corresp)                                                                                
CL_SALV_CONTROLLER_METADATA=>GET_SLIS_LAYOUT                                                                                
(S_LAYOUT - SLIS_LAYOUT_ALV)
           IS_KEYINFO        = GT_STACK-IS_KEYINFO	                      Type KKBLO_KEYINFO (master slave to header item)                                                                                GET_SLIS_KEYINFO (S_KEYINFO - SLIS_KEYINFO_ALV)
           IT_FIELDCAT       = GT_STACK-IT_FIELDCAT	                      Table of type KKBLO_FIELDCAT (move corres)                                                                                SET_SLIS_FIELDCATALOG (T_FIELDCATALOG -                                                                                SLIS_T_FIELDCAT_ALV)
           IT_FILTERED       = GT_STACK-T_SFINFO		
           IT_FILTERED_SLAVE = GT_STACK2-T_SFINFO_SLAVE		
           IT_SUBTOTALS      = GT_STACK2-T_SFSAVE		
      IMPORTING		
           ET_FIELDCAT       = GT_INFO_COUNTTAB_FIELDCAT[]		
      TABLES		
           T_OUTTAB          = <LT_OUTTAB>		
           T_OUTTAB_SLAVE    = <LT_OUTTAB_SLAVE>		
           T_COUNTTAB        = GT_INFO_COUNTTAB_OUTTAB		
      EXCEPTIONS		
           OTHERS            = 0.		

Still looking...

Alan

Edited by: Alan Kelly on Sep 26, 2011 4:07 PM

Edited by: Alan Kelly on Sep 26, 2011 5:22 PM

Former Member
0 Kudos

Hi,

Probably a "dirty" solution but you can setup a dynamic condition based on your filters objects. Then a LOOP on your internal table could give the remaining lines counter...

Well, just trying..

Kr,

m.

naimesh_patel
Active Contributor

Alan,

When user applies the Filters, ALV framework only determines which data is up for display in the "REFRESH".

After Filters, it calls the method SOFT_REFRESH_TABLE_DISPLAY to refreshes the Display and apply the filters. Within this method, it calls the method SET_DATA_TABLE to get the required data in the ALV output format. This method actually, determines what goes on the screen in which order. It sets the values in the MT_DATA attribute which is protected to CL_GUI_ALV_GRID.

So, it doesn't leave us much of a choice:

In the event handler of the event AFTER_SALV_FUNCTION of class CL_SALV_EVENTS_TABLE, you can get access to the filter object by calling method GET_FILTERS. Once you have filters, you need to get access to filter on each column. Once you have the access all filter ranges, you can filter the data and determine the number of records. Something similar may help you.


  METHOD on_after_events.
    DATA: lo_filters TYPE REF TO cl_salv_filters.
    DATA: lo_filter TYPE REF TO cl_salv_filter.
    DATA: lv_filter_val TYPE salv_t_selopt_ref.
    DATA: lo_selopt TYPE REF TO cl_salv_selopt.
    DATA: lr_erdat TYPE RANGE OF vbak-erdat.
    DATA: lwa_erdat LIKE LINE OF lr_erdat.

    DATA: lt_data TYPE ty_t_vbak.

    lt_data = me->t_vbak.
    lo_filters = o_alv->get_filters( ).
    TRY.
        lo_filter = lo_filters->get_filter( 'ERDAT' ).
        lv_filter_val = lo_filter->get( ).

        LOOP AT lv_filter_val INTO lo_selopt.
          lwa_erdat-sign = lo_selopt->get_sign( ).
          lwa_erdat-option = lo_selopt->get_option( ).
          lwa_erdat-low = lo_selopt->get_low( ).
          lwa_erdat-high = lo_selopt->get_high( ).
          APPEND lwa_erdat TO lr_erdat.
        ENDLOOP.
        DELETE lt_data WHERE NOT erdat IN lr_erdat.

      CATCH cx_salv_not_found.
    ENDTRY.

  ENDMETHOD.                    "on_after_events

I am afraid that you need to do it for all columns or find something dynamic which can help you.

I have captured entire working example on my blog at [SALV Show Count of Displayed Rows|http://help-abap.zevolving.com/2011/09/salv-15-show-count-of-displayed-rows/]

Regards,

Naimesh Patel

Edited by: Naimesh Patel on Sep 26, 2011 10:23 PM - Added post link

0 Kudos

Top of list form implemented using the filters suggested by Naimesh.

Code provided to assist others...



*TOP include*
TYPES:  BEGIN OF ty_listoutput,
*          hotspot    type icon_d,
          vbeln_va   TYPE vbeln_va,
          posnr_va   TYPE posnr_va,
          erdat      TYPE erdat,
          erzet      TYPE erzet,
          ernam      TYPE ernam,
          fullname   TYPE ad_namtext,
          auart      TYPE auart,
.....
          cellcolor  TYPE lvc_t_scol,

          delete     type c,

        END OF ty_listoutput,

        ty_listoutput_tab TYPE STANDARD TABLE OF ty_listoutput.


*method code*
DATA: lv_text TYPE string,
lv_count(5) TYPE c,
lt_listoutput_cpy type ty_listoutput_tab.

DATA: lr_header TYPE REF TO cl_salv_form_header_info.

DATA: lo_cols TYPE REF TO cl_salv_columns.
DATA: lo_cols_tab TYPE salv_t_column_ref.
DATA: lo_col LIKE LINE OF lo_cols_tab.

DATA: lo_filters TYPE REF TO cl_salv_filters.
DATA: lo_filter TYPE REF TO cl_salv_filter.
DATA: lv_filter_val TYPE salv_t_selopt_ref.

DATA: lo_selopt TYPE REF TO cl_salv_selopt.
DATA: lr_range TYPE RANGE OF char80.
DATA: lwa_range LIKE LINE OF lr_range.
data: lv_index type sytabix.

types: BEGIN OF ty_filters,
index type sytabix,
fname type NAME_KOMP,
range LIKE lr_range,
end of ty_filters.
data: lt_filters type sorted TABLE OF ty_filters WITH NON-UNIQUE key index,
ls_filters type ty_filters.

FIELD-SYMBOLS: like line of gt_listoutput,
TYPE ANY.

DATA : lt_comp_details TYPE abap_compdescr_tab,
ls_comp_details TYPE abap_compdescr.

DATA : ref_descr TYPE REF TO cl_abap_structdescr.

* Get the internal table definition for tha list structure as passed to the ALV
ref_descr ?= cl_abap_typedescr=>describe_by_name( u2018TY_LISTOUTPUTu2019 ).
lt_comp_details[] = ref_descr->components[].

* Make a local copy for calculation of the display rows
lt_listoutput_cpy[] = gt_listoutput[].

try.
* Columns and Filters
lo_cols = gr_table->get_columns( ).
lo_cols_tab = lo_cols->get( ).
lo_filters = gr_table->get_filters( ).

loop at lt_listoutput_cpy ASSIGNING .

at first.

loop at lt_comp_details into ls_comp_details.
CLEAR: lr_range, lr_range[].
lv_index = sy-tabix.

TRY.
* Get Filter for the column. No filter will raise exception
lo_filter = lo_filters->get_filter( ls_comp_details-name ).
lv_filter_val = lo_filter->get( ). u201Cexception raised if filter not existing.

LOOP AT lv_filter_val INTO lo_selopt.
lwa_range-sign = lo_selopt->get_sign( ).
lwa_range-option = lo_selopt->get_option( ).
lwa_range-low = lo_selopt->get_low( ).
lwa_range-high = lo_selopt->get_high( ).

ls_filters-fname = ls_comp_details-name.
ls_filters-index = lv_index.
APPEND lwa_range to lr_range.
ls_filters-range = lr_range.
insert ls_filters into table lt_filters.

CLEAR: lwa_range.
ENDLOOP.

CATCH cx_salv_not_found.
endtry.

ENDLOOP.
endat.

loop at lt_filters into ls_filters.
assign COMPONENT ls_filters-index of STRUCTURE to .

if NOT in ls_filters-range.
delete lt_listoutput_cpy. u201D Delete he row if it would not be displated in a filter
exit. u201D At least onefilter applicable
endif.
endloop.

endloop.

catch CX_SY_REF_IS_INITIAL.
endtry.

DESCRIBE TABLE lt_listoutput_cpy lines lv_count.

MOVE: text-m01 TO lv_text.

CONDENSE lv_count NO-GAPS.

REPLACE ALL OCCURRENCES OF u2018&u2019
IN lv_text
WITH lv_count.

CREATE OBJECT lr_header
EXPORTING
text = lv_text.

gr_table->set_top_of_list( lr_header ).

Former Member
0 Kudos

Try to call REUSE_ALV_GRID_LAYOUT_INFO_GET (exporting parameter ET_FILTERED_ENTRIES) or method GET_FILTERED_ENTRIES (of class CL_GUI_ALV_GRID ..instance could be read by function module GET_GLOBALS_FROM_SLVC_FULLSCR).

I works for me now.