En esta lección, nos concentraremos en cómo implementar el comportamiento de un componente con reglas y acciones.
Al crear componentes, se pueden escribir reglas que consisten en una expresión y una o más acciones. Las acciones se ejecutarán si la expresión es verdadera. Una regla consta de tres elementos:
Además, siempre se asignará una regla a un estado:
<onenter>
: Este es el primer estado cuando se introduce un paso. La interfaz de usuario no está disponible en este estado, por lo que no puede usar acciones relacionadas con la interfaz de usuario. Sin embargo, si desea inicializar los parámetros para usarlos para la asignación de la interfaz de usuario, este es el estado correcto para hacerlo.<onresume>
: El segundo estado después de <onenter>
. En este estado, la interfaz de usuario está disponible y puede modificar el diseño cargado con las acciones de actualización de la interfaz de usuario.<onpause>
y <onleave>
: Estos estados se producen cada vez que se abandona el paso actual o todo el componente mediante las step_transition
acciones o . finish_workflow
Dado que las transiciones no se pueden interrumpir, no puede usar reglas aquí que usen estas acciones. En elonpause
estado, los recursos del paso siguen existiendo, pero onleave
no es así.<onevent>
: Este es probablemente el estado más importante. Las reglas definidas en este estado se comprobarán cada vez que se procese un evento. Todas las reglas relacionadas con las interacciones con el usuario se definen en este estado.Las reglas dentro de un estado se evalúan en orden arbitrario, por lo que la expresión de una regla no debe depender de que se compruebe otra regla antes que ella.
Por otro lado, las acciones dentro de una regla se ejecutan en el orden en que las escribe.
Orden de evaluación/ejecución:
La estructura general de una expresión se compone de operandos (por ejemplo, variables de contexto) y operadores (por ejemplo, '=' o '>') como en cualquier lenguaje de programación.
Operadores admitidos: +, -, &&, ||, !, /, ==, >, >=, <, <=, %, *, !=
Echemos un vistazo a otro ejemplo simple del componente "Texto paginado" que muestra un texto de longitud arbitraria en varias páginas:
<onevent> <rule id="next_page"> <expression><![ CDATA[ #{event:command} == 'NEXT_PAGE' && #{page} < #{numberofpages} ]]></expression> <actions> <action ref="next"/> <action ref="settext"/> </actions> </rule> </onevent>
Consejos y trucos:
-> Los espacios en blanco se eliminarán de la expresión a menos que estén marcados como cadenas con comillas simples, por lo que puede usar libremente nuevas líneas para que su expresión sea legible.
->Esta expresión se convierte en verdadera cuando se presiona el botón name="NEXT_PAGE"
y la página actual no es la última página.
-> Es posible que hayas notado la <![CDATA[ ... ]]>
etiqueta que rodea la expresión. La etiqueta es obligatoria en este caso. Es una palabra clave XML que informa al analizador que lo que sigue no es ningún marcado. Sin la <![CDATA[ ... ]]>
etiqueta, esta expresión invalidaría el XML de nuestro componente porque contiene los caracteres &
reservados XML y . <
-> Añade una <![CDATA[ ... ]]>
etiqueta a todas tus expresiones. De esta manera, no tiene que pensar si está utilizando caracteres reservados XML.
Cuando la regla se encuentra en el <onevent>
estado de un paso, puede reaccionar a los eventos y utilizar las propiedades del evento en la expresión. La estructura de un evento es la siguiente:
{ "comando": "... ", "dispositivo": { "modalidad": "... ", "nombre": "... ", "fuente": "... ", "descriptor": "... " }, "payload": { "... ": "... ", "error": "... " } }
Solo necesitará un subconjunto de estos campos:
1. comando: El comando de este evento, por ejemplo, "NEXT". El comando puede, por ejemplo, corresponder a un ID en la descripción del diseño o del flujo de trabajo de su componente. Ejemplo: #{event:command} == 'CANCELAR'
2. device.modality: El origen del evento. Se puede acceder a este campo mediante una notación corta.
La expresión #{event(SPEECH):command=='NEXT' es equivalente a la expresión #{event:device.modality} == 'SPEECH' && #{event:command} == 'NEXT' . La modalidad depende del emisor del evento. Ejemplo, #{event:device.modality} == 'MENU_SELECTION'
3. Carga útil: La estructura / los campos de la carga útil dependen de la acción / controlador que desencadena el evento. Ejemplo, #{event:payload.amount}
4. payload.error: Contiene un mensaje de error si lo hay. Ejemplo, #{event:payload.error}
Puede restringir los orígenes de eventos para asegurarse de que una regla solo se active cuando el evento sea causado por una modalidad de entrada específica. Por ejemplo, podría tener un comando de voz "SIGUIENTE" que los trabajadores puedan usar para confirmar que han terminado su trabajo en una tarea o producto en particular. También pueden estar usando un dispositivo que desencadena un evento con el comando "NEXT". Cuando se presiona un botón de hardware, gira a través de las opciones disponibles en la pantalla. No desea activar la regla cuando se utilizan los botones de hardware, por lo que especifica la modalidad: #{event(SPEECH):command} == 'NEXT'
.
Fuentes generales de eventos (modalidades): VOZ, GESTOS, TECLADO, CÓDIGO DE BARRAS, HW_KEYS, CAMERA_PICTURE, MENU_SELECTION, MEDIA_INPUT
Repasemos algunas construcciones de reglas que aparecen con relativa frecuencia:
Nuestro primer ejemplo aborda un caso de uso típico: la realización automática de acciones al entrar o salir de un componente.
Consejos y trucos: Algunas reglas deben ejecutarse incondicionalmente. Para ello, puede establecer la expresión en <expression>1</expression>
.
<onresume> <rule id="init"> <expression>1</expression> <actions>< action ref="reset_counter"/> </actions> </rule> </onresume>
Las reglas dentro de un estado se evalúan en orden arbitrario. En algunas situaciones, es necesario que las reglas se ejecuten secuencialmente en el mismo paso. Para ello, puede utilizar un temporizador para activar las reglas en orden secuencial. La acción del temporizador desencadena manualmente un evento con un comando definido por el usuario.
Como última acción de la primera regla, agregará una acción de temporizador. A continuación, se puede agregar el comando definido por el usuario a la expresión de la segunda regla.
<onevent> <rule id="first_rule"> <expression><![ CDATA[ #{event:command}=='VALID' ]]></expression> <actions> <action ref="do_something"/> <setvar id="increment_counter"> <context_of>workflow</context_of> <context_update> <param name="counter" type="long">#{counter} + 1</param> </context_update> </setvar> <timer id="check_counter_trigger" command="CHECK_COUNTER" delay="0"/> </actions> </rule> <rule id="second_rule"> <expression><![ CDATA[ #{event:command}=='CHECK_COUNTER' && #{counter} >= #{max_iterations} ]]></expression> <actions> <finish_workflow id="exit"/> </actions> </rule>< /onevent>
Tarea 1:
En nuestro componente "Elección" no hemos estado usando la <![CDATA[ ... ]]>
etiqueta para mantener el componente lo más simple posible para el alumno inicial. Como práctica recomendada, se recomienda usar la etiqueta en todas las expresiones para eliminar un posible origen de error.
<![CDATA[ ... ]]>
etiqueta a nuestra regla existente.Tarea 2:
Asegurémonos de que el usuario esté seguro de su elección. Si, por ejemplo, tan pronto como elegimos "Apple" comienzan a producirse tartas de manzana, es posible que queramos que el usuario reafirme:
Descargar flujo de trabajo (pre-asignación)
<command>
de las ui_dialog
opciones. Parte de la lógica de la norma existente tendrá que trasladarse a esa nueva norma.Descargar componente (posterior a la asignación)
Con esto, has terminado la cuarta lección. En la quinta lección, analizaremos algunas limitaciones de la definición de flujos de trabajo solo con XML y cómo puede usar JavaScript en flujos de trabajo para resolver estos problemas.