Saltar al contenido principal
Version: Next (5.0)

awe-106 Acciones y dependencias

En este tutorial las pantallas estáticas empiezan a comportarse como aplicaciones. Las acciones definen qué ocurre cuando los usuarios o los componentes lanzan un trabajo. Las dependencias definen cuándo deben reaccionar los componentes a valores, eventos o resultados del servidor.

Ruta rápida​

  1. Empieza con una cadena de acciones de botón pequeña.
  2. Decide qué acciones se quedan en el navegador y cuáles llaman al servidor.
  3. Añade dependencias solo donde la pantalla necesite realmente un comportamiento dinámico.
  4. Prefiere un orden de acciones predecible a cadenas ingeniosas pero difíciles de depurar.

Antes de empezar​

Ya deberías tener:

  • el esqueleto de una pantalla de awe-102
  • criterios, grids o gráficos de awe-103
  • las queries o maintains relacionados de awe-104

Mantén un modelo mental sencillo:

button or event -> action stack -> optional server call -> UI update
component values/events -> dependency evaluation -> component update or action launch

Paso 1: Construir el flujo de acciones​

Las acciones pueden ejecutarse en el cliente, en el servidor o como una cadena que mezcla ambos.

Normalmente se lanzan desde:

  • button-action dentro de los botones
  • dependency-action dentro de las dependencias

Ambas usan el mismo modelo de acciones. La diferencia principal es CUÁNDO se ejecutan.

Acciones del lado cliente​

Las acciones de cliente operan sobre el estado del navegador o sobre la pantalla actual.

Restablecer todo:

<button-action type="reset"/>

Recargar un grid:

<button-action type="filter" target="customerGrid"/>

Navegar a otra pantalla:

<button-action type="screen" target="customer-detail"/>

Pedir confirmación:

<message id="deleteConfirm" title="Delete record" message="Do you want to continue?"/>
<button-action type="confirm" target="deleteConfirm"/>
Restablecer criterios Filtro del grid Acción de navegación Acción de confirmación

Si el usuario cancela el diálogo de confirmación, se descartan las acciones pendientes restantes de esa pila.

Acciones del lado servidor​

Cuando el trabajo debe recuperar datos, guardar cambios o lanzar lógica del backend, usa una acción de servidor.

<button-action type="server" server-action="maintain" target-action="saveCustomer"/>

Si el servidor devuelve datos que deben rellenar un componente, indica también target:

<button-action type="server" server-action="data" target-action="loadCustomerSummary" target="summaryGrid"/>
Acciones devueltas por una acción de servidor

Patrón habitual:

  • server-action="data" para recuperar datos, como una query
  • server-action="maintain" o maintain-silent para escrituras

Cadenas de acciones síncronas​

Por defecto, las acciones se ejecutan de forma síncrona y en el orden en que están escritas.

<button label="BUTTON_CONFIRM" icon="save" id="ButCnf" help="HELP_CONFIRM_BUTTON">
<button-action type="validate" />
<button-action type="confirm" target="saveConfirm" />
<button-action type="server" server-action="maintain" target-action="saveCustomer" />
<button-action type="server" server-action="maintain-silent" target-action="refreshCustomerCache" />
<button-action type="filter" target="customerGrid" />
</button>

Esta es la forma habitual de un flujo de escritura seguro:

  1. validar
  2. confirmar si hace falta
  3. guardar
  4. refrescar el componente afectado
Pila de acciones

Mientras se ejecuta la pila síncrona actual, los botones de la aplicación están deshabilitados para evitar flujos que se solapen.

Botones deshabilitados

Al abrir un diálogo se crea una nueva pila actual para ese flujo modal:

<button-action type="dialog" target="customerDialog"/>
Diálogo modal y nueva pila

Acciones asíncronas​

Cuando una llamada al servidor puede ejecutarse en paralelo, usa async="true".

<button-action type="server" server-action="data" target-action="loadDashboardStats" target="statsChart" async="true"/>

Esta acción entra primero en la pila normal, lo que significa que los pasos previos de validación o confirmación todavía pueden cancelarla antes de su ejecución.

Acciones asíncronas

Usa async para trabajo realmente paralelo, no como opción por defecto.

Inspeccionar el flujo de acciones​

Las herramientas de desarrollo pueden ralentizar el flujo de acciones para que puedas inspeccionar lo que ocurre.

