ALV Dinámico explicado paso a paso

Bienvenido!!!
En esta oportunidad voy a explicar paso a paso como crear un reporte de un ALV dinámico... Dinámico?... Si! según la cantidad de columnas que tengamos la presentación de nuestro ALV irá variando e inclusive haremos que los valores de la primera columna sean estáticos, por ende tendrán un nombre que identificará  la información mostrada en cada fila; Iniciemos.


PANTALLA DE SELECCIÓN

El usuario deberá poder ingresar el nro de columnas y el nro de Filas:


OBJETIVO
 Ejemplo 1:
Si el usuario ingresa 5 Columnas y 3 Filas:

 Al ejecutar, el reporte automáticamente debe incrementar el Nro. de columnas, mostrando la data correcta de acuerdo al Nro. de filas también indicado por pantalla.

 Ejemplo 2: 
Si el usuario ingresa 9 columnas y 7 filas:

Al ejecutar el reporte, de forma dinámica actualizará el Nro. de columnas en su catálogo de campos, mostrando la data correcta para la cantidad de filas ingresado en la pantalla de selección:

NOMENCLATURA QUE UTILIZARÉ PARA EL CÓDIGO FUENTE


EXPLICACIÓN DEL CÓDIGO FUENTE
*&----------------------------------------------------------------------------------------* 
*& Report ZAQR049
*&----------------------------------------------------------------------------------------*

*& Título........: Test Alv Dinámico
*& Descripción...: Segun la cantidad de columnas incrementar el catálogo de campos del ALV
*& Autor.........: Alex Mijael Alcántara Quispe
*& Fecha.........: 10 Febrero 2014
*&----------------------------------------------------------------------------------------*

*----------------------------------------------------------------------*
*FIELD-SYMBOLS *
*----------------------------------------------------------------------*

FIELD-SYMBOLS:
<gt_dyntable> TYPE STANDARD TABLE, "Nombre de la tabla interna dinámica
<gs_dyntable>, "Field symbol para crear un área de trabajo
<gv_fldval> TYPE any. "Field Symbol para asignar valores

*----------------------------------------------------------------------*
*ALV's Internal Tables *
*----------------------------------------------------------------------*
DATA:

gt_fieldcat TYPE slis_t_fieldcat_alv, "Lo utilizaremos al momento de invocar al ALV
gt_fcat      TYPE lvc_t_fcat."Lo utilizaremos al momento de crear la tabla dinámica

*----------------------------------------------------------------------*
*ALV's Variables *
*----------------------------------------------------------------------*
DATA:
gv_colno(2)  TYPE n,  "Nro de columna
             gv_flname(5) TYPE c. "Nombre del campo del catálogo

*----------------------------------------------------------------------*
*SELECTION-SCREEN *
*----------------------------------------------------------------------*
PARAMETERS:
pa_cols(5) TYPE c,  "Campo de Texto para ingresar el número de columnas
                              pa_rows(5) TYPE c. "Campo de Texto para ingresar el número de filas

*----------------------------------------------------------------------*
*START-OF-SELECTION                                            *
*----------------------------------------------------------------------*

"Al Ejecutar el reporte se invocarán las siguientes rutinas
PERFORM fill_dynamic_catalog.  "Llena el catálogo de campos de la tabla dinámica
PERFORM crea_dynamic_itable. "Crea la tabla interna dinámica
PERFORM crea_dynamic_warea."Crear el área de trabajo para la tabla interna dinámica
PERFORM fill_itable. "Llena de valores la tabla interna que se visualizará en el ALV
PERFORM display_alv. "Visualiza el ALV

*&---------------------------------------------------------------------*
*& Form FILL_DYNAMIC_CATALOG
*&---------------------------------------------------------------------*
*"Llena el catálogo de campos de la tabla dinámica
*----------------------------------------------------------------------*
FORM fill_dynamic_catalog.
DATA: ls_fcat TYPE lvc_s_fcat. "área de trabajo local para el catálogo de campos

"La primera columna
 ls_fcat-fieldname = 'DESCRIPCION'.
 ls_fcat-datatype = 'CHAR'.
 ls_fcat-intlen = 15.
 APPEND ls_fcat TO gt_fcat.

