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

Introducir datos utilizando formularios

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Crear un formulario para mostrar valores actuales y aceptar nuevas entradas de usuario.
  • Leer valores desde elementos de formulario.
  • Validar entradas de usuario y mostrar mensajes de error para entradas no válidas.
  • Cambiar el tamaño del código desde el controlador de un componente a su auxiliar.

Introducir datos utilizando formularios

A partir de esta unidad, terminamos con los componentes de estilo helloLoquesea. A partir de aquí, estaremos creando y reuniendo las mini aplicaciones del rastreador de gastos que presentamos previamente antes. Emplearemos la mayor parte de esta unidad en crear y comprender el formulario que le permita crear un nuevo gasto.

El contenedor de la aplicación expenses

Pero antes de comenzar con esto, terminemos con la creación de componentes normales, o absolutamente feos. Lo primero que haremos, a continuación, es avanzar en el Salesforce Lightning Design System, o SLDS, y “activarlo” en nuestra aplicación. El modo en que haremos esto nos permitirá hablar un poco más de los contenedores de aplicación.

Nota

Nota

No trataremos el SLDS en sí en esta unidad o cualquier parte del resto del módulo. Nos centraremos aquí en agregarlo a una aplicación y luego en nuestro código de ejemplo utilizaremos las clases de SLDS, pero no las explicaremos en detalle. Consulte recursos para muchos de los diferentes modos de aprender más acerca de SLDS.

En la actualidad, SLDS está automáticamente disponible en sus componentes cuando se ejecutan en Lightning Experience o la aplicación Salesforce. En ocasiones llamamos esta ejecución en el contenedor one.app. Esta versión integrada es la misma que se utiliza por varios de los componentes Lightning estándar. Sin embargo, SLDS no está disponible de forma predeterminada en una aplicación independiente o cuando utiliza sus componentes en Lightning Out o Componentes Lightning para Visualforce. Existen diferentes contenedores de aplicación, y proporcionan diferentes servicios y recursos. Nos gustaría crear nuestra aplicación de gastos de un modo que funcione bien y tenga un buen aspecto en todos estos contextos. Y afortunadamente, no es realmente difícil de hacer.

La forma en que lo haremos es agregando SLDS a nuestra aplicación de aprovechamiento. A continuación, dentro de la aplicación de gastos “real” (realmente, el componente de nivel superior y todos sus componentes secundarios), podemos utilizar herramientas y técnicas de SLDS, sin preocuparnos de dónde proceden los recursos de SLDS (hojas de estilo, iconos, etc). Es decir, nuestro contenedor de aplicación (la aplicación de aprovechamiento) configura recursos dentro de su contexto de modo que cualquier aplicación que se ejecute dentro de ese contenedor tenga los recursos que necesita.

Convirtamos estos conceptos prolijos en código. Cree una nueva aplicación expensesApp.app de Lightning con la siguiente marca.

<aura:application extends="force:slds">
        <!-- This component is the real "app" -->
        <!-- c:expenses/ -->
</aura:application>

Esto es lo que sucederá. El atributo extends=”force:slds” activa SLDS en esta aplicación incluyendo los mismos estilos de Lightning Design System proporcionados por Lightning Experience y la aplicación Salesforce. Pero tenga en cuenta que esta aplicación de aprovechamiento es solo un contenedor, una pantalla. La aplicación real es el componente expenses, que no creamos. (Esa es la parte <!-- c:expenses/ -->; está comentada porque no podemos guardar nuestra aplicación hasta que exista realmente el componente expenses.)

A través de la aplicación contenedor, nuestros componentes utilizan el mecanismo extends=”force:slds” para obtener el acceso a SLDS cuando se ejecutan desde esta aplicación. Cuando se ejecutan en Lightning Experience o la aplicación Salesforce, sin cambios de código, utilizan la inclusión automática de SLDS de ese contenedor.

En este caso, asciende a lo mismo. Pero este concepto del uso de la aplicación de aprovechamiento externa para configurar un contexto de modo que la aplicación real no necesite preocuparse de las diferencias de contexto no está limitado a recursos de estilo. Puede utilizar esto para proporcionar los gestores de eventos de sustitución, por ejemplo, aunque no avancemos. ¡Aprendamos a andar antes de intentar volar!

El componente de la aplicación expenses

