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

Atributos y expresiones

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Definir los atributos en sus componentes y pasar valores de atributos a componentes anidados.
  • Comprender la diferencia entre una definición de componente y una instancia de componente, así como crear múltiples instancias de un componente.
  • Crear expresiones básicas para mostrar valores cambiantes y calculados.
  • Crear expresiones condicionales para resultados dinámicos.

Atributos de componentes

Hasta este punto, aunque creamos un par de componentes y aprendimos bastante sobre la creación de aplicaciones con ellos (a un alto nivel), el código de computación que redactamos no hace mucho más de lo que hace el código HTML normal. Dicho de otro modo, los dos componentes que creamos dan como resultado el mismo texto estático, sin importar lo que hagamos. Podría poner una docena de ellos en la misma pantalla y todos harían siempre lo mismo.

Bastante aburrido, ¿verdad?

Para cambiar eso, necesitamos aprender dos cosas. En primer lugar, necesitamos aprender cómo activar un componente para aceptar datos cuando se crea. Esto es, necesitamos establecer valores en el componente. Hacemos esto empleando atributos.

(La segunda cosa que necesitamos aprender es cómo utilizar estos valores en la práctica para cambiar el comportamiento y los resultados de un componente. Haremos eso después de determinar los atributos.)

Los atributos en los componentes son como las variables de instancia en los objetos. Representan una forma de guardar valores que cambian, y un método para asignar un nombre a esos marcadores de valores. Por ejemplo, digamos que queremos escribir un componente helloMessage que imprime un mensaje personalizado. Podemos prever la incorporación de un atributo de mensaje a este componente para personalizar su resultado. Y luego podemos establecer ese mensaje cuando agreguemos el componente a nuestra aplicación, como lo siguiente.
<aura:component>
    <c:helloMessage message="You look nice today."/>
</aura:component>
Deseará agregar esto a su organización porque lo utilizaremos unas cuantas veces más a medida que avancemos. Pero si lo hace ahora obtendrá un error. ¿Por qué? Porque el componente helloMessage no existe aún. Salesforce valida su código conforme lo escribe. Si intenta guardar el código que sabe que no es válido (por ejemplo, hacer referencia a un componente no existente), obtendrá un error. Por lo tanto, averigüemos cómo crear helloMessage primero.

Puede establecer los atributos de un componente cuando lo crea, como hicimos en el ejemplo anterior. También puede cambiarlos durante el ciclo de vida de su componente, en respuesta a las acciones que realiza el usuario, o eventos que se producen en otro lugar, y así sucesivamente. Y también puede leer y utilizar los valores de los atributos de diversas formas. Las trataremos cuando lleguemos a las expresiones.

Por el momento, echemos un vistazo a cómo se definen los atributos para un componente. Un atributo se define utilizando una etiqueta <aura:attribute>, que requiere valores para los atributos name y type, y acepta estos atributos opcionales: default, description, required.

Vaya, ¡son muchas maneras de utilizar “atributo” en una frase! Es muy fácil confundirse aquí, porque tenemos tres conceptos diferentes con nombres similares. Seamos específicos:

  1. Un atributo de componente es donde puede almacenar un valor. En el ejemplo anterior, el componente helloMessage tiene un atributo de componente denominado message. La mayoría del tiempo hablamos de atributos de componentes.
  2. Define un atributo de componente empleando la etiqueta <aura:attribute>. Veremos un ejemplo de eso por un momento. Llamémoslos definiciones de atributo.
  3. La etiqueta <aura:attribute> en sí toma atributos cuando la utiliza. Por lo tanto, cuando define un atributo de componente utilizando la etiqueta <aura:attribute>, establece atributos en <aura:attribute> que especifican la “forma” del atributo de componente que está definiendo. Un momento, probemos de nuevo: agregue una definición de atributo de componente estableciendo los atributos en la definición del atributo. ¿La definición de atributo del atributo de componente toma atributos?

Así es, redactores. Intentemos resolver este problema de terminología con el mismo código.

Aquí esta el inicio de nuestro componente helloMessage:

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Hello! [ message goes here, soon ]</p>
</aura:component>

El componente helloMessage tiene un atributo de componente, y ese atributo se define estableciendo name y type del atributo. El nombre del atributo es message y, una vez aprendamos sobre las expresiones, así es como hará referencia a él. Aún solo da como resultado texto estático y HTML, pero nos estamos acercando a algo útil.

¿?

El otro atributo que utilizamos aquí es type y lo establecemos porque es obligatorio en una definición de atributo. Dice que el atributo message contiene una cadena, lo que tiene sentido. Hablaremos más sobre los tipos de datos de atributos, y las otras partes de las definiciones de atributos, pero primero aprendamos sobre las expresiones y hagamos que helloMessage haga algo de verdad.

Expresiones

En vez de perdernos de nuevo en palabras, profundicemos en hacer que helloMessage funcione como se espera.

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Hello! {!v.message}</p>
</aura:component>

