Empiece a realizar un seguimiento de su progreso
Inicio de Trailhead
Inicio de Trailhead

Conectar componentes con eventos

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Definir eventos personalizados para sus aplicaciones.
  • Crear y desencadenar eventos desde un controlador de componente.
  • Crear gestores de acciones para captar y gestionar eventos que envían otros componentes.
  • Cambiar un componente de gran tamaño en componentes de menor tamaño.

Conectar componentes con eventos

En esta unidad, completaremos la última parte de la función inacabada en nuestra pequeña aplicación de gastos: la casilla Reimbursed?. Probablemente esté pensando que la implementación de una casilla sería un tema breve. Deberíamos seguramente utilizar algunos atajos y hacerlo un tema muy breve.

Pero esta unidad, además de hacer que la casilla funcione, trata de eliminar todos los atajos que ya utilizamos. Pasaremos esta unidad “Haciéndolo bien”. Lo que, en algunas partes, significa cambiar el trabajo que hicimos anteriormente.

Antes de comenzar con esto, hablemos primero de los atajos que utilizamos, el camino correcto, y por qué el camino correcto es (un poco más) difícil, pero también mejor.

Composición y descomposición

Si hecha un vistazo a nuestra pequeña aplicación de gastos en la forma de código fuente y enumera los artefactos de código separados, obtendrá algo parecido a lo siguiente.

  • expenses component
    • expenses.cmp
    • expensesController.js
    • expensesHelper.js
  • expensesList component
    • expensesList.cmp
  • expenseItem component
    • expenseItem.cmp
  • ExpensesController (lado del servidor)
    • ExpensesController.apex

De este modo, tenemos todo el conjunto, con los eventos createExpense y updateExpense que conectará más adelante.

La aplicación de gastos se compone de muchos componentes más pequeños.

Pero si mira la aplicación en pantalla, ¿qué ve? Lo que debería ver y lo que verá realmente mire donde mire es que la aplicación se desglosa en muchos más componentes. Verá que puede descomponer nuestra aplicación aún más, en trozos más pequeños, de lo que hicimos hasta ahora. Cuando menos, esperamos que vea que el formulario Add Expense debería ser su propio componente separado. (Esa era la razón por la que dibujamos un cuadrado sobre él en la interfaz de usuario.)

¿Por qué no hicimos que ese formulario fuera un componente separado? No hacerlo es el mayor atajo que realizamos durante el curso de este módulo. Es peor que el truco que llamamos “repugnante” en términos de diseño de software. La forma correcta de crear una aplicación Componentes Lightning es crear componentes independientes y luego componerlos juntos para crear nuevas funciones de más alto nivel. ¿Por qué no tomamos ese enfoque?

Tomamos el atajo, manteniendo el formulario Add Expense dentro del componente expenses principal, porque dejaba el atributo de componente de la matriz expenses principal y el código del controlador que lo afectaba en el mismo componente. Deseábamos que la función auxiliar createExpense() pudiera tocar la matriz expenses directamente. Si hubiéramos movido el formulario Add Expense a un componente separado, eso no hubiera sido posible.

¿Por qué no? Tratamos la razón brevemente mucho antes, pero ahora queremos machacarla. Se supone que los Componentes Lightning son autocontenidos. Son elementos autónomos que encapsulan todas sus funciones esenciales. A un componente no se le permite llegar a otro componente, incluso a un componente secundario, y alterar sus funciones internas.

Existen dos maneras principales de afectar o interactuar con otro componente. La primera manera es la que ya vimos y con la que trabajamos bastante hasta el momento: establecer atributos en la etiqueta del componente. Los atributos públicos de un componente constituyen una parte de su API.

La segunda manera de interactuar con un componente es a través de eventos. Del mismo modo que los atributos, los componentes declaran los eventos que envían y los eventos que pueden gestionar. Al igual que los atributos, estos eventos públicos constituyen una parte de la API pública del componente. Ya hemos utilizado y gestionado eventos, pero los eventos se han estado escondiendo detrás de algunas funciones útiles. En esta unidad sacaremos los eventos a la luz y crearemos algunos propios.

La metáfora de la conexión de un circuito de nuevo

