Unlimited Wordpress themes, plugins, graphics & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Web Design
  2. JavaScript

Cómo crear una aplicación de tareas pendientes con JavaScript puro (y almacenamiento local)

by
Difficulty:AdvancedLength:LongLanguages:

Spanish (Español) translation by Ana Paulina Figueroa Vazquez (you can also view the original English article)

En este tutorial, mejoraremos nuestras habilidades en el front-end aprendiendo a crear una aplicación de tareas pendientes "hecha a mano". Para crearla no aprovecharemos ningún framework de JavaScript; solamente usaremos HTML, CSS y JavaScript puro.

Lo que vamos a construir

Este es un video introductorio que demuestra la funcionalidad de la aplicación JavaScript que vamos a crear. Los usuarios podrán agregar tareas, marcarlas como terminadas y eliminarlas. Los totales de las tareas y sus estados se mostrarán en la barra de estado:

Aquí está la demostración en Codepen para que la bifurques y juegues con ella:

Nota: este no es un tutorial introductorio. Este asume que estás familiarizado con habilidades esenciales del front-end como CSS Grid, flexbox, ES6, arreglos de JavaScript, etc. Además, para esta demostración, hacer que la aplicación sea totalmente accesible no es una prioridad.

1. Comienza con los recursos necesarios

Para que el diseño sea un poco más único, usaremos algunas ilustraciones SVG hechas a mano y una fuente personalizada tomada de Envato Elements.

SUMMER - FONT PACK
SUMMER - FONT PACK en Envato Elements

Vale la pena señalar que la mayoría de estos recursos provendrán de un tutorial anterior. De hecho, también usaremos muchas de las técnicas de posicionamiento que aprendimos en este tutorial, así que vale la pena leerlo.

How to Build a Responsive Handmade SVG Form


2. Continúa con el marcado de la página

Comenzaremos con un SVG y un contenedor div:

Sprites de SVG

Como lo hemos hecho muchas veces en el pasado, y como una práctica recomendada, vamos a almacenar todos los SVGs como symbols en un contenedor de tipo sprite de SVG. Después, los desplegaremos en la pantalla cada vez que sea necesario llamando al elemento use.

Este es el marcado para el sprite de SVG:

Observa el atributo preserveAspectRatio="none" que adjuntamos a la mayoría de las ilustraciones. Hemos hecho esto porque, como veremos más adelante, nuestros iconos cambiarán de escala y perderán sus dimensiones iniciales.

Contenedor

El contenedor incluirá un formulario, un elemento div y una lista ordenada vacía:

Dentro del formulario, tendremos un campo de entrada y un botón de envío junto con sus SVGs asociados:

Observa el atributo name que hemos agregado al campo de entrada. Más adelante usaremos este atributo para acceder al valor de la entrada después del envío del formulario.

Nota: en nuestra demostración, el atributo autofocus del campo de texto no funcionará. De hecho mostrará el siguiente error, que puedes ver si abres la consola de tu navegador:

The cross-origin error due to the autofocus attribute

Sin embargo, si ejecutas esta aplicación localmente (no como un proyecto de Codepen), este problema no existirá. Alternativamente, puedes establecer el foco a través de JavaScript.

Dentro del div, colocaremos tres divs anidados y el SVG asociado. En esta sección llevaremos a cabo un seguimiento de la cantidad total de tareas (tanto restantes como terminadas):

Finalmente, los elementos de la lista ordenada serán agregados de forma dinámica a través de JavaScript.

3. Define algunos estilos básicos

Con el marcado listo, continuaremos con algunos estilos de restablecimiento:


4. Establece los estilos principales

Ahora discutamos los estilos principales de nuestra aplicación.

Estilos del contenedor

El contenedor tendrá un ancho máximo, y el contenido estará centrado horizontalmente:

Estilos del formulario

En pantallas pequeñas, todos los elementos del formulario se apilarán:

The form layout on small screens

Sin embargo, en las ventanas de 600 píxeles de ancho o más, el diseño del formulario cambiará de la siguiente manera:

The form layout on medium screens and above

Tomemos nota de dos cosas:

  • En las ventanas anchas, el tamaño del campo de entrada será el doble del tamaño del botón.
  • Los SVGs serán elementos con posiciones absolutas y se ubicarán debajo de sus controles adyacentes en el formulario. Nuevamente, para obtener una explicación más detallada, echa un vistazo a este tutorial anterior.

Estos son los estilos para esta sección:

Estilos de las estadísticas

