Eventos en Polymer

  • Por
Introducción a los eventos en Polymer, cómo trabajar con eventos, asociar eventos a componentes, declarar funciones manejadoras de eventos y primeros ejemplos.

Polymer, como cualquier otra librería que se ocupa del desarrollo de la parte del cliente, posee una nutrida cantidad de mecanismos para el tratamiento de eventos que veremos en este artículo y los siguientes del Manual de Polymer.

Como sabes, los eventos sirven para realizar acciones cuando ocurren cosas, pudiendo ser de la más diversa índole, como operaciones realizadas por el usuario sobre las distintas interfaces nativas, la misma ventana del navegador, así como sobre componentes Polymer. Del mismo modo, desde la librería podremos perfectamente detectar y asociar manejadores de eventos tanto para eventos clásicos de ratón o de teclado, así como eventos "touch" (de dispositivos táctiles).

Además en Polymer existe la posibilidad de crear eventos personalizados "custom events" que son eventos que no existen en Javascript tradicional y que creamos nosotros mismos para implementar en componentes. Este punto es fundamental, puesto que en el desarrollo de aplicaciones Polymer lo que desarrollamos casi exclusivamente son "custom elements", que habitualmente tienen que avisar a otros elementos cuando ocurren cosas con ellos. Mediante los mecanismos de binding y la creación de eventos personalizados es como básicamente se produce la interoperabilidad entre componentres.

Asociar un manejador de evento

Como manejador de evento se conoce a una función que se ejecutará cuando se produzca un evento determinado. En Polymer tenemos dos maneras de asociar un manejador a un evento, por medio de su declaración en el código HTML o directamente en un script Javascript. Esto es parecido al desarrollo Javascript tradicional, donde podemos especificar eventos con atributos de las etiquetas HTML (onclick, onchange…) o usar el método addEventListener() directamente desde un script Javascript, aunque habrán ligeras diferencias de trabajo.

Declaración de un evento en el template HTML:
En este caso colocamos un atributo para declararlo en la propia etiqueta del elemento cuyo evento queremos detectar. El nombre del atributo comienza por "on-" y a continuación va seguido del nombre del evento que queremos usar. Por ejemplo, "on-tap".

<div on-tap="manejadorDeEvento">

Como valor del atributo colocaremos el nombre de un método dentro de este componente, que tendrá el código a ejecutar cuando se produzca el evento.

Declaración de un evento en el registro del componente:
Al registrar el componente, en la función Polymer() indicamos diversas propiedades, entre las que se encuentra una llamada “listeners”. En ella como valor tenemos un objeto, notación JSON, en el que indicamos de una manera resumida todos los tipos de eventos y sus manejadores. La notación tiene un estilo como este:

listeners: {
    'tipoEvento': 'funcionManejadora',
    'identificador.tipoEvento': 'funcionManejadora'
}

En el código anterior encuentras dos alternativas, con o sin identificador. En el caso que no indicas identificador (primera declaración en listeners) se aplica el evento a todo el componente en global.

El "identificador" será el valor colocado en el atributo "id" del elemento sobre el que se quiere asociar el manejador. "tipoEvento" será la clase de evento que se desea detectar, "tap", "click"... Por último "funcionManejadora" será la el método que se encargará de procesar ese evento sobre el elemento.

Nota: La declaración del evento en el propio componente mediante la propiedad "listeners" o en el template HTML mediante su correspondiente atributo no altera en si el funcionamiento del componente. Por tanto, escoger uno u otro mecanismo es una cuestión de preferencia, y cómo guste a cada equipo de desarrollo ordenar el código de los componentes. Los hay que prefieren ver declarados los eventos en la propia etiqueta del HTML, para visualizar rápidamente qué eventos se activan en cada elemento o componente, y los hay que prefieren tenerlos todos ordenados en la propiedad listeners, de modo que su declaración no ensucie el template. En Javascript habitualmente se prefiere declarar los eventos en el script y no en el HTML, para no mezclar funcionalidad con el contenido, pero en Polymer mucha de la propia funcionalidad se escribe en el mismo HTML, como lo mecanismos de bindeo, por lo que en mi opinión no representa tanto desorden colocar los eventos en el template.

Escribir un manejador de evento

Ya a la hora de escribir el método que va a servir de manejador de evento se realizará como una propiedad del componente, cuyo valor será la función manejadora. El nombre del atributo será aquel nombre del manejador o nombre de la función, que hayamos declarado al definir el evento en el paso anterior. Como todas las propiedades de los componentes de Polymer, se declaran dentro de la función Polymer(), la misma que usamos para registrar el componente.

Polymer({
    manejador: function(){
        //código de nuestro manejador de eventos
    }
});

Como todos los eventos en Javascript, los manejadores reciben automáticamente un objeto evento, del que podemos obtener diversos tipos de informaciones sobre el evento que se acaba de producir. Por ejemplo, la posición del ratón (o el lugar de la pantalla donde se hizo tap) en el momento en el que se produzco el evento, si se había pulsado alguna tecla especial, etc. Ese objeto evento es nativo de Javascript, por lo que es probable que ya lo conozcas. Además contiene algunas propiedades adicionales que en ocasiones agrega la librería Polymer. Del objeto evento tendremos ocasión de hablar más adelante.

