Crear un sistema de tags con JavaScript y Tagify

Crear un sistema para manejar tags en tus aplicaciones genera una mayor fidelización de tus usuarios. Aprende cómo hacerlo con la librería JavaScript Tagify.

https://yaireo.github.io/tagify/ “🔖 lightweight, efficient Tags input component in Vanilla JS / React / Angular / Vue.”

Hacia al final de éste post, he preparado un tutorial práctico para donde implementamos la librería. Haz click en la siguiente imagen para ver el ejercicio terminado en una ventana nueva:

Ejercicio con Tagify
Haz click sobre la imagen para abrir el ejercicio en una ventana nueva. Sistema de tags con Tagify y JavaScript

¿Quieres aprender a hacer este ejercicio? Saltar directamente al tutorial

La normalización del término «etiquetar»

Con el paso de los años, la tecnología ha provocado que ciertos conceptos revisen su significado, adaptándolos a la actualidad de cada momento. Por ejemplo, la idea de “etiquetar”, ha desarrollado toda una nueva dimensión de matices.

Aplicaciones como Instagram, han popularizado la funcionalidad de “etiquetar”, hasta el punto de convertirse en un sinónimo de interconexión, viralización o comunidad.

objetos etiquetados
objetos etiquetados

Etiquetar o “Taggear”, es algo tan común, que la mayoría de usuarios sabe hacerlo, sin necesidad de que se le explique cómo. Basta con mostrarle una interfaz gráfica, con la opción de incluir “tags”, e inmediatamente sabrá qué hacer.

Por consiguiente, es común incluir esta funcionalidad en el desarrollo de nuevas apps. Puede que incluso tú te plantees integrarlo en tu próxima app multiplataforma. Por cierto, si quieres saber más acerca de cómo crear apps multiplataforma a partir de tecnologia web, pincha en el siguiente enlace:

Crear apps multiplataforma con JavaScript y Capacitor

Sin embargo, no existe ningún “input” en el estándar web que resuelva ésta necesidad de forma completa. Algunos de los componentes de HTML5, permiten al usuario seleccionar uno o varios elementos dentro de una lista. O incluso, activar y desactivar “checkboxes” asociados a ítems personalizables.

Pero ninguno de estos elementos es suficientemente completo, como para resolver todo un sistema de etiquetado.

Por supuesto, aquí es donde entra Tagify Una librería JavaScript que permite crear un sistema de tags con JavaScript.

Una de las funcionalidades de Tagify permite combinar texto y tags
Ejemplo de la librería en marcha

Crear un sistema de tags con Tagify y JavaScript

Tagify es una herramienta en forma de librería JavaScript, que transforma un elemento HTML de tipo “input” o “textarea”,en un editor de etiquetas dinámico.

Esta librería fué creada por Yair Even Or, y su repositorio en Github tiene más de 2.5K estrellas. Tras instalarla mediante el comando “npm i @yaireo/tagify –save”, su peso no supera los 51.7Kb.

npm i @yaireo/tagify --save

La librería se encuentra activamente mantenida, y da soporte a frameworks como React, Vue o Angular. Sin embargo, hoy veremos cómo utilizarla directamente en JavaScript.

Para implementar Tagify, hay que importar la librería e instanciar un objeto de la clase con el mismo nombre. Al hacerlo, el constructor nos pide pasar un parámetro obligatorio. Se trata del elemento del DOM que actúa como “input” de texto o área de texto.

Solo con esto, la librería ya genera un sistema de etiquetas perfectamente funcional. En realidad, no haría falta nada más para crear un sistema de tags con JavaScript y Tagify

Pero la librería también admite un segundo argumento opcional. Este parámetro es un objeto JavaScript para definir opciones de configuración. Entre las múltiples opciones, encontramos algunas muy interesantes. 

Como por ejemplo “duplicates”, una booleana para decidir si permitimos que una etiqueta se pueda repetir o no. También existe “pattern”, para incluir un “Regex” que defina qué patrón deben cumplir las etiquetas. O los parámetros “whitelist” y “blacklist”, dos arrays para controlar qué “tags” se permiten, o cuáles se excluyen.

Se pueden ver el resto de opciones, en el enlace a su repositorio de Github: https://github.com/yairEO/tagify/blob/master/src/parts/defaults.js#L1

Tagify, también dispone de un conjunto de métodos, para controlar el comportamiento una vez creado el objeto de la clase.

https://github.com/yairEO/tagify#methods

En la documentación se pueden ver todos los métodos disponibles. Pero a continuación destacaremos algunos de los más relevantes.

Tal como su nombre sugiere “removeAllTags()”, elimina todas las etiquetas entradas en el input. Por supuesto, si existe un método para eliminar “tags”, también existe uno para añadir nuevos, “addTags()”.

Con el método “getInputValue()” se puede recuperar el valor del input en un momento determinado.

Y mediante el método “on()” es posible escuchar los siguientes eventos, y asociar funciones de callback a ellos.

https://github.com/yairEO/tagify#events

Vamos a crear una aplicación para añadir tags a películas