El siguiente paso es crear el componente que es el nivel superior para nuestra aplicación de gastos. (Recuerde, aunque la llamemos “aplicación”, es realmente solo otro componente Lightning.) En Developer Console, cree un nuevo componente Aura denominado “expenses” y sustituya la marca predeterminada por lo siguiente.

<aura:component>
    <!-- PAGE HEADER -->
    <lightning:layout class="slds-page-header slds-page-header_object-home">
        <lightning:layoutItem>
            <lightning:icon iconName="standard:scan_card" alternativeText="My Expenses"/>
        </lightning:layoutItem>
        <lightning:layoutItem padding="horizontal-small">
            <div class="page-section page-header">
                <h1 class="slds-text-heading_label">Expenses</h1>
                <h2 class="slds-text-heading_medium">My Expenses</h2>
            </div>
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / PAGE HEADER -->
    <!-- NEW EXPENSE FORM -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
        <!-- [[ expense form goes here ]] -->
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / NEW EXPENSE FORM -->
</aura:component>

Lo que estamos creando aquí es el encabezado de página que utiliza el formato de rejilla proporcionado por los componentes <lightning:layout> y <lightning:layoutItem>. size="6" crea un contenedor <div> que tiene el 50% de la anchura total (o tamaño de 6 de 12). Como puede observar, los componentes del espacio de nombres lightning se parecen a los componentes de Lightning Experience y la aplicación Salesforce. Además de los botones y formatos, encontrará muchos otros componentes útiles en este espacio de nombres que funcionan perfectamente con los estilos SLDS automáticamente.

Nota

Nota

¿Ha visto la etiqueta <lightning:icon>? Este componente representa sus iconos SLDS favoritos en un complemento. Ya no es necesario crear un componente auxiliar para mostrar los iconos SLDS.

Ahora puede retirar el comentario de la etiqueta <c:expenses/> en la .app actual y abrir la vista previa de lo que ahora es solo una pantalla vacía. Deberá ver algo similar a lo siguiente.

Formulario My Expenses básico

Todavía no pasan muchas cosas, pero es un poco emocionante ver el estilo SLDS tener ya un efecto. Recuerde que no explicaremos la mayoría de las marcas SLDS, pero incluiremos comentarios en la marca. Puede ver cómo creamos el encabezado para la aplicación y empezar a hacerse una idea.

El nuevo formulario de gasto

Antes de comenzar con el formulario, reconozcamos algo por adelantado: Lo que vamos a hacer es temporal. ¿Recuerda todo ese bla bla bla acerca de descomponer su aplicación en componentes separados más pequeños y luego desarrollar desde allí? No haremos eso aquí (no aún) y francamente, es un poco hacer trampa.

Pero es hacer trampa en el servicio para evitar que el código se complique demasiado, demasiado rápido. Lo estamos haciendo así de modo que podamos centrarnos en una sola lección a la vez. Además, no es una mala forma para que trabaje en cosas por sí mismo: crear dentro de un solo componente hasta que esté muy ocupado y luego cambiar el tamaño y descomponer en subcomponentes más pequeños. ¡Siempre que recuerde cambiar el tamaño!

Bien,  </sermoneo>. En componente expenses, sustituya el comentario <!-- [[ expense form goes here ]] --> por el siguiente código para el formulario Agregar gasto.

    <!-- CREATE NEW EXPENSE -->
    <div aria-labelledby="newexpenseform">
        <!-- BOXED AREA -->
        <fieldset class="slds-box slds-theme_default slds-container_small">
        <legend id="newexpenseform" class="slds-text-heading_small
          slds-p-vertical_medium">
          Add Expense
        </legend>
        <!-- CREATE NEW EXPENSE FORM -->
        <form class="slds-form_stacked">
            <lightning:input aura:id="expenseform" label="Expense Name"
                             name="expensename"
                             value="{!v.newExpense.Name}"
                             required="true"/>
            <lightning:input type="number" aura:id="expenseform" label="Amount"
                             name="expenseamount"
                             min="0.1"
                             formatter="currency"
                             step="0.01"
                             value="{!v.newExpense.Amount__c}"
                             messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
            <lightning:input aura:id="expenseform" label="Client"
                             name="expenseclient"
                             value="{!v.newExpense.Client__c}"
                             placeholder="ABC Co."/>
            <lightning:input type="date" aura:id="expenseform" label="Expense Date"
                             name="expensedate"
                             value="{!v.newExpense.Date__c}"/>
            <lightning:input type="checkbox" aura:id="expenseform" label="Reimbursed?"
                             name="expreimbursed"
                             checked="{!v.newExpense.Reimbursed__c}"/>
            <lightning:button label="Create Expense"
                              class="slds-m-top_medium"
                              variant="brand"
                              onclick="{!c.clickCreate}"/>
        </form>
        <!-- / CREATE NEW EXPENSE FORM -->
      </fieldset>
      <!-- / BOXED AREA -->
    </div>
    <!-- / CREATE NEW EXPENSE -->