Estos dos mecanismos, los atributos y los eventos, son los “zócalos” de la API, las maneras de conectar los componentes entre sí para formar circuitos completos. Los eventos son también, entre bambalinas, los electrones que fluyen por ese circuito. Pero esta es solo una de las maneras en que los eventos difieren de los atributos.

Cuando establece el atributo onclick en <lightning:button> para un controlador de acción de un controlador de componente, crea una relación directa entre esos dos componentes. Están vinculados, y aunque utilizan las API públicas para mantener su independencia entre sí, siguen estando emparejados.

Los eventos son diferentes. Los componentes no envían eventos a otro componente. Esa no es la manera de funcionar de los eventos. Los componentes difunden eventos de un tipo en particular. Si hay un componente que responde a ese tipo de evento, y si ese componente “escucha” su evento, actuará sobre él.

Puede pensar sobre la diferencia entre los atributos y los eventos como la diferencia entre circuitos cableados y circuitos sin cables. Y no estamos hablando aquí de teléfonos celulares. Un componente no consigue el “número” de otro componente y lo llama. Eso sería un atributo. No, los eventos son como difusiones inalámbricas. Su componente enciende la radio y envía un mensaje. ¿Hay alguien ahí con un aparato de radio encendido y sintonizado en la frecuencia correcta? Su componente no tiene manera de saberlo, de modo que debe redactar sus componentes de una forma en que no pase nada si nadie escucha los eventos que difunden. (O sea, puede que las cosas no funcionen, pero nada se bloquea.)

Envío de un evento desde un componente

De acuerdo, basta de teoría: hagamos algo específico con nuestra aplicación y veamos cómo funcionan los eventos en el código. Empezaremos implementando la casilla de verificación Reimbursed?. Luego tomaremos lo aprendido haciendo eso y lo utilizaremos para cambiar el tamaño del formulario Add Expense en su propio componente, del modo pensado por el Gran Ingeniero.

Primero, vamos a centrarnos en el controlador de clic de <lightning:input> para el campo Reimbursed__c.

<lightning:input type="toggle"
            label="Reimbursed?"
            name="reimbursed"
            class="slds-p-around_small"
            checked="{!v.expense.Reimbursed__c}"
            messageToggleActive="Yes"
            messageToggleInactive="No"
            onchange="{!c.clickReimbursed}"/>

Antes de examinar el controlador de clic, retrocedamos un paso para ver qué ofrece <lightning:input>. type="toggle" es en realidad un casilla con un diseño de conmutador de alternancia. class le permite aplicar estilos CSS personalizados o usar utilidades SLDS. messageToggleActive y messageToggleInactive proporcionan etiquetas personalizadas para las posiciones activadas y no activadas. Estos prácticos atributos son algunos de los muchos que se incluyen en <lightning:input>. Por último, el atributo onchange de <lightning:input> proporciona un método sencillo para conectar el conmutador de alternancia con un controlador de acción que actualiza el registro si se desplaza a la derecha (activado) o a la izquierda (desactivado).

Ahora, pensemos en lo que ocurre en el caso de la activación o la desactivación. En base al código que redactamos para crear un nuevo gasto, la actualización de un gasto es probablemente algo como esto.

  1. Obtenga el elemento expense que cambió.
  2. Cree una acción de servidor para actualizar el registro de gasto subyacente.
  3. Empaquete expense en la acción.
  4. Establezca una devolución de llamada para gestionar la respuesta.
  5. Desencadene la acción, enviando la solicitud al servidor.
  6. Cuando llegue la respuesta y se ejecute la devolución de la llamada, actualice el atributo expenses.

Ejem, ¿qué atributo expenses? Mire de nuevo la marca de nuestro componente. No hay expenses, solo expense en singular. Interesante... este componente es solo para un único elemento. Existe un atributo expenses en el componente expensesList, pero no es el expenses “auténtico”. El auténtico es un atributo de componente en el componente expenses de nivel superior. Vaya...

¿Hay un component.get("v.parent")? ¿O tendría que ser component.get("v.parent").get("v.parent") algo que nos permitiera obtener una referencia al principal de nuestro principal, de modo que podamos establecer expenses allí?