Como véis, es una librería realmente completa, y ofrece mucho más de lo que parece a simple vista. Por eso, a continuación implementaremos un pequeño ejercicio para tratar de conocerla un poco mejor.

Crearemos una sencilla aplicación web, donde el usuario podrá asignar tags a películas que se le irán sugiriendo.

Como es habitual, empezaremos por la parte de la estructura HTML. Esta se compondrá de dos secciones. 

En la primera dejaremos a punto los contenedores para el título de cada película. Un “iframe” para cargar un video. Un “input” que utilizaremos para cargar Tagify. Y un botón para guardar cada película etiquetada.

  <h1 class="text-center">Etiqueta las películas</h1>
    <div class="current-movie">
      <h2 class="movie-title text-center"></h2>
      <iframe src="" frameborder="0" class="gif-iframe-container"></iframe>
      <div>
        <input
          type="text"
          class="input-tagify"
          placeholder="Añade algunos tags"
        />
      </div>
      <div class="text-center">
        <button class="btn btn-save" type="button">Guardar</button>
      </div>
    </div>

En la segunda parte, solo prepararemos un listado, sobre el que iremos mostrando las películas guardadas y sus tags.

    <div class="movies-list-container">
      <ul></ul>
    </div>

Una vez creado el “layout” base, definiremos los estilos con SCSS.

Para ello, primero cargaremos una tipografía de Google Fonts. Los estilos SCSS de la librería Tagify. Y unos colores personalizados.

@import url("https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@200;600&display=swap");
@import "@yaireo/tagify/src/tagify.scss";
@import "./colors.scss";

Seguidamente, definiremos los estilos CSS para cada una de las clases que aparecen en el HTML.

* {
  box-sizing: border-box;
}
h1 {
  font-family: "Nunito Sans", sans-serif;
  font-weight: 600;
  font-size: 2.5rem;
  color: $mainColor;
  margin-bottom: 1rem;
}
h2 {
  font-weight: 100;
  font-size: 1.5rem;
  color: $mainColor;
  margin-bottom: 1rem;
}
body {
  font-family: "Nunito Sans", sans-serif;
  margin: 0;
  padding: 20px 0 20px 0;
  background-color: rgb(240, 240, 240);
}
.text-center {
  text-align: center;
}
.btn {
  border: none;
  padding: 15px 40px;
  cursor: pointer;
  background-color: $mainColor;
  color: $lighterMainColor;
  border-radius: 3px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
  &[disabled] {
    cursor: not-allowed;
  }
}
.current-movie {
  .gif-iframe-container {
    background-color: black;
    display: block;
    width: 100%;
    max-width: 700px;
    height: 400px;
    margin: 0 auto 20px auto;
  }
}
.input-tagify {
  background-color: rgb(193, 193, 193);
  padding: 20px;
  min-height: 38px;
  margin-bottom: 20px;
}
.movies-list-container {
  ul {
    list-style: none;
    padding: 0 20px 0 20px;
    display: flex;
    flex-wrap: wrap;
    li {
      width: 23%;
      margin: 0 1% 10px 1%;
      background-color: $mainColor;
      padding: 0 5px 10px 5px;
      border-radius: 3px;
      box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
      h3 {
        color: $lighterMainColor;
      }
    }
  }
}
// Media queries
@media screen and (max-width: 768px) {
  .movies-list-container {
    ul {
      li {
        width: 48%;
      }
    }
  }
}

Antes de empezar a programar el script, es importante preparar un archivo con los datos de las películas.

En el archivo movies.js definiremos una array de 8 películas. Cada una tendrá su título, un gif, y algunos tags a modo de sugerencias.

export const movies = [
  {
    title: "Lord of the rings",
    gif: "https://giphy.com/embed/BZMggpshzrPvbfQHIF/",
    suggestedTags: ["No puedes pasar!", "Mi tesoro...", "Sr Frodo"],
  },
  {
    title: "Star Wars",
    gif: "https://giphy.com/embed/3ornjSL2sBcPflIDiU",
    suggestedTags: ["Sables láser", "Ciencia ficción", "Yo soy tu padre"],
  },
  {
    title: "Jurassic Park",
    gif: "https://giphy.com/embed/hu1TLAaubiak9S4GT6",
    suggestedTags: ["Live finds a way", "Velociraptors"],
  },
  {
    title: "Little Miss Sunshine",
    gif: "https://giphy.com/embed/ThMIpSgPVFS12",
    suggestedTags: ["Roadmovie", "Steve Carell"],
  },
  {
    title: "Inception",
    gif: "https://giphy.com/embed/mSf4QMJjbvJYI",
    suggestedTags: ["Leo DiCaprio", "Sueños", "Espectacular"],
  },
  {
    title: "Batman",
    gif: "https://giphy.com/embed/EMpPEre2PqFy8GkOZE",
    suggestedTags: ["I am Batman", "2022"],
  },
  {
    title: "The Shinning",
    gif: "https://giphy.com/embed/4m7zfhchURMRO",
    suggestedTags: ["Nicholson", "Ven a jugar con nosotras Danny", "Redrum"],
  },
  {
    title: "Nightmare before christmas",
    gif: "https://giphy.com/embed/yidUzHwwoFalzhyKXu",
    suggestedTags: ["Jack Skellington", "Stop Motion", "Halloween"],
  },
];