¿Afecta esto al cambio climático o qué?

Estamos sacando el contenido de message empleando la expresión {!v.message}. Lo que es lo mismo, esta expresión hace referencia al atributo message. La expresión se evalúa y se resuelve en la cadena de texto que está almacenada en esos momentos en message. Y eso es lo que la expresión da como resultado en el cuerpo del componente.

Bueno… ¿qué demonios es una “expresión”?

Una expresión es básicamente una fórmula o un cálculo que coloca dentro de delimitadores de expresión (“{!” y “}”). De este modo, las expresiones tienen el siguiente aspecto:

{!<expression>}

La definición formal de una expresión intimida un poco, pero enunciémosla y luego la desarrollaremos: Una expresión es cualquier conjunto de valores literales, variables, subexpresiones o operadores que se pueden resolver en un solo valor.

Pues sí, básicamente una fórmula, parecida a lo que escribiría en un campo de cálculo, criterios de filtro o Visualforce. La fórmula o expresión puede contener una variedad de cosas. Los valores literales deberían ser obvios: son cosas como el número 42 o la cadena “Hola”. Las variables son cosas como el atributo message. Los operadores son cosas como +, -, etcétera, y las subexpresiones básicamente significan que puede utilizar paréntesis para agrupar cosas entre sí.

Probemos esto haciendo nuestra expresión un poco más compleja.

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>{!'Hello! ' + v.message}</p>
</aura:component>

Todo lo que hicimos fue mover la parte “Hola” del texto estático fuera de la expresión a texto literal dentro de la expresión. Nótese que empleamos el operador “+” para concatenar las dos cadenas entre sí. Esto puede parecer una diferencia bastante pequeña, pero mover el texto de saludo dentro de la expresión le permite utilizar etiquetas en vez de texto literal, lo que facilita la actualización (y la traducción) de sus componentes. Por ejemplo:

{!$Label.c.Greeting + v.message}

¿Se dio cuenta de lo que dejó fuera nuestra definición formal de las expresiones? Las llamadas de función de JavaScript. No puede utilizar JavaScript en expresiones en componentes Aura.

Una última cosa sobre las expresiones antes de avanzar. Puede pasarlas a otro componente para establecer el valor en dicho componente. Es un componente nuevo que se pasa en un valor personalizado al componente helloMessage. El paso del valor al otro componente reemplaza el valor de dicho componente.
<aura:component>
    <aura:attribute name="customMessage" type="String"/>
    <p> <c:helloMessage message="{!v.customMessage}"/> </p>
</aura:component>
.

Proveedores de valores

En realidad, tenemos que hablar sobre otro aspecto de las expresiones. En los ejemplos anteriores hicimos referencia al atributo de mensaje del componente helloMessage con v.message. ¿Qué es la parte “v.”?

v es algo denominado proveedor de valores. Los proveedores de valores son una forma de agrupar, encapsular y acceder a los datos relacionados. Los proveedores de valores son un tema complicado, así que por ahora, piense en v como una variable automática que está disponible para su uso. En nuestro componente, v es un proveedor de valores para la vista, que es el componente helloMessage en sí.

v le proporciona un “gancho” para acceder al atributo message del componente, y es la forma de acceder a todos los atributos de un componente.

Se accede a los valores de un proveedor de valores como propiedades denominadas. Para utilizar un valor, separe el proveedor de valores y el nombre de la propiedad con un punto. Por ejemplo, v.message, como vimos.

Cuando el atributo de un componente es un objeto u otros datos estructurados (o sea, no un valor primitivo), acceda a los valores de ese atributo empleando la misma notación de punto. Por ejemplo, {!v.account.Id} accede al campo Id de un registro de cuenta. Para objetos y atributos profundamente anidados, siga agregando puntos para atravesar la estructura y acceder a los valores anidados.

Tipos de datos de atributos

El acceso a datos estructurados es un buen tránsito a volver a hablar sobre los atributos, y específicamente acerca de tipos de atributos no primitivos. message es una cadena, pero existe un número de diferentes tipos de atributo.

  • Los tipos de datos primitivos, como booleano, fecha, fecha y hora, decimal, doble, entero, largo o cadena. Los sospechosos habituales en cualquier lenguaje de programación.
  • Objetos estándar y personalizados de Salesforce, como Cuenta o MyCustomObject__c.
  • Recopilaciones, como Lista, Mapa y Conjunto.
  • Clases de Apex personalizadas.
  • Tipos específicos de marco, como Aura.Component o Aura.Component[]. Estos son más avanzados de lo que llegaremos en este módulo, pero debe saber que existen.

A continuación mostramos sin accesorios el componente el expenseItem, que rellenaremos más tarde. Ilustra cómo se define un atributo para un objeto personalizado, y cómo acceder a los campos de un registro.