Pare. Justo. Ahí.

Los componentes no pueden llegar a otros componentes y establecer valores en ellos. No hay forma de decir “Hola jefe, voy a actualizar expenses.” Los componentes son autónomos. Cuando un componente desea que un componente antecesor realice un cambio en algo, lo solicita. Educadamente. Enviando un evento.

Aquí está la parte interesante. El envío de un evento tiene una apariencia casi idéntica a gestionar la actualización directamente. A continuación tenemos el código para el gestor clickReimbursed.

({
    clickReimbursed: function(component, event, helper) {
        let expense = component.get("v.expense");
        let updateEvent = component.getEvent("updateExpense");
        updateEvent.setParams({ "expense": expense });
        updateEvent.fire();
    }
})

¡Vaya! ¡Es bastante fácil! Y parece el tipo de afinidad que concebimos arriba. El código precedente para clickReimbursed realiza lo siguiente:

  1. Obtiene el gasto que cambió.
  2. Crea un evento denominado updateExpense.
  3. Empaqueta el gasto en el evento.
  4. Desencadena el evento.

Falta el tema de la devolución de llamada, pero el resto resulta familiar. Pero… ¿qué va a gestionar la llamada al servidor, la respuesta del servidor y la actualización del atributo de la matriz expenses principal? ¿Y cómo sabemos algo de este evento updateExpense?

updateExpense es un evento personalizado, o lo que es lo mismo, un evento que redactamos nosotros mismos. Esto se puede saber porque, a diferencia de la obtención de una acción de servidor, utilizamos component.getEvent() en vez de component.get(). Del mismo modo, lo que estamos obteniendo no tiene un proveedor de valores, solo un nombre. Definiremos este evento en solo un momento.

En referencia a lo que va a gestionar la llamada al servidor y la respuesta, hablemos de ello. Podríamos implementar la solicitud del servidor y gestionar la respuesta directamente aquí en el componente expenseItem. Luego enviaríamos un evento solo para volver a representar las cosas que dependen de la matriz expenses. Esto podría ser una elección de diseño perfectamente válida, y mantendría el componente expenseItem totalmente autocontenido, lo que es conveniente.

No obstante, como veremos, el código para crear un nuevo gasto y el código para actualizar un gasto existente es bastante similar, lo suficiente para que prefiramos evitar duplicar código. De este modo, la elección de diseño que realizamos es enviar un evento updateExpense, que el componente expenses principal gestionará. Más adelante, cuando cambiemos el tamaño de nuestro formulario, haremos lo mismo para crear un nuevo gasto.

Haciendo que todos los componentes secundarios deleguen la responsabilidad de gestionar las solicitudes del servidor y de administrar el atributo de la matriz expenses, estamos quebrando un poco la encapsulación. Pero si piensa en estos componentes secundarios como los detalles de implementación internos del componente expenses, esto es válido. El componente expenses principal es autocontenido.

Tiene una opción: la consolidación de la lógica crítica o la encapsulación. Realizará compensaciones en componentes Aura del mismo modo que realiza compensaciones en cualquier diseño de software. Solo tiene que asegurarse de que documenta los detalles.

Definición de un evento

Lo primero que haremos será definir nuestro propio evento personalizado. En Developer Console, seleccione File |New Lightning Event (Archivo, Nuevo, Evento Lightning) y asigne al evento el nombre “expensesItemUpdate”. Sustituya el contenido predeterminado por la siguiente marca:

<aura:event type="COMPONENT">
    <aura:attribute name="expense" type="Expense__c"/>
</aura:event>

Existen dos tipos de eventos: componente y aplicación. Aquí estamos utilizando un evento componente, porque queremos que un componente antecesor capte y gestione el evento. Un antecesor es un componente “por encima” de este en la jerarquía de componentes. Si deseamos un evento del tipo “difusión general”, donde cualquier componente pueda recibirlo, utilizaríamos un evento aplicación en su lugar.

Las diferencias completas y el correcto uso de los eventos aplicación frente a componente es algo que no podemos tratar aquí. Es un tema más avanzado que tiene suficientes detalles complicados que pueden suponer una distracción frente al propósito de este módulo. Cuando esté listo para más, los Recursos le ayudarán.