A continuación veamos la barra de estado, que nos dará un informe rápido sobre la cantidad total de tareas.

En pantallas pequeñas tendrá la siguiente apariencia apilada:

The stats layout on small screens

Sin embargo, en ventanas de 600 píxeles de ancho o más debería cambiar de la siguiente forma:

The stats layout on medium screens and above

Tomemos nota de dos cosas:

  • En las ventanas anchas, todos los elementos div hijos tendrán el mismo ancho.
  • De manera similar a los SVGs anteriores, este también tendrá una posición absoluta y actuará como una imagen de fondo que cubre toda la sección.

Los estilos relacionados:

Estilos de las tareas

El diseño de las tareas, que generaremos de forma dinámica en la próxima sección, se verá de esta forma:

The tasks layout

Cada tarea, que se representará por un li, tendrá dos partes.

The markup representation of a task

En la primera parte verás una casilla de verificación junto con el nombre de la tarea. En la segunda parte verás un botón de eliminación para borrar la tarea.

Estos son los estilos relacionados:

Cuando una tarea está incompleta, aparecerá una casilla de verificación vacía. Por otro lado, si una tarea está marcada como terminada, aparecerá una marca de verificación. De manera adicional, su nombre adquirirá una opacidad del 50% además de una línea atravesándolo.

Estos son los estilos responsables de este comportamiento:

Finalmente, a continuación puedes ver los estilos del botón para eliminar:


5. Agrega el código JavaScript

En este punto, estamos listos para crear la funcionalidad principal de nuestra aplicación. ¡Hagámoslo!

Al enviar el formulario

Cada vez que un usuario envíe el formulario, ya sea presionando la tecla Enter o el botón Submit (Enviar), haremos lo siguiente:

  1. Detendremos el envío del formulario, para evitar así una recarga de la página.
  2. Tomaremos el valor contenido en el campo de entrada.
  3. Suponiendo que el campo de entrada no está vacío, crearemos un nuevo literal de objeto que representará a la tarea. Cada tarea tendrá un id único, un nombre, y estará activa (no terminada) de forma predeterminada.
  4. Agregaremos esta tarea al arreglo tasks.
  5. Guardaremos el arreglo en el almacenamiento local. El almacenamiento local solamente admite cadenas, por lo que, para hacer eso, tenemos que usar el método JSON.stringify() para convertir los objetos del interior del arreglo en cadenas.
  6. Llamaremos a la función createTask() para representar visualmente la tarea en la pantalla.
  7. Limpiaremos el formulario.
  8. Asignaremos el foco al campo de entrada.

Este es el código correspondiente:

Crea una tarea

La función createTask() será responsable de la creación del marcado de la tarea.

Por ejemplo, esta es la estructura de la tarea "Salir a caminar":

The markup structure for a task

Aquí hay dos cosas importantes:

  • Si la tarea ha sido terminada, aparecerá la marca de verificación.
  • Si la tarea no ha sido terminada, su elemento span recibirá el atributo contenteditable. Este atributo nos dará la posibilidad de editar o actualizar su nombre.

A continuación se muestra la sintaxis de esta función:

Actualiza una tarea

Una tarea puede actualizarse de dos formas diferentes:

  • Cambiando su estado de "no terminada" a "terminada" y viceversa.
  • Modificando su nombre en caso de que la tarea no haya sido terminada. Recuerda que, en este caso, el elemento span tiene el atributo contenteditable.

Para hacer un seguimiento de estos cambios aprovecharemos el evento input. Este es un evento aceptable para nosotros, ya que se aplica tanto a los elementos input como a los elementos con contenteditable habilitado.

Lo complicado es que no podemos adjuntar este evento directamente a los elementos destino (casilla de verificación, span), porque se crean de forma dinámica y no son parte del DOM al cargar la página.

Gracias a la delegación de eventos, adjuntaremos el evento input a la lista padre, que es parte del marcado inicial. Después, a través de la propiedad target de ese evento, revisaremos los elementos en los que ocurrió el evento y llamaremos a la función updateTask():

Dentro de la función updateTask() haremos lo siguiente:

  1. Tomaremos la tarea que necesita actualizarse.
  2. Revisaremos el elemento que desencadenó el evento. Si el elemento tiene el atributo contenteditable (es decir, es el elemento span), estableceremos el nombre de la tarea para que sea igual al contenido de texto de span.
  3. De lo contrario (es decir, se trata de la casilla de verificación), cambiaremos el estado de la tarea y su atributo checked. Además, también cambiaremos el atributo contenteditable del span adyacente.
  4. Actualizaremos el valor de la clave tasks en el almacenamiento local.
  5. Llamaremos a la función countTasks().