<aura:component>
    <aura:attribute name="expense" type="Expense__c"/>
    <p>Amount:
        <lightning:formattedNumber value="{!v.expense.Amount__c}" style="currency"/>
    </p>
    <p>
        Client: {!v.expense.Client__c}
    </p>
    <p>
        <lightning:input type="toggle"
                         label="Reimbursed?"
                         name="reimbursed"
                         checked="{!v.expense.Reimbursed__c}" />
     </p>
    <!-- Other markup here -->
</aura:component>

Este componente tiene un atributo, expense, que es el objeto personalizado que creamos muy atrás al comienzo de este módulo. La finalidad del componente es mostrar los detalles de un gasto mediante la referencia al campo en el registro Expense__c con la expresión {!v.expense.fieldName}. Estamos utilizando el componente <lightning:input> de type="toggle", que es una casilla en forma de elemento de alternancia para poder actualizar el valor en la interfaz de usuario más adelante.

Otros aspectos de las definiciones de atributos

Cuando se trata de atributos que establece en la etiqueta <aura:attribute>, a continuación se indica el resto de lo que tiene que saber.

  • El atributo default define el valor de atributo predeterminado. Se utiliza cuando se hace referencia al atributo y no estableció aún el valor del atributo.
  • El atributo required define si el atributo es obligatorio. El valor predeterminado es false.
  • El atributo description define un breve resumen del atributo y su uso.

El establecimiento del valor predeterminado para un atributo con un tipo de datos complejo puede ser complicado. Veremos un ejemplo más adelante, así que por ahora solo le avisamos.

Diversión con atributos y expresiones

Para ilustrar algunos conceptos adicionales sobre los atributos y las expresiones, creemos un componente muy tonto, helloPlayground, con la siguiente marca.

<aura:component>
    <aura:attribute name="messages" type="List"
        default="['You look nice today.',
            'Great weather we\'re having.',
            'How are you?']"/>
    <h1>Hello Playground</h1>
    <p>Silly fun with attributes and expressions.</p>
    <h2>List Items</h2>
    <p><c:helloMessage message="{!v.messages[0]}"/></p>
    <p><c:helloMessage message="{!v.messages[1]}"/></p>
    <p><c:helloMessage message="{!v.messages[2]}"/></p>
    <h2>List Iteration</h2>
    <aura:iteration items="{!v.messages}" var="msg">
        <p><c:helloMessage message="{!msg}"/></p>
    </aura:iteration>
    <h2>Conditional Expressions and Global Value Providers</h2>
    <aura:if isTrue="{!$Browser.isIPhone}">
        <p><c:helloMessage message="{!v.messages[0]}"/></p>
    <aura:set attribute="else">
        <p><c:helloMessage message="{!v.messages[1]}"/></p>
        </aura:set>
    </aura:if>
</aura:component>

Ahora agregue el componente helloPlayground a su aplicación de aprovechamiento y vea cómo se ejecuta.

Hay varias cosas nuevas aquí. No profundizaremos en ellas ahora mismo, pero las volverá a ver todas.

En primer lugar, helloPlayground tiene un atributo, messages, que es de un tipo de datos completo, Lista. Y tiene un valor predeterminado para esa lista, una matriz de tres cadenas con comilla simple separadas por comas. Además, en la sección List Items (Elementos de lista), puede ver cómo acceder a cada una de las cadenas empleando un índice.

¿Qué ocurre si alguien crea un <c:helloPlayground> con solo dos mensajes? El acceso al tercer elemento fallará, y aunque no provocará aquí una interrupción, con componentes más complejos podría hacerlo.

De modo que, en la sección List Iteration (Iteración de lista), puede ver una mejor manera de pasar por todos los elementos de la lista. El componente <aura:iteration> repite su cuerpo una vez por elemento en su atributo items, de modo que la lista se reduce o crece a medida que tengamos menos o más mensajes.

En la sección Conditional Expressions (Expresiones condicionales) y Global Value Providers (Proveedores de valores globales), puede ver una manera de elegir entre dos resultados posibles. El formato es un poco engorroso, porque esto es marca de computación en vez de, digamos, JavaScript, pero el componente <aura:if> le permite, por ejemplo, agregar un botón de modificación a una página solo si el usuario tiene privilegios de modificación sobre el objeto.

Finalmente, algo que es un poco menos obvio. En el caso de la programación orientada a objetos, hay una diferencia entre una clase y una instancia de dicha clase. Los componentes se relacionan con un concepto similar. Al crear un recurso .cmp, proporciona la definición (clase) del componente. Si incluye una etiqueta de componente en .cmp, crea una referencia (instancia) al componente.

No es de extrañar que podamos agregar varias instancias del mismo componente con distintos atributos. En el ejemplo anterior, cuando utiliza el valor predeterminado para mensajes, acabará con ocho referencias (instancias) a nuestro componente <c:helloMessage> . Si pasa en una lista mayor, podrá acabar con (muchos) más. ¡Todo ello procedente de nuestro pequeño componente!

Y con esto, amigo, creemos que está listo para algo de trabajo real.