Otra cosa a tener en cuenta sobre el evento es lo compacta que sea la definición. Asignamos un nombre al evento cuando se creó, expensesItemUpdate, y su marca comienza y termina con la etiqueta <aura:event>, y una etiqueta <aura:attribute>. Los atributos de un evento describen la carga que puede llevar. En el gestor de acción clickReimbursed, establecemos la carga con una llamada a setParams(). Aquí en la definición de evento, vemos como se define el parámetro del evento y que no hay otros parámetros válidos.

Y hay mucho más para definir los eventos. No se agregan detalles de implementación o comportamiento a los eventos en sí. Solo son paquetes. De hecho, algunos eventos no tienen parámetros en absoluto. Solo son mensajes. “¡Esto ocurrió!” Todo el comportamiento sobre lo que hay que hacer si “esto” ocurre se define en los componentes que envían y reciben el evento.

Envío de un evento

Ya vimos como desencadenar un evento, en el gestor de acciones clickReimbursed. Pero para que funcione, debemos realizar una última cosa, que es registrar el evento. Agregue esta línea de marca al componente expenseItem, justo debajo de sus definiciones de atributos.

    <aura:registerEvent name="updateExpense" type="c:expensesItemUpdate"/>

Esta marca dice que nuestro componente desencadena un evento, denominado “updateExpense”, del tipo “c:expensesItemUpdate”. Pero ¿no era “expensesItemUpdate” el nombre del evento cuando lo definimos? ¿Y qué paso con los tipos de evento componente o aplicación?

Tiene razón al pensar que esto es un poco confuso, realmente es un poco un rompecabezas. Puede ayudar pensar en “aplicación” y “componente” como tipos de evento del marco de componentes Aura, mientras que los tipos que provienen de los nombres de eventos que define son tipos de eventos personalizados, o tipos estructurales de eventos. Esto significa que cuando define un evento, define un formato de paquete. Cuando registra para enviar un evento, declara qué formato utiliza.

El proceso de definir y registrar un evento puede aún parecer un poco extraño, así que miremos un poco hacia adelante. Aquí en expenseItem, vamos a enviar un evento denominado updateExpense. Más adelante en expenseForm, vamos a enviar un evento denominado createExpense. Ambos eventos tienen que incluir un gasto (expense) que hay que guardar en el servidor. Así que ambos utilizan el tipo de evento c:expensesItemUpdate, o formato de paquete, para enviar sus eventos.

En el extremo receptor, nuestro componente expenses principal va a registrar para gestionar ambos eventos. Aunque la llamada al servidor acaba siendo la misma, las actualizaciones de la interfaz de usuario son ligeramente diferentes. Así que ¿cómo sabe expenses si crea o actualiza el gasto (expense) en el paquete c:expensesItemUpdate? Por el nombre del evento que se envía.

La comprensión de la distinción aquí y cómo un evento puede utilizarse para varios fines es un rayo de luz en el aprendizaje de los Componentes Lightning. Si aún no ha tenido ese momento, lo tendrá cuando mire el resto del código.

Antes de que pasemos a gestionar eventos, resumamos lo que hace falta para enviarlos.

  1. Defina un evento personalizado creando un evento Lightning, asignándole un nombre y unos atributos.
  2. Registre su componente para enviar esos eventos seleccionando un tipo de evento personalizado y dándole un nombre a este uso específico de ese tipo.
  3. Desencadene el evento en el código de su controlador (o auxiliar):
    1. Empleando component.getEvent() para crear una instancia de evento específica.
    2. Enviando el evento con fire().

Si lo hizo e implementó todo el código que acabamos de analizar, puede probarlo. Vuelva a cargar su aplicación y alterne una casilla de verificación Reimbursed? varias veces. Si se saltó un paso, aparecerá un error y tendrá que volver a comprobar su trabajo. Si lo hizo todo bien... un momento, el gasto cambia de color para mostrar su estado Reimbursed?, ¡justo como se esperaba!

