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

Gestionar acciones con controladores

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Crear un controlador del lado cliente para gestionar acciones del usuario.
  • Leer valores desde atributos de componente.
  • Leer valores desde controles de interfaz de usuario en su componente.
  • Escribir código de controlador en JavaScript que cambia la interfaz de usuario.

Gestión de acciones con controladores

Hasta ahora, trabajamos solo con marcas de estilo XML. Hasta ahora, la única forma de que cambiara el resultado de nuestro componente era cambiando esa marca. Hasta ahora, nuestros componentes no reaccionaban a los ingresos del usuario. Hasta ahora, no hemos redactado nada de JavaScript.

Todo eso cambia en esta unidad.

Para comenzar, echemos un vistazo a un componente muy sencillo e imaginemos lo que necesita para poder gestionar su comportamiento sencillo.

Mensaje del día: Botón Tiene buen aspecto hoy, botón Hoy será un gran día

Este es helloMessageInteractive, y es difícil imaginar un componente más sencillo que “haga algo.” Es un poco de texto estático, un mensaje (actualmente en blanco) y dos botones. Este es el código:

<aura:component>
    <aura:attribute name="message" type="String"/>
    <p>Message of the day: {!v.message}</p>
    <div>
        <lightning:button label="You look nice today."
            onclick="{!c.handleClick}"/>
        <lightning:button label="Today is going to be a great day!"
            onclick="{!c.handleClick}"/>
    </div>
</aura:component>

Puede resultar familiar. Todo lo que hicimos realmente es agregar dos componentes <lightning:button> a helloMessage. Cuando hace clic en un botón, se actualiza el mensaje del día.

Bueno, aún no. Si ya ingresó el código y lo intentó por sí mismo, habrá observado que cuando hace clic en alguno de los botones, recibe un mensaje de error.

Existe un problema

Seremos los primeros en admitir que no todos los mensajes de error que verá en Componentes Lightning son tan útiles como puede esperar. ¡Pero este sí! Indica que no hay ninguna acción del controlador denominada “handleClick”. ¿De dónde procede “handleClick”? Procede de la expresión que asignamos al atributo onclick en cada una de las dos etiquetas <lightning:button>:

onclick="{!c.handleClick}"

Dado que este es un botón, puede probablemente adivinar que el atributo onclick es cómo asigna un comportamiento al botón para cuando se haga clic en él. ¿Pero qué asignamos? Una expresión, {!c.handleClick}, que es quizás algo misteriosa.

No obstante es bastante sencilla. Al igual que la expresión v.message de antes,c.handleClick es un proveedor de valores, c, con una propiedad, handleClick. c es el proveedor de valores para el controlador del lado del cliente del componente, y handleClick es una función definida en ese controlador. Por lo tanto, {!c.handleClick} es una referencia a un gestor de acciones en el controlador del componente.

c.handleClick: c es un proveedor de valores para el controlador del componente, con handleClick de la propiedad, una función definida en ese controlador

Ahh, ¿qué es un controlador?

¡Upsss! Un controlador es básicamente un conjunto de código que define el comportamiento de su aplicación cuando “suceden cosas”, a través de “cosas” queremos decir ingresos de usuario, temporizadores y otros eventos, actualizaciones de datos, etc. Si busca “Modelo-Vista-Controlador” en cualquier número de sitios de desarrollador, obtendrá varias definiciones. Para nuestros propósitos, para Componentes Lightning, un controlador es un recurso en un paquete de componentes que contiene los gestores de acciones para ese componente. Y los gestores de acciones son simplemente funciones de JavaScript con una firma de función concreta.

Más allá de los fundamentos

Hablamos mucho de controladores en esta unidad y sabemos que el componente en sí es una vista. Incluso mencionamos el MVC, o Modelo-Vista-Controlador, patrón de diseño bastante común en marcos de aplicaciones Web. ¿Componentes Lightning está creado en el patrón MVC?

En una sola palabra, no. Existen similitudes, para asegurarse, pero sería más correcto decir que Componentes Lightning es Vista-Controlador-Controlador-Modelo, o quizás Vista-Controlador-Controlador-Base de datos.