alt + shift + `[number]`

Esto añade un retardo en segundos y muestra las pilas de acciones, de modo que se vea con más claridad la ejecución síncrona y asíncrona.

Paso 2: Añadir dependencias con criterio​

Las dependencias dan a la pantalla un comportamiento dinámico basado en valores, atributos o eventos.

Pueden definirse en componentes interactivos como botones, criterios, grids y columnas.

Ejemplos:

<button ...>
<dependency ...>
</dependency>
</button>
<criteria ...>
<dependency ...>
</dependency>
</criteria>
<grid ...>
<dependency ...>
</dependency>
</grid>

La dependencia solo se ejecuta cuando coinciden sus lanzadores.

Tipos de lanzador​

Lanzadores de valor​

Observan los valores de los componentes.

<dependency ...>
<dependency-element id="criterionA"/>
</dependency>

Se ejecuta cuando criterionA tiene cualquier valor o cambia.

<dependency ...>
<dependency-element id="criterionA" condition="eq" value="value1"/>
</dependency>

Se ejecuta cuando criterionA == value1.

<dependency ...>
<dependency-element id="criterionA" condition="gt" value="3"/>
<dependency-element id="criterionA" condition="ne" id2="criterionB"/>
</dependency>

Se ejecuta cuando criterionA > 3 y criterionA != criterionB.

Lanzadores de atributo​

Observan los atributos de los componentes en lugar del valor principal.

<dependency ...>
<dependency-element id="criterionA" attribute="unit" condition="eq" value="EUR"/>
</dependency>

Para los grids o treegrids, las comprobaciones de atributo suelen necesitar el nombre de una columna:

<dependency ...>
<dependency-element id="gridA" column="status" attribute="selectedRowValue" condition="eq" value="READY"/>
</dependency>
selectedRowValue

También puedes recuperar valores relativos a la fila para hacer cálculos:

<column name="total" component="text">
<dependency ...>
<dependency-element id="gridA" column="price" attribute="currentRowValue" alias="priceValue"/>
<dependency-element id="gridA" column="quantity" attribute="currentRowValue" alias="quantityValue"/>
</dependency>
</column>

Lanzadores de evento​

Reaccionan a los eventos de los componentes.

<column name="total" component="text">
<dependency ...>
<dependency-element id="gridA" column="price" attribute="currentRowValue" alias="priceValue"/>
<dependency-element id="gridA" column="quantity" attribute="currentRowValue" alias="quantityValue"/>
<dependency-element id="calculateButton" event="click"/>
</dependency>
</column>
Recálculo con un botón

Ejemplo de recálculo al guardar una fila:

<column name="total" component="text">
<dependency ...>
<dependency-element id="gridA" column="price" attribute="currentRowValue" alias="priceValue"/>
<dependency-element id="gridA" column="quantity" attribute="currentRowValue" alias="quantityValue"/>
<dependency-element id="gridA" event="save-row"/>
</dependency>
</column>
Recálculo de una columna

Modificadores de dependencia​

Evaluación inicial​

Usa initial="true" cuando la dependencia deba evaluarse también durante la carga de la pantalla.

<dependency initial="true" ...>
<dependency-element id="criterionA" condition="gt" value="3"/>
<dependency-element id="criterionA" condition="ne" id2="criterionB"/>
</dependency>

and frente a or​

Las dependencias usan lógica and por defecto. Cámbiala a type="or" cuando baste con que se cumpla cualquiera de los lanzadores.

<dependency type="or" ...>
<dependency-element id="criterionA" condition="gt" value="3"/>
<dependency-element id="criterionA" condition="ne" id2="criterionB"/>
</dependency>

Evaluación invertida​

Usa invert="true" cuando quieras la condición contraria sin reescribir toda la expresión de la dependencia.

<dependency invert="true" ...>
<dependency-element id="criterionA" condition="gt" value="3"/>
<dependency-element id="criterionA" condition="ne" id2="criterionB"/>
</dependency>

Alias para los valores recuperados​

Los alias permiten que los lanzadores aporten valores a fórmulas o a actualizaciones de la dependencia.

<criteria component="numeric" id="total">
<dependency initial="true" source-type="formule" target-type="input" formule="[a] + [b]">
<dependency-element id="amountA" alias="a"/>
<dependency-element id="amountB" alias="b"/>
</dependency>
</criteria>