"Segun el número de columnas ingresado por el usuario en pantalla.
 DO pa_cols TIMES.
  CLEAR ls_fcat.
  MOVE sy-index TO gv_colno.
  CONCATENATE 'COL' gv_colno INTO ls_fcat-fieldname.
  ls_fcat-datatype = 'CHAR'.
  ls_fcat-intlen = 10.
  APPEND ls_fcat TO gt_fcat.
 ENDDO.
ENDFORM. " FILL_DYNAMIC_CATALOG

*&-----------------------------------------------------------------------*
*& Form CREA_DYNAMIC_ITABLE
*&-----------------------------------------------------------------------*
*"Crea la tabla interna dinámica y asignamos a un field-symbol
*&-----------------------------------------------------------------------*
FORM crea_dynamic_itable .
 "Referencia de un Objeto
 DATA lo_newtable TYPE REF TO data. "Para la tabla interna dinámica

 "Invocamos al método 'create_dynamic_table' de la clase cl_alv_table_create
 "Como es una clase estática accedemos directamente desde la clase al método.
   CALL METHOD cl_alv_table_create=>create_dynamic_table
       EXPORTING
            it_fieldcatalog = gt_fcat
       IMPORTING
            ep_table = lo_newtable.

  ASSIGN lo_newtable->* TO <gt_dyntable>.
ENDFORM. " CREA_DYNAMIC_ITABLE 

*&----------------------------------------------------------------------------------------------------*
*& Form CREA_DYNAMIC_WAREA
*&----------------------------------------------------------------------------------------------------*
*"Crear el área de trabajo para la tabla interna dinámica y asignamos a un field-symbol
*&----------------------------------------------------------------------------------------------------*
FORM crea_dynamic_warea.
 "Referencia de un Objeto
 DATA lo_newline TYPE REF TO data. "Para el área de trabajo de la tabla interna dinámica.

 CREATE DATA lo_newline LIKE LINE OF <gt_dyntable>.
 ASSIGN lo_newline->* TO <gs_dyntable>.
ENDFORM. " CREA_DYNAMIC_WAREA

*&-----------------------------------------------------------------------*
*& Form FILL_ITABLE
*&-----------------------------------------------------------------------*
*"Llena de valores la tabla interna que se visualizará en el ALV
*&-----------------------------------------------------------------------*
FORM fill_itable.
 DATA:
  lv_index_row(3) TYPE c, "Nro de fila que se esta tratando
  lv_index_col(3) TYPE c,  "Nro de columna que se esta tratando
  lv_fldval(10) TYPE c.       "Valor que será asignado en dicha celda de la fila y columna

 DO pa_rows TIMES. "Recorremos tantas filas se haya ingresado por pantalla
   lv_index_row = sy-index.

*<gv_fldval> apuntará a la columna DESCRIPCION y por cada fila asignará su valor correspondiente
*Por ejemplo si se tratase de un ALV dinámico que muestra las características de un vehículo sería bueno *que antes se haya definido primero una tabla interna que contega los nombres de cada característica por *ejemplo: COLOR, MODELO, AÑO DE FABRICACIÓN etc. de tal manera que aquí lo que se haría es *hacer un read table a dicha tabla interna y según la fila que se este analizando leeríamos el texto.

   ASSIGN COMPONENT 'DESCRIPCION' OF STRUCTURE <gs_dyntable> TO <gv_fldval>.

   CONCATENATE 'FILA-' lv_index_row INTO lv_fldval.

   CONDENSE lv_fldval NO-GAPS. "NO-GAPS es para eliminar los espacios en blanco entre carácter
   
   <gv_fldval> = lv_fldval.

    DO pa_cols TIMES. "Por cada fila recorremos tantas columnas se haya ingresado por pantalla
      lv_index_col = sy-index.

     MOVE lv_index_col TO gv_colno.
   
     CONCATENATE 'COL' gv_colno INTO gv_flname.
 
     "<gv_fldval> apuntará a la columna COL01, COL02, COL03 y así sucesivamente según la columna que      "se este analizando y ahí se almacenará el nuevo valor correspondiente.
     ASSIGN COMPONENT gv_flname OF STRUCTURE <gs_dyntable> TO <gv_fldval>.

     
     CONCATENATE 'VALOR' lv_index_row '-' lv_index_col INTO lv_fldval.

     CONDENSE lv_fldval NO-GAPS."NO-GAPS es para eliminar los espacios en blanco entre carácter
     <gv_fldval> = lv_fldval.

   ENDDO. "Cierra el Do del recorrido de Columnas por la fila en análisis

  APPEND