¿Por qué “controlador” aparece dos veces en ese nombre de patrón? Porque al interactuar con Salesforce, sus componentes tendrán un controlador del lado del servidor además del controlador del lado del cliente con el que trabajamos en esta unidad. Este diseño de controlador doble es la diferencia clave entre Componentes Lightning y MVC.

¿Cuál es la diferencia entre “modelo” y “base de datos”? En MVC tradicional, el modelo es una abstracción programática (normalmente, una clase) entre el almacenamiento de datos subyacente (habitualmente una base de datos relacional) y el resto de la aplicación. En Componentes Lightning, no existe una clase de Apex directamente entre los métodos de controlador @AuraEnabled y operaciones DML. Pero claro, los sObjects ya son una abstracción entre su código Apex y la capa de almacenamiento subyacente. Puede agregar campos de cálculo, lógica de validación e incluso agregar comportamientos completamente programáticos en la forma de desencadenadores. Por lo tanto, ¿es una base de datos o un modelo? Decimos ki-WI pero también es válido decir ki-VI.

¿Hecho un lío? ¿Entusiasmado? Se lo explicaremos en los detalles de controladores del lado de servidor en una unidad posterior.

Echemos un vistazo al controlador de helloMessageInteractive detalladamente y hagamos que esa explicación sea un poco más concreta.

({
    handleClick: function(component, event, helper) {
        let btnClicked = event.getSource();         // the button
        let btnMessage = btnClicked.get("v.label"); // the button's label
        component.set("v.message", btnMessage);     // update our message
    }
})

Los recursos de controlador tienen un formato interesante. Son objetos de JavaScript que contienen un mapa de pares de nombre-valor, donde el nombre es el nombre del gestor de acciones y el valor es la definición de una función.

Gestores de acciones

La combinación del par de nombre-valor y firma de función específica es un gestor de acciones. Oirá hablar o verá los términos gestor de acciones, acción de controlador y función de controlador utilizados indistintamente, y en gran parte es correcto. Casi siempre hacen referencia a lo mismo. (No nos preocuparemos de las excepciones en este módulo.)

No se preocupe demasiado del formato especial del recurso del controlador. Cuando hace clic en el botón CONTROLLER (Controlador) en Developer Console, obtendrá un recurso de controlador con un gestor de acciones de ejemplo ya agregado. El truco es (y recibirá errores de sintaxis si lo olvida) que necesita poner comas entre gestores de acciones. Esta es solo sintaxis básica de JavaScript y veremos las especificaciones en breve.

La función handleClick actual es solo cuatro líneas de código de computación, pero pueden parecer difíciles de comprender a primera vista. A un alto nivel, es sencillo: Cuando se hace clic en el botón, se llama su gestor de acciones (1). En el gestor de acciones, el controlador obtiene el botón en que se hizo clic, extrae el texto de etiquetas de él y luego establece el atributo message del componente a ese texto (2). Y se actualiza el mensaje del día (3). ¡Tiene buen aspecto hoy!

En el gestor de acciones, el controlador obtiene le texto del botón en que se hizo clic, luego establece el atributo de mensaje del componente.

Sencillo, ¿verdad? Bien...

Como esto es muy importante, desglosémoslo línea por línea.