Este comportamiento estaba presente incluso antes de iniciar esta unidad. Ese es el efecto del componente <lightning:input> que tiene establecido value="{!v.expense.Reimbursed__c}". Cuando alterna el conmutador, la versión local de expense se actualiza. Pero el cambio no se envía al servidor. Si mira el registro expense en Salesforce o vuelve a cargar la aplicación, no verá el cambio.

¿Por qué no? Solo realizamos la mitad del trabajo para crear un circuito completo para nuestro evento. Tenemos que terminar de conectar el circuito creando el gestor de eventos en el otro lado. Ese gestor de eventos se encargará de enviar el cambio al servidor y hacer que la actualización sea duradera.

Gestionar un evento

La activación del componente expenseItem para enviar un evento requirió tres pasos. La activación del componente expenses para recibir y gestionar estos eventos requiere tres pasos paralelos.

  1. Defina un evento personalizado. Ya hicimos esto, porque expenseItem está enviando el mismo evento personalizado que gastos está recibiendo.
  2. Registre el componente para gestionar el evento. Esto asigna el evento a un gestor de acciones.
  3. Realmente gestiona el evento en un gestor de acciones.

Debido a que ya que realizamos el paso 1, pasemos inmediatamente al paso 2 y registremos gastos para recibir y gestionar el evento updateExpense. Como el registro para enviar un evento, el registro para gestionar uno es una única línea de marca, que debe agregar al componente expenses justo después del gestor de init.

     <aura:handler name="updateExpense" event="c:expensesItemUpdate"
        action="{!c.handleUpdateExpense}"/>

Como el gestor de init, este utiliza la etiqueta <aura:handler>, y tiene un atributo action que establece el gestor de acciones del controlador para el evento. Como cuando registro el evento en expenseItem, aquí establece el nombre y el tipo de evento, aunque hay que tener en cuenta el uso del atributo nombrado mucho más razonablemente event para el tipo.

En otras palabras, no hay mucho aquí que no haya visto antes. Lo que es nuevo y específico en la gestión de eventos personalizados es la combinación de los atributos y saber como este “zócalo” receptor en expenses coincide con el “zócalo” emisor en expenseItem.

Esto completa la parte de las conexiones para hacer que esto funcione. ¡Todo lo que queda es escribir el gestor de acciones!

Empezaremos con el gestor de acciones handleUpdateExpense. Aquí está el código, y asegúrese de ponerlo JUSTO debajo del gestor de acciones clickCreate.

    handleUpdateExpense: function(component, event, helper) {
        let updatedExp = event.getParam("expense");
        helper.updateExpense(component, updatedExp);
    }

Vaya. Eso es interesante. Excepto la comprobación de validación de formulario y la función auxiliar específica a la que estamos delegando el trabajo, parece que este gestor de acciones es el mismo que handleCreateExpense.

Agreguemos ahora la función auxiliar updateExpense. Como hicimos con el gestor de acciones, asegúrese de que pone este código justo debajo de la función auxiliar createExpense.

    updateExpense: function(component, expense) {
        let action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        action.setCallback(this, function(response){
            let state = response.getState();
            if (state === "SUCCESS") {
                // do nothing!
            }
        });
        $A.enqueueAction(action);
    },

Dos cosas a tener en cuenta de forma inmediata. En primer lugar, excepto por los aspectos específicos de las devoluciones de llamadas, el método auxiliar updateExpense es idéntico al método auxiliar createExpense. Eso huele a oportunidad.

En segundo lugar acerca de los aspectos específicos de las devoluciones de llamadas. ¿Qué ofrecen? ¿Cómo puede ser lo correcto no hacer nada?

Piense en ello por un momento. Anteriormente, cuando se probaba el evento (si no antes), vimos que el color de expenseItem del componente cambió en respuesta a la alternancia de la casilla de verificación Reimbursed?. ¿Recuerda la explicación? La copia local del registro expense ya está actualizada. De modo que, al menos por el momento, cuando el servidor nos indica que la operación de actualización de su versión fue correcta, no tenemos que hacer nada.

Tenga en cuenta que este código solo gestiona el caso donde el servidor actualiza correctamente el registro de expense. Definitivamente tendremos que hacer algunas tareas si se produjo un error. Digamos que el departamento de contabilidad marcó este gasto como no reembolsable, lo que imposibilita establecer este campo como true. Pero eso, como se dice, es una lección para otro día.

