Esta serie de blogs presenta la Proyecto ABAP2UI5. Es un proyecto de código abierto que lo ayuda a desarrollar aplicaciones UI5 independientes en ABAP puro. Toda la información que necesita para instalar el proyecto se puede encontrar en GitHub y para próximas novedades y mejoras puedes seguir el proyecto en Gorjeo.
Esta es la segunda publicación de blog que se enfoca en la salida de modelos de datos profundos como tablas.
Serie de blogs:
Si está interesado en los antecedentes técnicos, eche un vistazo a esta primera publicación de blog: ABAP2UI5 – Desarrollo de Pantallas de Selección UI5 en ABAP puro
ChatGPT me dio este fragmento cuando pedí una forma de mostrar tablas en ABAP:
TYPES: BEGIN OF t_flight,
carrid TYPE s_carr_id,
connid TYPE s_conn_id,
fldate TYPE s_date,
price TYPE s_price,
END OF t_flight.
DATA: it_flight TYPE STANDARD TABLE OF t_flight.
SELECT carrid connid fldate price FROM sflight INTO TABLE it_flight.
DATA: gr_flight TYPE REF TO cl_gui_alv_grid.
CREATE OBJECT gr_flight
EXPORTING
i_parent = cl_gui_container=>screen0.
gr_flight->set_table_for_first_display(
EXPORTING
i_structure_name="T_FLIGHT"
CHANGING
it_outtab = it_flight ).
Solo alrededor de 25 líneas de ABAP puro y obtienes una interfaz de usuario con una salida de tabla. Eso es muy eficiente, pero cuando luego pedí una forma que no fuera sap-gui o lista para la nube, por supuesto, chatGPT no conocía otra forma que no fuera Fiori Elements y terminó con puro ABAP. ABAP2UI5 intenta llenar este vacío y proporciona una forma no sap-gui y preparada para la nube de generar interfaces de usuario. El código ABAP2UI5 para este ejemplo se ve así:
CLASS z2ui5_cl_app_demo_03 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES: BEGIN OF t_flight,
carrid TYPE s_carr_id,
connid TYPE s_conn_id,
fldate TYPE s_date,
price TYPE s_price,
END OF t_flight.
DATA t_flight TYPE STANDARD TABLE OF t_flight.
ENDCLASS.
CLASS z2ui5_cl_app_demo_03 IMPLEMENTATION.
METHOD z2ui5_if_app~controller.
CASE client->get( )-lifecycle_method.
WHEN client->cs-lifecycle_method-on_init.
SELECT carrid connid fldate price FROM sflight INTO TABLE t_flight.
WHEN client->cs-lifecycle_method-on_rendering.
data(view) = client->factory_view( ).
view->page( )->list( items = view->_bind_one_way( t_tab )
)->standard_list_item(
title="{CARRID}"
description = '{CONNID}'
info = '{FLDATE}' ).
ENDCASE.
ENDMETHOD.
ENDCLASS.
De acuerdo, ABAP2UI5 necesita algunas líneas más, pero el código también está en ABAP OO para eso 😉
La salida ABAP2UI5 de una tabla con barra de herramientas en un contenedor de desplazamiento se ve así:
CLASS z2ui5_cl_app_demo_06 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES:
BEGIN OF ty_row,
title TYPE string,
value TYPE string,
descr TYPE string,
icon TYPE string,
info TYPE string,
checkbox TYPE abap_bool,
END OF ty_row.
DATA t_tab TYPE STANDARD TABLE OF ty_row WITH EMPTY KEY.
ENDCLASS.
CLASS Z2UI5_CL_APP_DEMO_06 IMPLEMENTATION.
METHOD z2ui5_if_app~controller.
CASE client->get( )-lifecycle_method.
WHEN client->cs-lifecycle_method-on_init.
t_tab = REDUCE #( INIT ret = VALUE #( ) FOR n = 1 WHILE n < 101 NEXT ret =
VALUE #( BASE ret ( title="Hans" value="red" info = 'completed' descr="this is a description" checkbox = abap_true ) ) ).
WHEN client->cs-lifecycle_method-on_event.
CASE client->get( )-event.
WHEN 'BUTTON_SORT'.
SORT t_tab BY value.
WHEN 'BUTTON_POST'.
client->display_message_box( 'button post was pressed' ).
ENDCASE.
WHEN client->cs-lifecycle_method-on_rendering.
DATA(view) = client->factory_view( ).
DATA(page) = view->page( title="Example - ZZ2UI5_CL_APP_DEMO_06" nav_button_tap = view->_event_display_id( client->get( )-id_prev_app ) ).
"set table and container
DATA(tab) = page->scroll_container( '70%' )->table( view->_bind_one_way( t_tab ) ).
"set toolbar
tab->header_toolbar( )->overflow_toolbar(
)->title( 'title of the table'
)->toolbar_spacer(
)->button( text="Sort" press = view->_event( 'BUTTON_SORT' )
)->button( text="Post" press = view->_event( 'BUTTON_POST' )
).
"set header
tab->columns(
)->column( )->text( 'Title' )->get_parent(
)->column( )->text( 'Color' )->get_parent(
)->column( )->text( 'Info' )->get_parent(
)->column( )->text( 'Description' )->get_parent(
)->column( )->text( 'Checkbox' ).
"set content
tab->items( )->column_list_item( )->cells(
)->text( '{TITLE}'
)->text( '{VALUE}'
)->text( '{INFO}'
)->text( '{DESCR}'
)->checkbox( '{CHECKBOX}' ).
ENDCASE.
ENDMETHOD.
ENDCLASS.
Hasta ahora, la definición de la vista es la misma que en la primera publicación del blog, cuando definimos una pantalla de selección. Simplemente usamos el control de tabla en su lugar.
No hay fieldcat y las columnas se definen manualmente:
"set header
tab->columns(
)->column( )->text( 'Title' )->get_parent(
)->column( )->text( 'Color' )->get_parent(
)->column( )->text( 'Info' )->get_parent(
)->column( )->text( 'Description' )->get_parent(
)->column( )->text( 'Checkbox' ).
"set content
tab->items( )->column_list_item( )->cells(
)->text( '{TITLE}'
)->text( '{VALUE}'
)->text( '{INFO}'
)->text( '{DESCR}'
)->checkbox( '{CHECKBOX}' ).
No sería problema hacer algo de RTTS y encapsular, que la definición de la columna se establece automáticamente y de forma genérica como en CL_SALV_TABLE, pero como se explicó en la primera publicación del blog, ABAP2Ui5 solo quiere dar la funcionalidad básica y el resto está listo. al usuario
Lo más importante es el enlace de datos:
"set table and container
DATA(tab) = page->scroll_container( '70%'
)->table( items = view->_bind_one_way( t_tab ) ).
A diferencia, por ejemplo, del control de texto, no podemos escribir el valor del atributo directamente en el XML porque la tabla es un modelo de datos profundo. Por lo tanto, debe escribirse en el modelo de vista de la vista UI5. Pero no se preocupe por eso, ABAP2UI5 se encarga de esto, solo necesita usar el método bind_one_way y colocar su tabla en él. ABAP2UI5 luego transforma estos datos en una tabla JSON, los envía a la interfaz y los vincula con el modelo de vista a la vista XML de UI5.
A continuación, veamos cómo podemos hacer que la tabla sea editable.
CL_GUI_ALV_GRID tiene la funcionalidad (no oficial) para hacerlo editable, CL_SALV_TABLE aún está esperando, ABAP2UI5 se ve así:
El código se parece mucho al primer ejemplo:
CLASS z2ui5_cl_app_demo_11 DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES z2ui5_if_app.
TYPES:
BEGIN OF ty_row,
title TYPE string,
value TYPE string,
descr TYPE string,
icon TYPE string,
info TYPE string,
checkbox TYPE abap_bool,
END OF ty_row.
DATA t_tab TYPE STANDARD TABLE OF ty_row WITH EMPTY KEY.
DATA check_editable_active TYPE abap_bool.
ENDCLASS.
CLASS Z2UI5_CL_APP_DEMO_11 IMPLEMENTATION.
METHOD z2ui5_if_app~controller.
CASE client->get( )-lifecycle_method.
WHEN client->cs-lifecycle_method-on_init.
check_editable_active = abap_false.
t_tab = REDUCE #( INIT ret = VALUE #( ) FOR n = 1 WHILE n < 10 NEXT ret =
VALUE #( BASE ret ( title="Hans" value="red" info = 'completed' descr="this is a description" checkbox = abap_true ) ) ).
WHEN client->cs-lifecycle_method-on_event.
CASE client->get( )-event.
WHEN 'BUTTON_EDIT'.
check_editable_active = xsdbool( check_editable_active = abap_false ).
ENDCASE.
WHEN client->cs-lifecycle_method-on_rendering.
DATA(view) = client->factory_view( ).
DATA(page) = view->page( title="Example - ZZ2UI5_CL_APP_DEMO_11" nav_button_tap = view->_event_display_id( client->get( )-id_prev_app ) ).
DATA(tab) = page->table( view->_bind( t_tab ) ).
"set toolbar
tab->header_toolbar( )->overflow_toolbar(
)->title( 'title of the table'
)->toolbar_spacer(
)->button(
text = SWITCH #( check_editable_active WHEN abap_true THEN 'display' ELSE 'edit' )
press = view->_event( 'BUTTON_EDIT' ) ).
"set header
tab->columns(
)->column( )->text( 'Title' )->get_parent(
)->column( )->text( 'Color' )->get_parent(
)->column( )->text( 'Info' )->get_parent(
)->column( )->text( 'Description' )->get_parent(
)->column( )->text( 'Checkbox' ).
"set columns
IF check_editable_active = abap_true.
tab->items( )->column_list_item( )->cells(
)->input( '{TITLE}'
)->input( '{VALUE}'
)->input( '{INFO}'
)->input( '{DESCR}'
)->checkbox( selected = '{CHECKBOX}' enabled = abap_true ).
ELSE.
tab->items( )->column_list_item( )->cells(
)->text( '{TITLE}'
)->text( '{VALUE}'
)->text( '{INFO}'
)->text( '{DESCR}'
)->checkbox( '{CHECKBOX}' ).
ENDIF.
ENDCASE.
ENDMETHOD.
ENDCLASS.
Hay una diferencia en la definición de la columna, cuando la función editable está activada usamos controles de entrada en lugar de controles de texto:
IF check_editable_active = abap_true.
tab->items( )->column_list_item( )->cells(
)->input( '{TITLE}'
)->input( '{VALUE}'
)->input( '{INFO}'
)->input( '{DESCR}'
)->checkbox( selected = '{CHECKBOX}' enabled = abap_true ).
ELSE.
tab->items( )->column_list_item( )->cells(
)->text( '{TITLE}'
)->text( '{VALUE}'
)->text( '{INFO}'
)->text( '{DESCR}'
)->checkbox( '{CHECKBOX}' ).
ENDIF.
Además, debemos asegurarnos de que ABAP2UI5 devuelva los valores actualizados al servidor. Por lo tanto, tenemos que usar un enlace de datos diferente en comparación con el primer ejemplo:
DATA(tab) = page->table( items = view->_bind( t_tab ) ).
Con el método _bind() ABAP2UI5 crea un enlace bidireccional con esta tabla. Eso significa que primero los datos se transforman en un json y se envían a la interfaz y, en segundo lugar, con cada solicitud, también se envían de vuelta al backend. Así que asegúrese de que su tabla t_tab sea un atributo público que ABAP2UI5 pueda asignarle desde afuera y actualice los valores.
tiempo de ejecución
El procesamiento de solicitudes para el enlace bidireccional con tablas tiene costos un poco más altos que el enlace unidireccional porque después de cada solicitud se procesa una asignación de JSON a ABAP para actualizar la tabla editada. Por lo tanto, solo use el enlace bidireccional cuando sea realmente necesario y tal vez no haga que miles de entradas se puedan editar a la vez. Pero, ¿quién conoce a un usuario que edita 10.000 entradas al mismo tiempo? Y no hay ningún control UI5 que genere tantas entradas de todos modos. Cientos o miles de entradas y cada caso de uso más realista no es un problema con este enfoque.
ABAP2UI5 proporciona una forma rápida y sencilla de mostrar tablas y listas. Además, el uso de barras de herramientas o incluir una función editable no es un problema. Estos dos ejemplos son muy básicos, puede agregar muchos más controles a la vista para hacer que la salida de la tabla sea más hermosa o ampliar toda la funcionalidad de la aplicación.
En el futuro, se agregarán muchos más controles para mostrar los datos de la tabla a ABAP2UI5, por ejemplo, sap.ui.table o el control de línea de tiempo. Además, la funcionalidad de las filas seleccionadas y el envío de estos eventos al servidor pueden ser parte de ABAP2Ui5 en el futuro.
¿Qué opinas sobre este enfoque? Siéntase libre de compartir sus comentarios, ideas y deseos.
¡Gracias por leer!
Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010
Paseo de la Reforma 26
Colonia Juárez, Cuauhtémoc
Ciudad de México 06600
Real Cariari
Autopista General Cañas,
San José, SJ 40104
Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073