<gs_dyntable> TO <gt_dyntable>."Añadimos la línea d valores a nuestra tabla interna dinámica

 ENDDO."Cierra el Do del recorrido de Filas

ENDFORM. " FILL_ITABLE

*&---------------------------------------------------------------------*
*& Form DISPLAY_ALV
*&---------------------------------------------------------------------*
*"Visualiza el ALV
*----------------------------------------------------------------------*
FORM display_alv.

   PERFORM
fill_catalog_alv.

   CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
       EXPORTING
            it_fieldcat = gt_fieldcat
       TABLES
            t_outtab = <gt_dyntable>.

ENDFORM. " DISPLAY_ALV 

*&---------------------------------------------------------------------*
*& Form FILL_CATALOG_ALV
*&---------------------------------------------------------------------*
*LLena el catálogo de campos del ALV a visualizar en Pantalla
*----------------------------------------------------------------------*
FORM fill_catalog_alv .
   DATA: ls_fieldcat TYPE slis_fieldcat_alv.

   ls_fieldcat-fieldname = 'DESCRIPCION'.
   ls_fieldcat-seltext_l = 'Nro de Fila'.
   ls_fieldcat-outputlen = '15'.
   APPEND ls_fieldcat TO gt_fieldcat.

   DO pa_cols TIMES.
     CLEAR ls_fieldcat.
     MOVE sy-index TO gv_colno.
     CONCATENATE 'COL' gv_colno INTO gv_flname.
     ls_fieldcat-fieldname = gv_flname.
     ls_fieldcat-seltext_s = gv_flname.
     ls_fieldcat-outputlen = '10'.
     APPEND ls_fieldcat TO gt_fieldcat.
   ENDDO.

ENDFORM. " FILL_CATALOG_ALV

*FIN CÓDIGO FUENTE

Visualiza y descarga el código fuente haciendo clic aqui

"Nota: Es muy importante que el nombre del catálogo de campos tanto de la tabla dinámica a crear como del ALV a visualizar tengan el mismo nombre en su fieldname, por tanto si agregan un campo más... Tienen que hacerlo en ambos, sino al ejecutar les generará un Dump.

DEBUG AL EJECUTAR EL REPORTE 

Ponemos un Break externo en la línea 50 ya que ahí es donde empieza a invocar las rutinas para el procesamiento de la data y la posterior visualización del ALV.

Ejecutamos el reporte y a modo de ejemplo, en la pantalla ingresamos 3 columnas y 2 filas, ejecutamos (F8)

El Debug se detiene en la línea que hemos puesto el Breakpoint.

Ejecutamos el Break paso a paso (F5) para ver internamente el código fuente de la rutina: fill_dynamic_catalog
Nos  ubicamos en la línea 77, ahí le ponemos un Breakpoint y ejecutamos(F8) automáticamente se detendrá en dicha línea. Veremos que nuestro tabla interna de catálogo de campos para la tabla dinámica tiene la cantidad de columnas que ingresamos en pantalla más una columna que será para la descripción del texto que identificará a cada fila, por eso GT_FCAT tiene 4 registros.
Salimos de la rutina: fill_dynamic_catalog y con F5 ingresamos a la rutina: crea_dynamic_itable


Como vemos en imagen inicialmente lo_newtable es Initial quiere decir que aún no hace referencia a ningún objeto, esto es debido a que aún no hemos invocado al método create_dynamic_table de la clase cl_alv_table_create.

Una vez que le damos Ejecutar (F6) ahora ya tenemos un objeto referenciado, donde LO_NEWTABLE de acuerdo al catálogo de campos de GT_FCAT ahora es una tabla interna con 4 columnas, dicho objeto referenciado LO_NEWTABLE lo asignamos a un field symbol <GT_DYNTABLE>.

 Por ende, ahora <GT_DYNTABLE> apuntará a dicha tabla interna con 4 columnas, como vemos en la siguiente imagen:


Salimos de la rutina: crea_dynamic_itable y con F5 ingresamos a la rutina: crea_dynamic_warea
Como vemos en imagen, LO_NEWLINE es Initial antes de ser creado como una línea de la tabla interna <GT_DYNTABLE>

 Una vez que creamos la data LO_NEWLINE ahora ya es un objeto que hace referencia a una línea de la tabla interna <GT_DYNTABLE>