El siguiente paso es programar el comportamiento de nuestra aplicación web. Empezaremos por importar la librería, los datos de las películas y los estilos.

import Tagify from "@yaireo/tagify";
import { movies } from "./movies";
import "./SCSS/index.scss";

Seguidamente, guardamos referencias a distintos elementos del DOM para tener acceso a ellos más tarde.

const currentMovieContainer = document.querySelector(".current-movie");
const gifIFrameContainer = currentMovieContainer.querySelector(
  ".gif-iframe-container"
);
const movieTitleContainer = currentMovieContainer.querySelector(".movie-title");
const moviesListContainer = document.querySelector(".movies-list-container ul");
const btnSave = document.querySelector(".btn-save");

Declaramos una variable tagify, y guardamos en ella una instancia de la clase Tagify pasándole una referencia al input.

Adicionalmente, creamos una variable “i” para controlar el índice del array de películas sobre el que el usuario interactúa en cada momento.

const tagify = new Tagify(document.querySelector(".input-tagify"));
let i = 0;

La primera función que creamos es “buildMovieTemplate”. Esta función se encargará de crear un elemento “li”, y rellenarlo con los datos de la película y los tags elegidos por el usuario.

const buildMovieTemplate = (movie, tags) => {
  const li = document.createElement("li");
  li.innerHTML = `
    <div>
      <h3 class="text-center">${movie.title}</h3>
      <input type="text" value="${tags
        .map((tag) => tag.value)
        .join(",")}" disabled />
    </div>
  `;
  return li;
};

En “saveCurrentMovie” ejecutaremos las siguientes instrucciones. Obtener los tags generados por el usuario. Crear el elemento “li” llamando a “buildMovieTemplate” e incluirlo en la lista. Ejecutar una nueva instancia de Tagify para el input dentro del “li”. Y finalmente resetar el objeto “tagify”.

const saveCurrentMovie = (newMovieData) => {
  let tags = tagify.getInputValue();
  const liElement = buildMovieTemplate(
    newMovieData,
    tags ? JSON.parse(tags) : []
  );
  moviesListContainer.appendChild(liElement);
  new Tagify(liElement.querySelector("input"), {});
  tagify.removeAllTags();
  tagify.DOM.input.focus();
};

A continuación, declaramos “loadMovie”, que recibirá los datos de una película. Dentro de esta función, cargaremos las etiquetas sugeridas, y actualizaremos el título y el gif a mostrar en pantalla.

const loadMovie = (newMovieData) => {
  tagify.addTags(newMovieData.suggestedTags);
  gifIFrameContainer.setAttribute("src", newMovieData.gif);
  movieTitleContainer.innerHTML = newMovieData.title;
};

Finalmente, escucharemos el evento “click” sobre el botón. Dentro del “callback” lanzamos el método “saveCurrentMovie” pasándole los datos de la película en cada momento. 

También comprobamos si existen más películas para el siguiente click. En caso de que no sea así, actualizamos la vista acorde. En caso de que sí, actualizamos la variable “i” cargando una nueva película con “loadMovie”.

btnSave.addEventListener("click", () => {
  saveCurrentMovie(movies[i]);
  if (i >= movies.length - 1) {
    movieTitleContainer.innerHTML = "";
    gifIFrameContainer.parentNode.removeChild(gifIFrameContainer);
    btnSave.setAttribute("disabled", "");
    tagify.setDisabled(true);
    return;
  }
  loadMovie(movies[++i]);
});
loadMovie(movies[i]);

Librerías JS que mejoran la UI/UX

Con este ejemplo hemos conseguido crear un sistema de tags con JavaScript y Tagify. No es la primera vez que vemos un ejemplo de librería que resuelve muy bien una necesidad de UI/UX. En otra ocasiones, vimos como JavaScript también nos puede ayudar a construir «layouts» enteros, o agregar la funcionalidad de copiador automático en botones.

Crear layouts Masonry con MiniMasonry.

Copiar en el portapapeles con JavaScript y ClipboardJs

Tal y como hemos visto, Tagify sorprende por la enorme cantidad de opciones que ofrece.

Pero hay un aspecto igual de importante que quizá pase más desapercibido. Esta librería no solo resuelve una necesidad de UI sinó que además lo hace con estilo.

Mediante pequeñas animaciones y cambios de estado, consigue que la experiencia de usuario sea mucho más rica y agradable. Sin duda, se convierte en una de esas herramientas que como desarrolladores vamos a tener en cuenta para futuros proyectos.

Este ha sido un pequeño vistazo a la librería Tagify. A continuación os dejo enlaces a más recursos, así como el ejercicio subido al repositorio de Github de “Librerías Js”:

Nos vemos pronto, un abrazo desarrolladores!

Deja un comentario