LWC en Screen Flows

y sus particularidades.

Contenido

    Introducción

    Ligtning web components es nuestro framework front-end moderno en Salesforce y tiene muchisimas posibilidades y una de ellas es la integración con otra de sus herramientas mas poderesas, los screen flows.

    En este árticulo vamos a ver como crear un componente LWC totalmente funcional en un screen flow. Abordaremos desde la creación, pasando por la definición de parametros, mantener los datos ingresados del usuario y realizar una validación al presionar siguiente.

    Screen Flows

    Los screen flows son una de las funcionalidades de Salesforce que nos permite programar sin escribir una sola linea de código, basta con arrastrar y relacionar diferentes componentes entre si, sin embargo el flujo debe seguir una logica y en algunos casos necesitamos comportamientos o funcionalidades muy especificas que se salen fuera del alcance por defecto, pero en estos casos podemos desarrollar nuestro propio componente utilizando Lighning Web Components (LWC).

    Código Personalizado

    Todo código personalizado que desarrollemos debe ser responsable de manejar cada uno de los posibles escenarios que puedan ocurrir dentro de un flow, esto incluye la entrada y salida de datos, validaciones cuando el usuario desee darle siguiente y muy importante la conservación de datos cuando el usuario navega por el flow.

    Parámetros de Entrada y Salida

    Cuando creamos un LWC se crea con la siguiente estructura

    ShellScript
    componentName/
    componentName/__tests__/
    componentName/componentName.html
    componentName/componentName.js
    componentName/componentName.js-meta.xml

    Donde componentName es el nombre del componente y como se aprecia se crea una carpeta con el nombre del componente , una carpeta donde se guardan la pruebas de unidad (__test__), un HTML, un Javascript y un XML. Este ultimo, el xml (componentName.js-meta.xml) es el encargado de indicarle a Salesforce como debe tratar el componente, en pocas palabras es un archivo de configuración.

    La apariencia de este archio es la siguiente

    XML
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>61.0</apiVersion>
        <isExposed>false</isExposed>
    </LightningComponentBundle>

    Como minimo tenemos 2 atributos, el primeo es apiVersion, el cual indica que API de Salesforce interpreta el componente, esto debido a que Salesforce agrega funcionalidades y a veces elimina o reemplaza otras, de esta forma se sabe que el componente fue creado con cierto interprete y el codigo no va a fallar por actualizaciones de la API en general. El otro es isExposed, en caso de true indica que el componente esta expuesto a otras partes de Salesforce, y en caso de false indica que solo va a ser referenciado en codigo fuente por otros componentes.

    Este archivo de configuración tiene muchas configuraciones que pueden ser consultadas en el siguiente enlace https://developer.salesforce.com/docs/platform/lwc/guide/reference-configuration-tags.html

    Para nuestro objetivo vamos a necesitar 2 atributos mas, el primero es targets, en el cual indicamos que nuestro componente va a estar disponible en FLOWS, y el segundo es property en donde indicamos cuales van a ser los parámetros que van a estar disponibles en nuestro componente, este property tiene una pripieda que es role, el cual nos permite definir si un parametro es de entrada, salida o ambos.

    Un archivo de configuración con las caracteristicas mencionadas anterormente se deberia de ver asi.

    XML
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>61.0</apiVersion>
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__FlowScreen</target>
        </targets>
        <targetConfigs>
            <targetConfig targets='lightning__FlowScreen'>
                <property 
                  type='String' 
                  name='defaultValue' 
                  label='Default Value' 
                  role='inputOnly'/>
            </targetConfig>
        </targetConfigs>
    </LightningComponentBundle>

    En el cual las opciones de configuración deberian de verse de la siguiente forma al momento de agregarlo a un flow

    Validando el Componente en el Flujo

    Podemos realizar validaciones en nuestro componente, pero esto no evita que el usuario presione siguiente y las validaciones sean completamente ignoradas, sin embargo podemos adicionar una función a nuestro js llamada validate expuesta como api y que retorna un object con 2 atributos, isValid y errorMessage, como se puede intuir, isValid se asigna como true o false de acuerdo asi es valido, y errorMessage es el mensaje de error a mostrar al usuario.

    JavaScript
    @api validate(){
      
      return {
        isValid : true,
        errorMessage: ''
      }
      
    }

    Preservando los Valores al Navegar

    Para tener una buena experiencia de usuario, nuestros componentes deben preservar la información que el usuario ingresó al momento de darle siguiente, para que en caso de que presione regresar en una pantalla posterior cargue los utimos datos que ingresó. Este es el comportamiento por defecto de los flows cuando utilizamos componentes estándares de Salesforce.

    Para lograr este objetivo necesitamos tener mucho cuidado con el role que definimos en property. Actualmente tenemos tres opciones:

    • inputOnly : solo parámetro de entrada.
    • outputOnly : solo parámetro de salida.
    • no defiened : parámetro de entrada y salida.

    Si seleccionamos inputOnly hace que los datos solo sean de entrada, pero adicionalmente no tendremos una referencia de el valor una vez presionemos siguiente y desde la pantalla siguiente le demos regresar o cuando la validación realizada a través de @api validation() retorne un error. El siguiente video ilustra este comportamiento

    Si decidimos utilizar este role por alguna restricción de diseño o cualquier otra razón, tocaría controlar en nuestro flow la variable de entrada y actualizar el valor cada vez que le demos siguiente y en el componente tras cada validación utilizar alguna forma de conservar los datos como seria el uso de localstorage.

    continuando con los roles tenemos la alternativa que un parámetro sea tanto de entrada como de salida y esto lo logramos simplemente sin definir el atributo role. Al hacerlo de esta forma no tenemos que realizar ningun cambio y el valor es automaticamente manejado por flow, por lo que seria menos trabajo de desarrollo, menos código por mantener y mas fácil de entender, lo unico es que los valores de entrada como se sugiere, tambien estarian disponibles como salida; personalmente siempre obtaria por esta solución teniendo en cuenta sus ventajas. simplemente removiendo el role a la property, el componente se deberia de comportar como ilustra el siguiente video

    Desarrollo del Componente

    A continuación el componente que utilicé para el último video, el cual tiene todo lo explicado en este árticulo.

    Este componente y el flow de prueba puede ser descargado aqui

    HTML
    <template>
        <div class="slds-theme_default">
            <div>
                <lightning-input 
                  type="text" 
                  label="Enter a name" 
                  value={name} 
                  onchange={handleChange}></lightning-input>
            </div>
            <div>
                Total characters : {nameLenght}
            </div>
            <div>
                {greetings}
            </div>
        </div>
    </template>

    Explicación HTML

    • Linea 2: un contenedor que utiliza el estilo por defecto de Salesforce
    • Lineas 3-9: define un input component de tipo texto, el cual muetra el valor ingresado por el usuario
    • Linea 11 : Mustra el total de caracteres ingresados
    • Linea 14: Muestra el saludo
    JavaScript
    import { api, LightningElement } from 'lwc';
    
    export default class AFlowForm extends LightningElement {
    
        @api name;
        @api greetings;
    
        nameLenght;
    
        connectedCallback(){
            this.updateGreetings();
        }
    
        handleChange(event){
            this.name = event.detail.value;
            this.updateGreetings();
        }
    
        updateGreetings(){
            this.greetings = 'Hello '+this.name+', congratulation to learn LWC in Screen Flows ';
            this.nameLenght = this.name.length;
        }
    
        @api validate(){
      
            let isValid = true;
            let message = '';
            console.log('characters',this.name.length);
    
            if(this.name.length <= 10){
                isValid = false;
                message = 'name must contains at least 10 letters';
            }
    
            return {
              isValid : isValid,
              errorMessage: message
            }
            
          }
    
    }

    Explicación Javascript

    • Lineas 5-6: Define los parametros de entra y salida
    • Lineas 10-12: ejecuta la función updateGreetings() cada vez que ocurre el llamado del connectedCallback. En este caso especifico ocurre al menos 2 veces, la primera cuando se carga el componente en la pantalla, la segunda cuando el componente falla la validación al presionar el boton siguiente.
    • Lineas14-17: define la función que se llama cada vez que el texto ingresado por el usuario cambia. su tarea es actualizar el name y el saludo.
    • Lineas 19-22: función que define especificamente como actualizar el saludo.
    • Lineas 24-40: función para validar el componente cuando se presiona el boton siguiente. La validación especifica valida que el texto ingresado por el usuario sea el menos de 10 caracteres.
    XML
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>61.0</apiVersion>
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__FlowScreen</target>
        </targets>
        <targetConfigs>
            <targetConfig targets='lightning__FlowScreen'>
                <property 
                  type='String' 
                  name='name' 
                  label='Name' />
                <property 
                  type='String' 
                  name='greetings' 
                  label='greetings' 
                  role='outputOnly' />
            </targetConfig>
        </targetConfigs>
    </LightningComponentBundle>

    Explicación Archivo de configuración

    • Linea 6: Permite que el componente sea utilizado en screen flows
    • Lineas 8-20: define los parametros de entrada y salida. El name es de entrada y salida porque no define el role y greetings es solo de salida porque especificamente se indica el role outputOnly.

    Explicación Flow

    El flow utiliza 2 pantallas, la primera incluye el componente que se crea en este árticulo y la segunda pantalla muestra el saludo obtenido del nuestro componente.

    Se crea una constante para denifir un valor por defecto

    Detalle de la primera pantalla en la que se incluye el componente creado

    Finalmente la segunda pantalla en la que se muestra el saludo obtenido del componente

    Conclusiones

    • los lighning web components nos permiten extender los screen flow, sin embargo hay que tener en cuenta los pequeños detalles para que la experiencia de desarollo y mantenimiento no sean un dolor de cabeza
    • Prefiere utilizar properties sin definir el role para los parametros de entrada, a menos que se tenga alguna restricción de diseño.
    • Nunca nadie menciona como conservar los datos dentro de los flow usando un componente y esto puede complicar el desarrollo para un desarrollador inexperto.

    Gracias por leer.

    Commentarios

    Leave a Reply

    Your email address will not be published. Required fields are marked *