Dentro de una función manejadora de evento podemos acceder a todos los "ingredientes" de nuestro componente, para operar a nuestro gusto y realizar todo lo que se deba hacer. Podremos conocer el estado actual de sus propiedades, acceder a sus elementos HTML y otros componentes que contenga y manipularlos a placer.

  1. A las propiedades del componente se acceden con this: Es decir, todas las propiedades (tanto las declaradas como las no declaradas) del componente Polymer las tendremos disponibles mediante la palabra this, seguida del operador punto y el nombre de la propiedad. Por ejemplo:


  2. this.nombrePropiedad


  3. A los elementos del HTML, tanto los nativos como a otros componentes Polymer hijos del componente actual, se puede acceder mediante this.$, seguido del identificador del elemento. Lógicamente, siempre y cuando tengamos ese elemento con un atributo id definido. Esto es gracias a que Polymer de manera automática crea ya una especie de índice para acceder a los elementos del componente. Es algo muy útil porque el acceso desde el código de los métodos a los elementos del componente es una operación muy habitual. Por ejemplo, con un elemento definido así:


  4. <div id="mielemento">división</div>
    Accedemos por $ mediante esta notación:
    this.$.mielemento

Nota: A los elementos definidos dentro de un componente, el árbol de elementos del template del componente Polymer, se le conoce como "local dom". Con this.$ podremos acceder a los elementos que se hayan presentes dentro del template, en el código del componente. Pero en el caso que haya elementos dinámicamente generados (o elementos a los que no se les ha puesto un identificador) podremos también utilizar this.$$(selector), siendo "selector" cualquier selector disponible dentro de las CSS.

Ejemplo con eventos en Polymer

Para comenzar a ilustrar el trabajo con eventos vamos a realizar un pequeño ejemplo en el que definamos un manejador de evento "tap" sobre un elemento del componente. Nuestro ejemplo sería una especie de interruptor, para activar o desactivar una supuesta alarma.

Nuestro template tiene un icono con forma de alarma:

<template>
    <iron-icon icon="{{icono}}" on-tap="cambiaIcono"></iron-icon>
</template>

Como podrás observar, en el componente iron-icon tenemos definido un evento "on-tap". Ese evento, cuando se produzca, invoca un método llamado "cambiaIcono".

Además, para poder cambiar la forma del icono de alarma, para demostrar visualmente que la alarma está activada / desactivada, tenemos bindeada una propiedad llamada "icono" al atributo "icon". Cambiando esa propiedad cambiará el icono que se visualice.

Esta es la declaración para el registro de nuestro componente:

Polymer({
    is: 'alarma-on-off',
    properties: {
        icono: {
            type: String,
            value: 'icons:alarm-on'
        }
    },
    cambiaIcono: function(){
        if(this.icono == 'icons:alarm-on'){
            this.icono = 'icons:alarm-off';
        }else{
            this.icono = 'icons:alarm-on';;
        }
    }
});

La propiedad "icono" veremos que tiene como valor predeterminado el valor de un icono que muestra que está activada la alarma. Esta propiedad no es tan importante para el tema que nos ocupa, así que nos centraremos en el método definido después, cambiaIcono, que es nuestro manejador de evento.

Como ves, cambiaIcono contiene la función que se ejecutará cuando se produzca un "tap" sobre el icono. En realidad es un método muy simple, que solo comprueba el valor de nuestra propiedad para colocar otro valor diferente, así intercambiar el estado del icono entre la alarma activada / desactivada.

Ejemplo de declaración con Listeners

Ahora vamos a hacer unas pequeñas alteraciones a este componente para practicar con la declaración de manejadores mediante la propiedad "listeners". Además, por hacer algo nuevo, hemos agregado al template ahora un mensaje de texto que indicará si está o no está activa la alarma.

<template>
    <p>{{estado}}</p>
    <iron-icon icon="{{icono}}" id="elicono"></iron-icon>
</template>

La propiedad "estado" está bindeada dentro del párrafo y mantendrá una cadena con el estado de la alarma activa / desactivada. Fíjate que en el template ahora no tenemos ningún manejador declarado para los elementos, puesto que vamos a implementar la alternativa de definición con la propiedad "listeners". En cambio, ahora nuestro icono tiene un atributo "id", para que luego podamos referirnos a él desde la declaración del componente.

Ahora el registro del componente es el siguiente:

Polymer({
  is: "alarma-on-off",
  properties: {
    icono: {
      type: String,
      value: 'icons:alarm-on'
    },
    estado: {
      type: String,
      value: 'Activo'
    }
  },
  listeners: {
    'tap': 'tapComponente',
    'elicono.tap': 'cambiaIcono'
  },
  tapComponente: function(e){
    console.log('evento global:', e);
  },
  cambiaIcono: function(){
    if(this.icono == 'icons:alarm-on'){
      this.icono = 'icons:alarm-off';
      this.estado = 'Inactivo';
    }else{
      this.icono = 'icons:alarm-on';
      this.estado = 'Activo';
    }
  }
});

Entre las propiedades ahora hemos declarado un par de ellas. Tal como teníamos antes, "icono" guarda el icono que se debe mostrar. Además ahora también tenemos "estado", que contiene el texto explicativo del estado actual de la alarma.

Luego encuentras la declaración "listeners". En ella hemos definido dos manejadores de eventos, los dos para el evento "tap". Pero fíjate que uno afecta a todo el componente y otro solo al icono, al que nos referimos mediante su identificador.

Por último están definidos los métodos para los manejadores de eventos que vamos a usar. Los dos se pondrán en marcha cuando se produzcan los taps, sobre el componente de manera global y sobre el icono de manera particular.

El código de este segundo ejemplo completo lo encuentras en Github.

Con esto acabamos este primer artículo sobre los eventos en Polymer. Estamos seguros que contiene mucha información útil para ir creando tus componentes capaces de interactuar con el usuario por medio de eventos. Sin embargo hay cosas que todavía tenemos que tratar para completar este tema del manual. En el próximo artículo hablaremos de un asunto importante como son los eventos personalizados.

Autor

Miguel Angel Alvarez

Miguel es fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Comenzó en el mundo del desarrollo web en el año 1997, transformando su hobby en su trabajo.

Compartir