El objeto referenciado LO_NEWLINE  lo asignamos a un field symbol <GS_DYNTABLE>

 Ahora <GS_DYNTABLE> será nuestra área de trabajo la cual contendrá cada línea de la tabla interna <GT_DYNTABLE> como vemos en la siguiente imagen:

Salimos de la rutina: crea_dynamic_warea y con F5 ingresamos a la rutina: fill_itable donde llenaremos la tabla interna de valores; para este Blog cada celda del ALV contendrá la identificación de VALOR1-1, VALOR1-2, VALOR1-3...etc haciendo referencia a VALOR<FILA>-<COLUMNA>

 En la línea 120 lo que hacemos es asignar el componente 'DESCRIPCION' de nuestra estructura <GS_DYNTABLE> al puntero <GV_FLDVAL>, de manera que el valor que asignamos en <GV_FLDVAL> directamente será el valor que visualizaremos en la columna 'DESCRIPCION', todo esto depende de la fila en análisis.

Si nos encontramos en la fila 1 el valor que pondremos a modo de ejemplo para este Blog será FILA-1 como verá ahí hay un espacio en blanco dentro de la cadena de caracteres que contiene el valor de LV_FLDVAL

Aplicamos CONDENSE lv_fldval NO-GAPS para eliminar los espacios en blanco dentro de una cadena de caracteres.

 Luego ya recorremos tantas columnas hayamos ingresado por pantalla y según el componente COL01, COL02, COL03... que estemos analizando asignaremos dicho componente de la estructura <GS_DYNTABLE> a <GV_FLDVAL> la cual contendrá el nuevo valor correspondiente.

Como vemos el valor de LV_FLDVAL tiene espacios en blanco dentro de la cadena de caracteres.

 Por eso también le aplicamos CONDENSE lv_fldval NO-GAPS para eliminar los espacios en blanco como se logra ver en imagen.

La nueva línea <GS_DYNTABLE> lleno de datos lo añadimos a nuestra tabla interna <GT_DYNTABLE>


Una vez añadida, como vemos en la imagen; automáticamente se incrementa el número de registros y se actualiza los valores de nuestra tabla interna <GT_DYNTABLE> 

 Así sucesivamente iremos llenando de valores todas las columnas para cada fila.
Al finalizar la rutina: FILL_ITABLE, visualizamos nuestra tabla interna <GT_DYNTABLE>  con la data correspondiente para el número de filas y columnas que inicialmente ingresamos por pantalla.

Salimos de la rutina: FILL_ITABLE y con F5 ingresamos a la rutina: DISPLAY_ALV

Antes de ejecutar la función que visualiza el ALV 'REUSE_ALV_GRID_DISPLAY' llenamos el catálogo de campos. 

Algunos podrían decir: ¿Por qué aquí no le pasas la misma tabla interna del catálogo de campos que utilizamos para crear la tabla dinámica...?

La respuesta es simple; el tipo de dato de ambas tablas internas para el catálogo de campos son diferentes.
Recuerdan la definición de las variables que hicimos al inicio?  Bueno aquí les hago recordar:

DATA: gt_fieldcat TYPE slis_t_fieldcat_alv, "Lo utilizamos al invocar para visualizar el ALV
            gt_fcat       TYPE lvc_t_fcat."Lo hemos utilizado para crear la tabla dinámica

Por ende... continuamos y llenamos nuestra tabla interna para catálogo de campos que se visualizará en el ALV, aqui es importante que el FIELDNAME de ambas tablas internas (para crear la tabla dinámica y para visualizar el ALV)  tengan el mismo nombre y la misma cantidad de campos.


 El texto que el usuario visualizará como nombre de la columna en el ALV eso si puede variar; como en este ejemplo donde al FIELDNAME: 'DESCRIPCION' le he puesto 'Nro de Fila' , veamos la siguiente imagen:



Ahora si, con la tabla interna del catálogo de campos y de la tabla interna de salida, estamos listos para ejecutar la función: REUSE_ALV_GRID_DISPLAY la cual nos permitirá visualizar nuestro ALV GRID.

 Ejecutamos el reporte (F8)

Nos vemos en el siguiente Blog ;)
MAGALEX

Comentarios

  1. Muy bueno amigo lo felicito sobre todo por esa explicación tan detallada solo al inicio le falto definir el TYPE-POOLS: slis. para que se pueda ejecutar, Saludos

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Modificando Vista de Actualización SM30

User Exit para VA01 y VA02

Buttons and events in ALV GRID and ALV GRID OO