handleClick: function(component, event, helper) {

El nombre del gestor de acciones, seguido por una declaración de función anónima. Lo importante aquí es la firma de función. Aunque no se requiera técnicamente, debe siempre declarar sus funciones del controlador para utilizar estos tres parámetros. Hablaremos más de ellos conforme avancemos, pero por ahora, estos parámetros representan:

  • component: el componente. En este caso, es helloMessageInteractive.
  • event: el evento que causó la llamada del gestor de acciones.
  • helper: el auxiliar del componente, otro recurso de JavaScript de funciones reutilizables.
    let btnClicked = event.getSource();         // the button

Recuerde que handleClick está conectado con nuestra etiqueta <lightning:button> y su atributo onclick. En el caso de event, alguien hace clic en el botón. En este evento se incluye la noción de una fuente, generada por el evento y que constituye el botón. Por lo tanto, la llamada a event.getSource() genera una referencia al <lightning:button> específico en el que se hizo clic.

    let btnMessage = btnClicked.get("v.label"); // the button's label

Qué hacemos ahora que tenemos una referencia al botón? Buscamos en él y obtenemos su etiqueta, que está establecida en el <lightning:button> en la marca del componente. Por ejemplo, <lightning:button label="Tiene buen aspecto hoy." ... >.

Pensemos en eso un poco más. No tenemos la definición de <lightning:button> delante, pero label solo es otro atributo, parecido al atributo message que agregamos a helloMessageInteractive. Puede llamar get() en cualquier componente y proporcionar el nombre del atributo que desea recuperar, en el formato v.attributeName. El resultado es el valor del atributo.

Recuerde que, al igual que en la marca del componente, v representa la vista, el componente en sí; pero en este caso, es el componente secundario <lightning:button> y no helloMessageInteractive. Piense en ello de este modo. btnClicked.get(”v.label”) avisa al componente btnClicked que sea y le dice “Oye, dame v.label”. Ese componente cree que “v soy yo”, busca dentro de sí mismo y devuelve el valor de su atributo de etiqueta.

Así que ahora que tenemos una cadena de texto recuperada desde el botón, nos queda un paso: cambiar nuestro atributo message al nuevo texto de mensaje. Naturalmente, justo cuando get() lee un valor desde un componente, set() escribe un valor.

    component.set("v.message", btnMessage);     // update our message

Sin embargo, observemos una importante diferencia. Llamamos a get() en btnClicked, el <lightning:button> que está dentro de helloMessageInteractive. Estamos llamando a set() en component: el componente helloMessageInteractive en sí. Este es un patrón que repetirá virtualmente en cada componente que cree: obtener valores de componentes secundarios, quizás realizar algún procesamiento y establecer los valores en el componente en sí.

El modelo de programación del controlador de vista de componentes Aura

De acuerdo, buen momento para comprobar. ¿Esto tiene sentido? ¿Seguro? Si lo cree, asegúrese de que haya creado realmente el componente helloMessageInteractive utilizando el código anterior. Es un solo componente, y copiar/pegar el código lleva dos minutos, pero poder utilizarlo es esencial para comprender acciones de gestión.

Lo que hizo aquí puede parecer muy sencillo, porque no hay muchas líneas de código. Pero estas líneas de código ilustran algunos de los conceptos fundamentales de la creación de aplicaciones con componentes Aura.

Puede pensar en buscar componentes en gestores de acciones como “activarlos”. Piense en helloMessageInteractive como un sencillo circuito eléctrico. Existen dos interruptores y existen bombillas. (El marco Componentes Lightning proporciona la energía.) Por sí solo, un interruptor puede emitir un agradable sonido al hacer clic, pero hasta que lo conecte, no es muy funcional. Puede tener la bombilla estilo Edison más vanguardista, pero hasta que no la conecta, no ilumina nada.

Y lo mismo sucede con componentes Aura. Vuelta atrás, dijimos que los diferentes recursos en un paquete de componentes se “conectan automáticamente” entre sí. Y es cierto: la conexión toma la forma de los proveedores de valores v y c. Se crean y se hacen disponibles automáticamente en sus componentes, por lo que su controlador puede hacer referencia al componente y viceversa. Pero esta conexión automática solo tiene lugar a alto nivel (en helloMessageInteractive), entre el recurso .cmp del componente y el recurso .js del controlador. Esta es la flecha verde en la siguiente ilustración.

helloMessageInteractive y su controlador se conectan automáticamente

La conexión para conectar un componente <lightning:button> específico a un gestor de acciones específico (o sea, conectar cosas que generan eventos, como botones, en las cosas que gestionan eventos, como una función de controlador específica) es la conexión que necesita hacer por sí mismo. Cosa que, de hecho, acaba de hacer usted mismo. Estas son las flechas rojas necesarias para completar un circuito de trabajo.

Agregar {!c.handleClick} al atributo onclick de un componente <lightning:button> (1) lo conecta al gestor de acciones específico. La llamada a component.set("v.message", newMessage) (2) conecta el resultado de ese controlador de acciones con el atributo message del componente. Este se conecta a su vez con la expresión {!v.message}.

Puede incluso pensar en el evento onclick como un electrón que fluye por el circuito que creó. Si no creó un circuito completo, el evento no irá a ninguna parte y no sucederá nada. Cuando empiece a escribir sus propios componentes, recuerde. ¿Tiene un circuito completo? ¿Está seguro? En caso de dudas, en ocasiones resulta de ayuda dibujarlo todo en una pizarra blanca o papel y confirmar cada conexión.

Conectará componentes, eventos y gestores, a niveles bajos y altos, por lo que en ocasiones se sentirá como un electricista. (O bien, adoptando el nombre del marco, quizás Benjamin Franklin.) Conectar las cosas entre sí es fundamental en el modelo de programación de componentes Aura.

Entonces, hagámoslo más. Después de todo, la práctica hace al maestro.

Concatenación, reconexión y depuración sencilla

Nuestra primera versión de handleClick era tres líneas de código, porque dividimos cada paso en el patrón obtener-procesar-establecer en líneas separadas. Puede utilizar algo denominado concatenación de función para contraerlas en menos líneas. Como habrá probablemente visto esto en otro código de Componente Lightning, démosle un giro nosotros mismos. Agregue el siguiente código adicional a su controlador helloMessageInteractive, después de handleClick.

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        component.set("v.message", newMessage);
    },
    handleClick3: function(component, event, helper) {
        component.set("v.message", event.getSource().get("v.label"));
    }