Cambiar el tamaño de funciones auxiliares

Volvamos a esa oportunidad que vimos para reducir algo de código común. Las dos funciones auxiliares son idénticas excepto en la devolución de llamadas. De este modo, creemos una función nueva más generalizada que lleve la callback como un parámetro.

    saveExpense: function(component, expense, callback) {
        let action = component.get("c.saveExpense");
        action.setParams({
            "expense": expense
        });
        if (callback) {
            action.setCallback(this, callback);
        }
        $A.enqueueAction(action);
    },

El parámetro callback es opcional. Si está allí, lo pasaremos a action. Sencillo. Y ahora podemos reducir nuestras funciones auxiliares específicas de eventos al siguiente código.

    createExpense: function(component, expense) {
        this.saveExpense(component, expense, function(response){
            let state = response.getState();
            if (state === "SUCCESS") {
                let expenses = component.get("v.expenses");
                expenses.push(response.getReturnValue());
                component.set("v.expenses", expenses);
            }
        });
    },
    updateExpense: function(component, expense) {
        this.saveExpense(component, expense);
    },

createExpense es solo un poco más corto, pero está centrado exclusivamente en qué hacer cuando vuelve la respuesta (la devolución de llamada). Vaya, ¡updateExpense se quedó con una línea!

Cambiar el tamaño del formulario Add Expense

Ese pequeño ejercicio de cambio de tamaño fue tan satisfactorio y el uso de eventos fue tan electrizante (lo sentimos) que vamos hacerlo otra vez, pero a lo grande. ¡Más madera!

Esta nueva tarea lleva aparejada la extracción del formulario Add Expense desde el componente expenses y trasladarlo a su propio nuevo componente. La extracción de la marca del formulario es bastante sencilla, un sencillo ejercicio de copiar y pegar. ¿Pero qué más se traslada con él? Antes de que empecemos a trasladar partes alegremente, pensemos en lo que se traslada y en lo que se queda.

En el diseño vigente, el gestor de acciones del formulario, clickCreate, gestiona la validación de entrada, el envío de la solicitud al servidor y la actualización del estado local y los elementos de la interfaz de usuario. El formulario aún necesitará un gestor de acciones y probablemente seguirá gestionando la validación del formulario. Pero planificaremos dejar atrás el resto, porque estamos manteniendo nuestra lógica de solicitudes de servidor consolidada en el componente expenses.

Así que solo hay que trastear un poco (pero solo un poco) aquí. Entonces, nuestro plan es empezar a trasladar la marca del formulario, y luego trasladar lo menos posible para hacer que funcione correctamente. Cambiaremos el tamaño de ambos componentes para que se comuniquen a través de eventos, en vez del acceso directo al atributo de componente de la matriz expenses.

Vamos a empezar.

En el componente expenses principal, seleccione todo entre los dos comentarios <!-- CREATE NEW EXPENSE -->, incluyendo los comentarios de inicio y fin. Corte a su portapapeles. (Sí, corte. Estamos resueltos a ello.)

Cree un nuevo componente Aura y llámelo “expenseForm”. Pegue la marca del formulario Add Expense copiada en el nuevo componente, entre las etiquetas <aura:component>.

Vuelva al componente expenses. Agregue el nuevo componente expenseForm a la marca. Esa sección de expenses debería tener este aspecto.

    <!-- NEW EXPENSE FORM -->
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:expenseForm/>
        </lightning:layoutItem>
    </lightning:layout>

En este punto, puede volver a cargar su aplicación para ver los cambios. No debería haber cambios visibles. Pero, naturalmente, el botón Create Expense ya no funciona.

Pasemos rápidamente por el resto del traslado de cosas.

A continuación, traslade el atributo newExpense desde el componente expenses a la marca del componente expenseForm. Esto se utiliza para los campos de formulario, así que necesita estar en el componente del formulario. Se traslada sin necesitar otros cambios, de modo que solo corte de uno y pegue en el otro.

En el componente expenseForm, cree los recursos controlador y auxiliar.