A continuación puedes ver la sintaxis de esta función:

Elimina una tarea

Podemos eliminar una tarea a través del botón "cerrar".

Button for removing a task

De manera similar a la operación de actualización, no podemos adjuntar un evento directamente a este botón, ya que no se encuentra en el DOM al cargar la página.

Gracias a la delegación de eventos de nuevo, adjuntaremos un evento click a la lista padre y llevaremos a cabo las siguientes acciones:

  1. Revisaremos si el elemento al que se le hizo clic es el botón "cerrar" o su SVG hijo.
  2. Si eso ocurre, obtendremos el id del elemento de la lista padre.
  3. Enviaremos este id a la función removeTask().

Este es el código correspondiente:

Dentro de la función removeTask() haremos lo siguiente:

  1. Eliminaremos la tarea asociada del arreglo tasks.
  2. Actualizaremos el valor de la clave tasks en el almacenamiento local.
  3. Eliminaremos el elemento asociado de la lista.
  4. Llamaremos a la función countTasks().

Aquí puedes ver la sintaxis de esta función:

Cuenta las tareas

Como ya hemos discutido, muchas de las funciones anteriores incluyen a la función countTask().

Su trabajo es monitorear las tareas en busca de cambios (adiciones, actualizaciones, eliminaciones) y actualizar el contenido de los elementos relacionados.

Count tasks

Esta es su firma:

Evita la adición de líneas nuevas

Cada vez que un usuario actualice el nombre de una tarea, no debería poder crear líneas nuevas presionando la tecla Enter.

Prevent multi lines

Para deshabilitar esta funcionalidad, una vez más aprovecharemos la delegación de eventos y adjuntaremos el evento keydown a la lista, de esta forma:

Observa que, en este escenario, solamente los elementos span podrían desencadenar ese evento, por lo que no hay necesidad de realizar una verificación adicional de esta manera:

Conserva los datos al cargar la página

Hasta ahora, si cerramos el navegador y nos dirigimos al proyecto de demostración, nuestras tareas desaparecerán.

Pero espera, ¡eso no es 100% cierto! Recuerda que cada vez que manipulamos una tarea, también almacenamos el arreglo tasks en el almacenamiento local. Por ejemplo, en Chrome, para ver las claves y valores del almacenamiento local haz clic en la pestaña Application (Aplicación), luego expande el menú Local Storage (Almacenamiento local) y, finalmente, haz clic en un dominio para ver sus pares de clave y valor.

En mi caso, estos son los valores para la clave tasks:

An example with local storage

Entonces, para mostrar estas tareas primero necesitamos recuperarlas del almacenamiento local. Para hacer esto usaremos el método JSON.parse(), que convertirá las cadenas de vuelta a objetos de JavaScript.

A continuación almacenaremos todas las tareas en el familiar arreglo tasks. Ten en cuenta que, si no hay datos en el almacenamiento local (por ejemplo, al visitar la aplicación por primera vez), este arreglo está vacío. Después tenemos qué recorrer el arreglo y, por cada tarea, debemos llamar a la función createTask(). ¡Y eso es todo!

El fragmento de código correspondiente:


Conclusión

¡Uf! Gracias por seguir los pasos en este largo viaje, amigos. Con suerte, hoy has adquirido nuevos conocimientos que podrás aplicar a tus propios proyectos.

Recordemos lo que hemos creado:

Sin duda, crear una aplicación así con un framework de JavaScript podría ser más estable, sencillo y eficiente (volver a pintar el DOM es caro). Sin embargo, saber resolver este tipo de ejercicio con JavaScript puro te ayudará a obtener una comprensión sólida de sus fundamentos y te convertirá en un mejor desarrollador de JavaScript.

Antes de terminar, permíteme proponer dos ideas para extender este ejercicio:

  • Usa la API HTML para arrastrar y soltar o una biblioteca de JavaScript como Sortable.js para reordenar las tareas.
  • Almacena los datos (las tareas) en la nube en vez de hacerlo en el navegador. Por ejemplo, sustituye el almacenamiento local con una base de datos en tiempo real como Firebase.

Como siempre, ¡muchas gracias por leer!

Más aplicaciones con JavaScript puro

Si deseas aprender a crear pequeñas aplicaciones con JavaScript puro, consulta los siguientes tutoriales:

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.