Parece un montón de código que abarcar de una vez. No lo es. Si elimina la marca y las clases SLDS, este formulario se reduce a una serie de campos de entrada y un botón para el envío del formulario.

Este es el formulario resultante.

Nuevo formulario de gasto
Nota

Nota

<lightning:input> es como una navaja suiza para los campos de entrada con todas las ventajas de los estilos SLDS. Puede usarlo siempre que encuentre variantes del componente <ui:input>, como <ui:inputText>, <ui:inputNumber> y otros. Los componentes del espacio de nombres ui no incluyen estilos SLDS y se consideran componentes heredados.

Primero, observe que hemos creado varias instancias del componente <lightning:input> con tipos de datos específicos. Por lo tanto, cabe esperar que use type="date" con un campo de fecha, etc. Hay una amplia variedad de tipos además de los especificados y la mejor opción es que el tipo de componente se corresponda siempre con el tipo de datos. Si no especifica ningún tipo, se establece el texto como valor predeterminado. El motivo podría no ser obvio aún, pero lo será cuando pruebe esta aplicación en un celular: los componentes específicos de tipo pueden proporcionar widgets de entrada mejor adaptados al factor de forma. Por ejemplo, el selector de fecha está optimizado para ratón y punta del dedo, dependiendo de dónde acceda a él.

A continuación, observe que cada componente de entrada tiene una etiqueta establecida y que el texto de etiqueta se muestra automáticamente junto al campo de entrada. Existen algunos otros atributos que no hemos visto antes: required, placeholder, type, min y step. La mayoría de estos atributos son similares a los atributos HTML correspondientes. Por ejemplo, min especifica el valor mínimo para la entrada. Si no sabe para qué sirven, puede consultarlos en la Biblioteca de componentes Lightning. (Y volveremos a ese engañoso required.)

A continuación, existe un atributo aura:id establecido en cada etiqueta. ¿Para qué es eso? Establece un Id. único (a nivel local) en cada etiqueta a la que se agrega y ese Id. es cómo leeremos valores fuera de los campos de formulario. Todos los campos comparten el mismo Id. en este ejemplo para poder acceder a ellos como una matriz para la validación de campos. Averiguaremos cómo hacer eso en breve.

Atributos para objetos de Salesforce (sObjects)

Pero primero necesitamos echar un vistazo al atributo value. Cada etiqueta tiene un valor, establecido como una expresión. Por ejemplo, {!v.newExpense.Amount__c}. Desde el formato de la expresión, debería poder deducir algunas cosas.

  • v significa que esta es una propiedad del proveedor de valor de vista. Eso significa que es un atributo en el componente. (Que no creamos aún.)
  • Basándose en la notación de puntos, puede decir que newExpense es alguna clase de tipo de datos estructurados. O sea, newExpense en sí tiene propiedades. ¿O...campos?
  • Desde la “__c” que está al final de la mayoría de los nombres de propiedad, puede adivinar que se asignan de vuelta a campos personalizados, con mayor probabilidad en el objeto personalizado Expense.
  • O sea, newExpense es probablemente un objeto Expense.

Bien, no le hemos tratado aún. Esta es la definición actual del atributo, que debe agregar a la parte superior del componente, justo después de la etiqueta <aura:component> de apertura.

    <aura:attribute name="newExpense" type="Expense__c"
         default="{ 'sobjectType': 'Expense__c',
                        'Name': '',
                        'Amount__c': 0,
                        'Client__c': '',
                        'Date__c': '',
                        'Reimbursed__c': false }"/>

Lo que sucederá aquí es realmente muy sencillo. El atributo de nombre que ya conoce. Y el tipo es, naturalmente, el nombre de API de nuestro objeto personalizado. Hasta ahora, todo bien.