Traslade el gestor de acciones clickCreate desde el controlador expenses al controlador expenseForm. El botón está en el componente del formulario, así que el gestor de acciones para el botón tiene que estar allí también. Créalo o no, esto tampoco necesita ningún cambio. (Puede que esto empiece a sonarle a una canción.)

Ahora sí que tenemos que realizar un par de cambios. Pero estará familiarizado con ellos, porque solo estamos incorporando el envío de eventos, que hicimos antes para expenseItem. Además, expenseItem también envía un evento con una carga expense, que está gestionada por el componente expenses.

En el auxiliar expenseForm, cree la función createExpense.

    createExpense: function(component, newExpense) {
        let createEvent = component.getEvent("createExpense");
        createEvent.setParams({ "expense": newExpense });
        createEvent.fire();
    },

Esto se parece mucho al gestor de acciones clickReimbursed en expenseItem.

Si un componente va a enviar un evento, necesita registrar el evento. Agregue lo siguiente a la marca del componente expenseForm, justo debajo del atributo newExpense.

    <aura:registerEvent name="createExpense" type="c:expensesItemUpdate"/>

En este punto realizamos todo el trabajo para implementar el componente expenseForm. Debería poder volver a cargar la aplicación, y el formulario “funcionará” ahora en el sentido de que no hay errores, y debería ver los mensajes de formulario apropiados cuando ingrese datos no válidos. Si está utilizando Salesforce Lightning Inspector, podrá ver incluso que el evento expensesItemUpdate se está desencadenando. Todo lo que resta es gestionarlo.

Antes de gestionar el evento, considere lo fácil que fue el cambio de tamaño. La mayoría del código no cambió. Hay un total de seis líneas de nuevo código y marca en los pasos anteriores. No estará familiarizado con este trabajo hoy, pero hágalo un par de veces y se dará cuenta que está moviendo algo de código.

Vale, finalicemos esto. expenseForm desencadena el evento createExpense, pero también necesitamos que el componente expenses lo capte. En primer lugar registramos el gestor de eventos createExpense y lo conecta con el gestor de acciones handleCreateExpense. Una vez más, esto es una sola línea de marca. Agregue esta línea justo encima o debajo del gestor de eventos updateExpense.

    <aura:handler name="createExpense" event="c:expensesItemUpdate"
        action="{!c.handleCreateExpense}"/>

Finalmente, como último paso, cree el gestor de acciones handleCreateExpense en el controlador expenses. Agregue este código justo encima o debajo del gestor de acciones handleUpdateExpense.

    handleCreateExpense: function(component, event, helper) {
        let newExpense = event.getParam("expense");
        helper.createExpense(component, newExpense);
    },

Sí, así de sencillo. Todo el trabajo se delega a la función auxiliar createExpense, que ni se trasladó ni cambió. Nuestro gestor de acciones handleCreateExpense está justo ahí para conectar las cosas adecuadas entre sí.

Y con ello terminamos de mostrarle como emparejar componentes inconexos empleado eventos. El evento se crea y desencadena en un componente y se captura y se gestiona en otro. ¡Circuitos sin cables!

Lección de bonificación: mejoras visuales menores

Antes de cabalgar hacia el crepúsculo, o mejor, al reto, aquí tiene una modesta mejora visual.

Nos gustaría mejorar un poco el formato de nuestra aplicación mediante la adición de unos cuantos componentes de contenedor. Esta última parte también le da una oportunidad de ver el componente expense completo después de todos nuestros cambios. En el componente expense, sustituya la marca expensesList por lo siguiente.

<lightning:layout>
    <lightning:layoutItem padding="around-small" size="6">
        <c:expensesList expenses="{!v.expenses}"/>
    </lightning:layoutItem>
    <lightning:layoutItem padding="around-small" size="6">
        Put something cool here
    </lightning:layoutItem>
</lightning:layout>

Los efectos de los cambios son la incorporación de algunos márgenes y espaciado interno, así como hacer que la lista de gastos sea más estrecha. El formato deja espacio para poner algo a la derecha. En la siguiente unidad sugeriremos un par de ejercicios que puede hacer usted mismo.