¡Vaaya! ¿Recibió un error de sintaxis al intentar guardar? ¿Recuerda cuando dijimos antes que necesita agregar comas entre sus gestores de acciones? Ese es el problema aquí. Agregue una coma después del corchete final (“}”) de handleClick, como puede ver al final de handleClick2 en el miniprograma anterior.

Estos gestores de acciones hacen exactamente lo mismo que handleClick, en menos líneas de código de computación. Hacen esto omitiendo variables intermedias, a menudo “concatenando” directamente con la siguiente llamada de función, agregando esa llamada al final de la anterior, separadas por un punto. (Este concepto es más claro al ver las diferencias entre handleClick y handleClick2.)

El estilo que prefiere es cuestión de gusto personal y quizás el estilo de codificación de su organización. Su humilde autor prefiere handleClick2, separando get y set, pero sin molestar con una variable para el botón, que solo necesitamos para su texto de etiqueta.

Por supuesto, no puede verificar que los nuevos gestores de acciones funcionan hasta que conecte un <lightning:button> para utilizar uno de ellos, estableciendo el atributo onclick como {!c.handleClick2} o {!c.handleClick3}. Piense en esto como desconectar los cables de una bombilla y luego conectarlos a una bombilla diferente. Es muy sencillo.

En ese punto, vuelve a cargar la aplicación, hace clic en uno de los botones reconectados y... bueno, es lo mismo en el diseño, ¿no? ¿Cómo podemos incluso distinguir a qué gestor de acciones se está llamando?

A veces, lo sencillo es siempre lo mejor. Incorporemos un poco de registro a una de las funciones del gestor de acciones:

    handleClick2: function(component, event, helper) {
        let newMessage = event.getSource().get("v.label");
        console.log("handleClick2: Message: " + newMessage);
        component.set("v.message", newMessage);
    },

Ahora, si conecta un <lightning:button> a handleClick2, verá un mensaje de registro en la consola de JavaScript de su navegador cada vez que haga clic en él.

Sí, existen herramientas de depuración más sofisticadas, pero la impresión en la consola es una técnica de depuración consagrada. Si desea que un objeto ofrezca resultados de algún tipo, inclúyalo con JSON.stringify(suObjeto para obtener detalles aún más útiles. Después de pasar por un vistazo rápido, console.log() es su amigo.

No trataremos estas técnicas y herramientas de depuración más sofisticadas aquí, pero vea Recursos para obtener algunas buenas herramientas e instrucciones.

Bueno, helloMessageInteractive era simplemente estúpido y tiene una actitud codificada (y constantemente positiva). En la siguiente unidad, trabajaremos con algo más complejo y obtendremos información acerca de cómo capturar ingresos reales del usuario. Y como las personas en el mundo real no son siempre positivas, obtendremos información acerca de cómo validar sus ingresos, también.