El atributo predeterminado no es nuevo, pero el formato de su valor lo es. Pero no debe ser muy difícil de abarcar. Es una representación JSON de un sObject, especificando el tipo del objeto (de nuevo, el nombre de API) y los valores para cada uno de los campos para establecer en él de forma predeterminada. En este caso, estamos básicamente estableciendo todo como una representación de un valor vacío.

Bien, ¡eso todo lo que necesita saber acerca de los sObjects! De aquí en adelante, el marco de Componentes Lightning le permitirá tratar newExpense, en JavaScript y en marcas, como si fuera un registro de Salesforce, aunque no lo estamos (aún) cargando desde Salesforce.

Gestionar el envío de formulario en un gestor de acciones

Tenemos un formulario. Justo ahora, si lo rellena y hace clic en el botón para crear un nuevo gasto, ¿qué sucede? A menos que se adelantara y ya lo haya creado, recibirá otro error acerca de una acción de controlador que no existe. Esto se debe a que ni el controlador ni el gestor de acciones especificados en <lightning:button> se han creado.

En Developer Console, haga clic en el botón CONTROLLER (Controlador) para el componente expenses para crear el recurso del controlador. Luego sustituya el código predeterminado por lo siguiente.

({
    clickCreate: function(component, event, helper) {
        let validExpense = component.find('expenseform').reduce(function (validSoFar, inputCmp) {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validExpense){
            // Create the new expense
            let newExpense = component.get("v.newExpense");
            console.log("Create expense: " + JSON.stringify(newExpense));
            helper.createExpense(component, newExpense);
        }
    }
})

Bien, todo esto es nuevo, así que echémosle un vistazo detenidamente. En primer lugar, tengamos en cuenta que esta función de gestor de acciones está básicamente dividida en tres secciones, o pasos:

  1. Configuración
  2. Procesar valores de formulario
  3. Si no hay errores, hacer algo

Esta estructura le puede resultar familiar, porque es una forma bastante fundamental de procesar ingresos del usuario en una aplicación Web. Echemos un vistazo a cada uno de los pasos para ver cómo funcionan en el componente Lightning.

Para la configuración, todo lo que hacemos es inicializar el estado de nuestra comprobación de errores. Es un indicador sencillo, ¿es éste un gasto válido? Cada vez que se llama al gestor de acciones clickCreate, partiremos del supuesto de que los datos del gasto son correctos y luego se invalidará si encontramos un problema. Este es un resumen de la marca validExpense con un valor inicial establecido en verdadero.

  • component.find('expenseform') obtiene una referencia a la matriz de los campos <lightning:input> que requieren la validación. Si el Id. es único, la referencia devuelve el componente. En este caso, el Id. no es único y la referencia devuelve una matriz de componentes.
  • El método reduce() de JavaScript reduce la matriz a un solo valor capturado por validSoFar, el cual es verdadero hasta que se encuentra un campo no válido, lo que cambia validSoFar a falso. Un campo no válido puede ser un campo obligatorio vacío o un campo con un número inferior al número mínimo especificado entre muchos otros.
  • inputCmp.get('v.validity').valid devuelve la validez del campo de entrada actual en la matriz.
  • inputCmp.showHelpMessageIfInvalid() muestra un mensaje de error para campos no válidos. <lightning:input> genera mensajes de error predeterminados que se pueden personalizar mediante atributos como messageWhenRangeUnderflow, el cual ya ha visto en el ejemplo de formulario de gastos.

Veamos algunos detalles interesantes. En helloMessageInteractive, no utilizamos find() para averiguar el texto de etiqueta del botón en el que se hizo clic. Eso es porque no lo necesitamos. Pudimos obtener una referencia a ese botón directamente, extrayéndolo del parámetro event utilizando event.getSource(). No siempre tiene ese lujo; no lo dude, es raro cuando todo lo que necesita de ingresos de usuario proviene únicamente del evento.

Por lo tanto, cuando su controlador necesita una forma de llegar a un componente secundario, primero establezca un aura:id en ese componente en marca y luego utilice component.find(theId) para obtener una referencia al componente en el momento de la ejecución.

Nota

Nota

component.find() solo le permite acceder al componente y sus componentes secundario desde el controlador y el auxiliar. No es una forma mágica de deambular por la jerarquía de componentes y leer o cambiar cosas. Recuerde, se supone que los componentes son autocontenidos o se comunican con... bien, llegaremos a eso.

La validación con <lightning:input> permite aprovechar la capacidad del elemento de entrada HTML subyacente para procesar los valores del formulario de modo que no tenga que realizar esta tarea en la mayoría de los casos. ¿Necesita validar un número de teléfono? Use type="tel" y defina el atributo pattern mediante una expresión regular. ¿Necesita validar un valor de porcentaje? Use type="number" con formatter="percent". ¿Necesita validar algo más? Deje que <lightning:input> haga el trabajo por usted.

Es cuando falla la validación que las cosas vuelven a estar interesantes. Cuando el usuario ingresa entradas no válidas, deseamos que sucedan dos cosas:

  1. No intentar crear el gasto.
  2. Mostrar un mensaje de error útil.

En primer lugar, establecemos la marca validExpense en falso si la validez del campo a la que hace referencia inputCmp.get('v.validity').valid se evalúa como falso. En segundo lugar, usamos los errores de validación incluidos o proporcionamos mensajes personalizados para los errores. En el formulario de gastos, el campo de nombre obligatorio muestra “Complete este campo” si el campo está vacío e intenta enviar el formulario. No obstante, puede proporcionar su propio mensaje personalizado mediante la especificación de messageWhenValueMissing="Did you forget me?".

Por el contrario, si el campo se valida, la marca validExpense se evalúa como verdadero y no se muestra ningún error.

Y con eso, estamos en el paso tres de la gestión de envío de formulario: ¡realmente creando el gasto! Como puede ver, para prepararse para eso, estamos obteniendo el objeto newExpense completo del atributo del componente: component.get("v.newExpense"). Esto nos proporciona una variable única que podemos utilizar para crear un nuevo registro de gastos.

Antes de llegar a eso, no obstante, aquí tiene una pregunta en la que pensar: ¿por qué no extraemos los valores de formulario de newExpense? ¿Obtener la variable estructurada una vez, al inicio del gestor de acciones y luego solo acceder a sus propiedades en vez de lo que podría ser una larga serie de llamadas de find().get()?

La razón es sencilla: porque necesitamos referencias a los campos individuales para poder establecer showHelpMessageIfInvalid() en ellos. También es recomendable validar los datos de formulario de la fila; su lógica de validación desconoce qué tipos de procesamiento pueden suceder en el objeto newExpense.

Crear el nuevo gasto

¿Recuerda que dijimos antes que colocar el formulario de gastos en el componente principal era un poco hacer trampa? Bien, esta próxima sección no obtiene el calificador “un poco”. Lo que estamos haciendo aquí es solo evitar a toda máquina la complejidad de crear realmente el registro. Y lo estamos evitando ahora porque es toda la unidad siguiente. Por lo tanto, envolvamos esta con algo sencillo, pero que nos siga mostrando algunos conceptos importantes.

Primero, creemos una ubicación para “almacenar” nuevos gastos. Simplemente crearemos una matriz de gastos solo local para fijarlos. En la parte superior de marca de componente expenses, justo antes del atributo newExpense, agregue un nuevo atributo expenses que fija una matriz de objetos de gastos.

    <aura:attribute name="expenses" type="Expense__c[]"/>

Todo lo que necesitamos hacer es actualizar la matriz expenses. Que, al parecer, es sencilla (en la versión tramposo-tramposo de nuestro formulario) y que ilustra otro concepto importante.

En nuestro controlador, ocultamos el trabajo de crear realmente el nuevo gasto detrás de esta llamada de función: helper.createExpense(component, newExpense). En el desarrollo de software, otra palabra para “ocultar” es abstraer. Además, estamos utilizando algo denominado un auxiliar para extraer nuestras trampas.

Tratamos los auxiliares brevemente antes y no trataremos detalles avanzados de los auxiliares en este módulo. Por ahora, digamos tres cosas acerca de los auxiliares:

  • El auxiliar de un componente es el lugar apropiado para colocar código para compartirlo entre varios gestores de acciones diferentes.
  • El auxiliar de un componente es un lugar perfecto para colocar detalles de procesamiento complejos de modo que la lógica de sus gestores de acciones permanezca clara y simplificada.
  • Las funciones del auxiliar pueden tener cualquier firma de función. O sea, no se ven limitados por el modo en que están los gestores de acciones en el controlador. (¿Por qué es así? Porque usted está llamando la función del auxiliar directamente desde su código. En cambio, el marco llama los gestores de acciones a través del tiempo de ejecución del marco.) Proporcionar siempre el componente como el primer parámetro en funciones del auxiliar es un convenio y mejor práctica.

Bien, pongámonos con ello. En Developer Console, haga clic en el botón HELPER (Auxiliar) para que el componente expenses cree el recurso del auxiliar asociado y luego sustituya el código de ejemplo con lo siguiente.

({
    createExpense: function(component, expense) {
        let theExpenses = component.get("v.expenses");
        // Copy the expense to a new object
        // THIS IS A DISGUSTING, TEMPORARY HACK
        let newExpense = JSON.parse(JSON.stringify(expense));
        theExpenses.push(newExpense);
        component.set("v.expenses", theExpenses);
    }
})

Por el momento, ignore la detestable parte de trucos. Las otras tres líneas de código ilustran un patrón común que vimos antes y que utilizará una y otra vez: obtener-procesar-establecer. Primero obtenemos la matriz de gastos del atributo expenses. Luego le agregamos el nuevo “registro” de gastos. Luego actualizamos (set) el atributo expenses con la matriz cambiada.

La referencia no es el conjunto

La novedad aquí es eso, por primera vez, estamos actualizando un conjunto, una matriz. Y si es un programador experimentado, probablemente esté pensando: “¿Por qué necesito el set() aquí?”

Eso es, component.get("v.expenses") obtiene una referencia a la matriz almacenada en el atributo component. component.set("v.expenses", theExpenses) simplemente establece el atributo component como la misma referencia. Vale, entremedias, los contenidos de la matriz se agregaron, pero el contenedor es el mismo: ¡la referencia a la matriz no cambió realmente! Entones, ¿por qué actualizarla?

Si tiene problemas para comprender lo que esto significa, agregue dos declaraciones de registro antes y después de las declaraciones importantes y vuelque los contenidos de theExpenses en la consola.

console.log("Expenses before 'create': " + JSON.stringify(theExpenses));
theExpenses.push(newExpense);
component.set("v.expenses", theExpenses);
console.log("Expenses after 'create': " + JSON.stringify(theExpenses));

Vuelva a cargar e inicie la aplicación, agregue al menos dos gastos y eche un vistazo a la estructura de theExpenses. Ahora comente la línea component.set() y hágalo de nuevo.

¿Qué...?.component.set() no afecta a theExpenses en absoluto. Pero Pero ¿Pero? ¿Qué hace realmente?

Está absolutamente en lo cierto formulando esta pregunta. Y la respuesta es: ¡magia!

Lo que component.set() hace aquí no es actualizar el valor del atributo expenses. Desencadena una notificación de que el atributo expenses cambió.

El efecto es que, en cualquier parte en su aplicación donde haya hecho referencia al atributo expenses en una expresión, el valor de esa expresión se actualiza y esa actualización se difunde en cascada en cualquier parte que se haya utilizado el atributo expenses. Y todos se actualizan para volver a representar basándose en los nuevos contenidos. Todo esto sucede en segundo plano, gestionado por el marco de Componentes Lightning, como parte de la conexión automática que se produce cuando utiliza {!v.expenses}. En una sola palabra, magia.

Para resumir, si esto fuera JavaScript normal, no necesitaría el component.set(). Con el fin de desencadenar efectos subyacentes creados en el modelo de programación de componentes Aura, lo hace. Si alguna vez escribe código de controlador o auxiliar, lo prueba y no sucede nada, asegúrese de haber realizado el component.set() obligatorio.

El “detestable truco” funciona en un problema similar con referencias. Para ver el problema, cambie la línea para eliminar las dos llamadas JSON y pruebe la aplicación. Verá lo que es el problema lo suficientemente rápido. Lo eliminaremos en la siguiente unidad y por lo tanto no lo volveremos a explicar.

Visualización de la lista de gastos

Por lo tanto, para todo lo que se dijo de la actualización “mágica” de todo lo que utiliza {!v.expenses}, adivine una cosa. Nada lo está utilizando, aún. Vamos a solucionar esto.

En Developer Console, cree un nuevo componente Aura denominado expenseItem y sustituya la marca predeterminada por lo siguiente. Si ya creó expenseItem, solo actualice la marca. Ya ha visto las expresiones que permiten el acceso a los campos de registro de gasto. Esta versión incluye la marca SLDS para mejorar el estilo.
<aura:component>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute name="formatdate" type="Date"/>
    <aura:attribute name="expense" type="Expense__c"/>
    <lightning:card title="{!v.expense.Name}" iconName="standard:scan_card"
                    class="{!v.expense.Reimbursed__c ?
                           'slds-theme_success' : ''}">
        <aura:set attribute="footer">
            <p>Date: <lightning:formattedDateTime value="{!v.formatdate}"/></p>
            <p class="slds-text-title"><lightning:relativeDateTime value="{!v.formatdate}"/></p>
        </aura:set>
        <p class="slds-text-heading_medium slds-p-horizontal_small">
           Amount: <lightning:formattedNumber value="{!v.expense.Amount__c}" style="currency"/>
        </p>
        <p class="slds-p-horizontal_small">
            Client: {!v.expense.Client__c}
        </p>
        <p>
            <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}"/>
        </p>
    </lightning:card>