Paso 3: Decidir qué debe hacer la dependencia​

Una vez lanzada, una dependencia puede actualizar el componente actual o lanzar acciones en otro lugar.

Actualizar el componente actual​

source-type indica a AWE de dónde obtiene los datos la dependencia.

Patrones habituales:

Copiar desde un lanzador​

<criteria component="numeric" id="copiedValue">
<dependency source-type="launcher" target-type="input" target-action="a">
<dependency-element id="criterionA" alias="a"/>
</dependency>
</criteria>

Usar un valor estático​

<criteria component="text" id="staticValue">
<dependency source-type="value" target-type="input" value="Pending review">
<dependency-element id="criterionA" alias="a"/>
</dependency>
</criteria>

Usar una fórmula​

<criteria label="a" id="a" component="numeric" style="col-xs-6 col-sm-3 col-lg-2" value="3"/>
<criteria label="b" id="b" component="numeric" style="col-xs-6 col-sm-3 col-lg-2" value="6"/>
<criteria label="a + b" id="aplusb" component="numeric" style="col-xs-6 col-sm-3 col-lg-2">
<dependency source-type="formule" target-type="input" formule="[a] + [b]">
<dependency-element id="a"/>
<dependency-element id="b"/>
</dependency>
</criteria>
Dependencia con fórmula

Usar una query​

<grid id="grid">
<column name="customerName"/>
<column name="customerStatus"/>
<dependency source-type="query" target-type="input" server-action="data" target-action="loadCustomerDetails">
<dependency-element id="criterionA" alias="a"/>
<dependency-element id="criterionB" condition="ne" value="archived"/>
</dependency>
</grid>
Dependencia con query

target-type decide después qué parte del componente se actualiza: el valor de entrada, la etiqueta, la unidad, la visibilidad, el estado habilitado, etc.

Ejemplo: habilitar un botón solo cuando un criterio tiene un valor concreto.

<button id="saveButton">
<dependency target-type="enable">
<dependency-element id="criterionA" condition="eq" value="READY"/>
</dependency>
</button>

Ejemplo: mostrar un criterio solo cuando otro criterio tiene un valor concreto.

<criteria id="criterionB" component="text">
<dependency target-type="show">
<dependency-element id="criterionA" condition="eq" value="show"/>
</dependency>
</criteria>
Actuación reversible

Lanzar acciones desde una dependencia​

Algunas dependencias no actualizan su propio componente. Solo lanzan acciones cuando se cumplen las condiciones.

<dependency>
<dependency-element id="gridA" attribute="selectedRows" condition="eq" value="1" />
<dependency-element id="gridA" event="select-row" />
<dependency-action type="server" server-action="data" target-action="loadDetailGrid" target="gridB"/>
</dependency>

Es un patrón maestro-detalle habitual: al seleccionar una fila en un grid se refresca otro grid.

Al seleccionar una fila se recarga otro grid

Orden de ejecución y rendimiento​

Las dependencias se evalúan en el orden en que están definidas. Si varias dependencias del mismo componente coinciden, se ejecutan de forma síncrona en ese orden.

<criteria id="criterionA" component="hidden">
<dependency source-type="launcher" target-type="input" target-action="value">
<dependency-element id="criterionB" alias="value"/>
<dependency-element id="buttonA" event="click"/>
</dependency>
<dependency source-type="launcher" target-type="input" target-action="value">
<dependency-element id="criterionC" alias="value"/>
<dependency-element id="buttonA" event="click"/>
</dependency>
</criteria>

En ese ejemplo, la segunda dependencia puede sobrescribir a la primera porque se ejecuta después.

Regla de rendimiento: las dependencias son potentes, pero demasiadas hacen que una pantalla sea más difícil de razonar y más lenta en el navegador. Construye el comportamiento dinámico más pequeño que resuelva el problema del usuario.

Qué hacer a continuación​

  • Vuelve a awe-104 si los descriptores del lado servidor que hay detrás de estas acciones todavía no te quedan claros.
  • Continúa con awe-107 cuando una acción de servidor deba ejecutar lógica Java.
  • Ten a mano la documentación de la API para consultar todas las opciones de acciones y dependencias cuando el flujo básico de la pantalla ya funcione.