</aura:component>
Observe que <lightning:card> asigna un tema SLDS cuando el campo del elemento de gasto ¿Reembolsado? está marcado: ¿{!v.expense.Reimbursed__c ? 'slds-theme_success' : ''}. Esta expresión le da control sobre la apariencia de los elementos de gasto reembolsados en la interfaz de usuario. Sin ninguna personalización posterior, los elementos de gasto aparecen con el estilo del componente expensesList que contiene los elementos de gasto. Para personalizar el componente expenseItem, haga clic en STYLE y agregue lo siguiente.
.THIS.slds-card.slds-theme_success {
    background-color: rgb(75, 202, 129);
}

A continuación, cree un controlador del lado del cliente expenseItemController.js con el siguiente código. Aquí convertimos la fecha devuelta por el servidor más adelante en un objeto de fecha de JavaScript para que se muestre correctamente <lightning:formattedDateTime> y <lightning:relativeDateTime>. Esta conversión se controla durante la inicialización de componentes y se captura mediante la etiqueta <aura:handler>. Este es un método útil para controlar el evento de inicialización y lo usaremos de nuevo más adelante al cargar datos de Salesforce.

({
    doInit : function(component, event, helper) {
        let mydate = component.get("v.expense.Date__c");
        if(mydate){
            component.set("v.formatdate", new Date(mydate));
        }
    },
})
En Developer Console, cree un componente Aura denominado expensesList y sustituya la marca predeterminada por lo siguiente.
<aura:component>
    <aura:attribute name="expenses" type="Expense__c[]"/>
    <lightning:card title="Expenses">
        <p class="slds-p-horizontal_small">
            <aura:iteration items="{!v.expenses}" var="expense">
                <c:expenseItem expense="{!expense}"/>
            </aura:iteration>
        </p>
    </lightning:card>
</aura:component>

No hay muchas novedades para usted aquí. Este es un componente que muestra una lista de gastos. Tiene un solo atributo, expenses, que es una matriz de objetos (Expense__c) expense. Y utiliza una <aura:iteration> para crear un <c:expenseItem> para cada uno de los objetos de gastos. El efecto en general es, como señalamos, mostrar una lista de gastos. Hasta ahora, todo bien.

Ahora agregue el componente expensesList al final del componente expenses. Agréguelo justo antes de la etiqueta </aura:component> de finalización en expenses.cmp.

<c:expensesList expenses="{!v.expenses}"/>

Si vuelve a cargar la aplicación, verá una sección Gatos debajo del formulario. (No está tan bien visualmente, pero es suficiente por ahora.)

¿Qué acabamos de hacer? Le agregamos el componente expensesList y pasamos el atributo expenses principal a él. Entonces, ahora la instancia de expenses que expensesList tiene es la misma que la sentencia de expenses que tiene el componente expenses. Existen referencias a la misma matriz de registros y a través de la magia de Componentes Lightning, cuando se actualiza la matriz principal de expenses, el componente expensesList “reconocerá” y volverá a representar su lista. ¡Hagamos la prueba!

Genial. Fue una unidad larga y toca un pequeño descanso. Levántese y camine unos minutos.

Luego vuelva y le mostraremos cómo guardar sus nuevos gastos en la realidad.