Aplicación de To Do List con Alpine JS

Veremos el desarrollo para implementar una aplicación de To Do List y su CRUD con Alpine JS.

Veremos los pasos para crear una app de tipo To Do List como primer proyecto real y funcional.

Crear

La siguiente funcionalidad que vamos a crear sería la de crear un todo para esto vamos a ampliar un sencillo formulario como el que está viendo en pantalla por aquí un input igualito que tenemos acá:

<form x-on:submit.prevent="save()" class="row g-2 mt-2">

    <div class="col-auto">
        <label class="col-form-label">Create</label>
    </div>
    <div class="col-auto">
        <input type="text" x-model="task" class="form-control">
    </div>
    <div class="col-auto">
        <button class="btn btn-success" type="submit">Save</button>
    </div>
</form>

Que es lo importante pero con otro nombre es decir otra variable por lo demás aquí tenemos el botón de tipo submit por lo tanto aquí obligatoriamente se pudiera decir para que tenga sentido esto tenemos que colocar aquí un formulario pero para evitar que el formulario se envíe mediante lápide html es decir que cuando le peguemos un click de recargue toda la página cosa que no queremos entonces aquí prevenimos el envío del mismo para que no recargue otra vez toda la página y que se supondría ahí que estuviéramos enviando una petición al servidor otra vez no queremos ya que todos lo queremos mantener aquí en local y para eso aquí colocamos el siguiente atributo submit prevent:

submit.prevent

Que es para manejar los eventos entonces hacemos es un Push a la array de todos y obviamente le colocamos aquí complet en falso:

todos: [],
***
save() {
    this.todos.push(
        { completed: false, task: this.task }
    )
}

Porque se la está creando se supone que no está completada y si la quiere completar que le pegue un check después y limpiamos aquí la variable entonces es simplemente eso vamos a regresar acá y vamos a crearla voy a colocarla por aquí colocamos formulario dije formulario otra otra vez el action ni nada esto nos interesa porque es un formulario local y para evitar que se envíe colocamos xon submit punto primen y llamamos a la función que ya vamos a implementar la llamada save ya por aquí podemos colocar un input un Button de tipo submit aquí lo tenemos voy a colocarle como save y por aquí colocamos el label voy a colocarle create y aquí colocamos el input de tipo text buen Este no es tipo text Aquí está quitamos todo esto y vamos a llamarle el x-model o vamos a colocarle el atributo de X model con el atributo de Tas bien ya por aquí terminamos faltaría es crear aquí la variable le llamamos task y creamos aquí la función de save es por esto que puedes ver que creamos todo esto un componente aparte y no directamente en el html ya que tenemos múltiples funciones y arriba se volvería todo un lío colocamos ts otra vez punto todos el array en este caso Ya esto es algo a través de javascript para agregar un elemento a un array que es lo que tenemos por acá podemos ampliar ya que existen muchas formas la función de Push la cual recibes el elemento ya escrita es bastante abierto puedes pasarle directamente un número si tú quieres pero en este caso queremos respetar la estructura que ya tenemos y para que veas que es exactamente lo mismo voy a copiarlo y voy a colocarlo por acá otra vez porque es la misma estructura que queremos mantener para que la aplicación tenga sentido lo que cambiaría aquí sería el valor que en este caso colocarías y aquí voy a colocarlo falso porque otra vez no quiero que esté completada apenas agregue y esto sería ya prácticamente todo.

Campo de Busqueda

La siguiente funcionalidad que vamos a implementar o la primera funcionalidad sería la de un filtro o campo de búsqueda para esto lo que vamos a hacer sería emplear un input de tipo texto colocamos el x-model ya sabemos para qué lo que escribe el usuario lo podamos tener guardado también en una variable que ya vamos a crear llamada search y por aquí esta variable fíjate que aquí también ahora estamos iterando mediante una función que también vamos a implementar y mediante la mencionada variable buscamos coincidencias con lo
que ya tenemos Entonces inicialmente no tiene nada tal cual puedes ver por lo tanto devolvería todos los registros:

<script>
   function data() {
       return {
           search: "",
           todos: [{ completed: true, task: 'TO DO 1' }, { completed: false, task: 'TO DO 2' }, { completed: false, task: 'TO DO 3' }],
           completed(todo) {
               return todo.completed
           },
           incompleted(todo) {
               return !todo.completed
           },
           totalTareas() {
               return this.todos.length
           },
           filterTodo() {
               return this.todos.filter((t) => t.task.toLowerCase().includes(this.search.toLowerCase())
               )
           },
       }
   }
</script>

Pero ya a partir de que el usuario empiece a escribir ya se filtrara y cómo funciona el filtro en javascript tenemos una función llamada filter que a la final también funciona similar al for each y demás es decir lo implementamos mediante un callback o un método sin nombre una función mejor dicho en la cual aquí tenemos el item es decir el elemento que estamos iterando y aplicamos la condición si esta condición:

<div x-data="data()">


    <p>Total Task <span x-text="totalTareas"></span></p>


    <label>Search
        <input type="text" x-model="search">
    </label>


    <template x-for="t in filterTodo()">
        <p>
            <template x-if="completed(t)">
                <span>Completed</span>
            </template>
            <template x-if="!t.completed">
                <span>Uncompleted</span>
            </template>
            <span x-text="t.task"></span>
        </p>
    </template>
</div>

Devuelve true significa que forma parte del listado que estamos retornando acá y si no simplemente lo excluye por lo tanto por defecto aquí ya tenemos un listado filtrado otra vez si esto es vacío que sería la condición inicial devolvería todos los elementos aquí también empleamos la función de toLowerCase que es para convertir el texto en minúscula que es lo que estamos comparando por acá:

return this.todos.filter((t) => t.task.toLowerCase().includes(this.search.toLowerCase())

y por acá por si el usuario por ejemplo aquí dice sacar la basura entonces escribe sacar con la s minúscula entonces es como quien dice para integrar todo y sin importar si está mayúscula o minúscula también devuelve el mismo resultado Porque si uno tuviera que hacer coincidencia exacta cosa que otra vez no quisiéramos así que vamos a comenzar por aquí voy a colocar el Label Y ahorita creamos la variable y por aquí el input colocamos input de tipo text quitamos todo esto colocamos x model y lo vamos a llamar como share por aquí la vamos a registrar colocamos shar va a ser igual a vacío y creamos la nueva función filter todo aquí aplicamos la condición tal cual te comentábamos esto va a retornar es una raate es provisto por t punto todos Recuerda que para referenciar cualquiera de estos métodos variables tenemos que colocar el tis tal cual ocurre con Vue como si fuera una clase entonces aquí referenciamos es es el de todos tal cual hacíamos también por acá solo que en este caso queremos es aplicar la función de filter de javascript muy importante que funciona de la siguiente manera en caso de que no la sepas también la documentación de moxila también tiene una varios ejemplos muy interesantes con esto En caso de que todavía no lo entiendas pero esto es un callback básicamente en el cual esto tiene ha que retornar una condición de verdadero o falso también puedes ir por el clásico si es lo que tú quieres pero como la condición es en una sola línea podemos aprovechar las funciones de flecha que tenemos en javascript que tiene la siguiente sintaxis bueno por aquí vamos a colocar la condición recuerda aquí tenemos el todo que estamos iterando queremos es acceder a la tarea al texto lo convertimos en minúscula con la función de to lowercase y finalmente aquí comparamos si esto se encuentra incluido en el término de búsqueda que acaba de colocar el usuario y esto nos devuelve true o falso entonces colocamos t. share para acceder a la variable que acabamos de crear punto toLowerCase otra vez para convertir todo en minúscula y pendiente que es una función y esto devolvería la condición de true o false también lo puedes ejecutar en caso de que no lo veas por aquí en tu consola de javascript este token ahí bueno esta función es la que vamos a emplear ahora por acá para iterar y esto sería prácticamente todo entonces aquí recargamos aquí la tenemos Recuerda que es esto bueno Esto me está chocando un poquito aquí más adelante vamos a colocar un iconito pero también nos va a colocar un guion para hacer aquí una separación y poder visualizar esto de mejor manera estos son los todos que yo tengo voy a colocar por ejemplo uno Fíjate que lo encuentra perfectamente porque es el único que tiene uno incluido se escribió todo en minúscula fíjate que lo toma por la la condición que colocamos acá si no colocá esto entonces tuviera que hacer coincidencia exacta cosa que usualmente no es lo que queremos fíjate que escribió todo y no lo encuentra si la coloco en mayúscula la encuentra entonces así de fácil ya implementamos un filtro un sencillo filtro para nuestra aplicación de todo list.

To Do completado

La siguiente operación que vamos a hacer es marcar un todo como completado para esto utilizaremos el input de tipo checkbox y le estableceremos fíjate que no es una variable que estamos definiendo sino como quien dice es en vivo y le establecemos aquí desde el todo un campo llamado complete que por defecto ninguna estuviera completada tal cual hemos hecho hasta este momento:

***
<template x-for="t in filterTodo()">
    <input type="checkbox" x-model="t.completed">
    <span x-text="t.task"></span>
</template>
***

Recuerda que este campo de complete sería este entonces simplemente atamos me refiero en vivo porque no está establecido de esta forma sino forma parte de un array y esto es dinámico puede que por ejemplo este puede que no esté puede que el usuario cree otro etcétera entonces aclarado es un poquito vamos a hacerlo aquí rapidito vamos a colocarlo justamente en el listado recuerda que esto es de momento más adelante escogemos algo más bonito y voy a colocarlo acá colocamos un input otra vez recuerda que es aquí el iteración de tipo checkbox y colocamos x model igual a punto complete no esperes que haga mucho porque otra vez toda esta Data la estamos manejando aquí en local más adelante la configuramos al iw el servidor si está siguiendo el curso de iware pero momento nos conformamos con al menos tener aquí la funcionalidad y fíjate que cambia automáticamente el mensaje aquí también por cierto lo coloqué fue un complete que sería la denominación correcta así que vamos a la siguiente clase.

To Do Eliminar

La siguiente operación que vamos a realizar es la posibilidad de eliminar un todo sería la que tenemos acá muy sencilla otra vez recordemos que todo se mantiene el local cuando rec carguemos se perderá o se mantendrá el esquema que tenemos actualmente en mi caso es esto pero para ya tenerla aquí lista entonces para esto qué es lo que hacemos un botón claro está nuevamente sin diseño al menos de momento y por aquí hay 1000 formas de eliminar un elemento de un array en javascript importante que esto es de javascript y una de ellas viene siendo la de filter ya que estamos ampliando la de filter para filtrarla aquí también la podemos aprovechar qué es lo que hace la condición bueno básicamente iterar todos los todos y el que sea distinto al todo que queremos eliminar que es el que le estamos pasando por acá se mantiene en esencia va a mantener todos los todos menos el que le estamos pasando que es el que queremos elinar de igual manera cualquier duda Haz la prueba en la consola del navegador y ahí vas a ver cómo funciona pero es eso vamos a implementar aquí el método bueno la función la llamamos remove aquí recibimos el todo que queremos eliminar todos:

remove(todo) {this.todos = this.todos.filter((t) => t != todo)},

Recuerda que todo esto es reactivo por lo tanto no hace falta hacer como quien dice alguna operación adicional para recargar el listado es lo bonito de esto t punto todos va a ser igual a dis punto todos punto todos punto filter como te comentaba una de las maneras que tenemos para eliminar un elemento en específico del listado y lo que hacemos es T sea distinto a todo recuerda en mi caso por ejemplo tengo tres todos iteramos esos tres y todos los que sean distintos que serían todos serían los otros dos todos se mantienen pero el todo que sea igual al que queremos eliminar que sería uno de los tres todos que tengo ahí es el que quitaríamos de acá por lo tanto esto en mi ejemplo que yo tengo otra vez tres todos devolvería los dos todos que no queremos eliminar y eliminaría uno espero que haya quedado claro De igual manera cualquier consulta al al cajón de comentarios Aquí lo tengo y no implemente el botón Así que lo implementamos voy a colocarlo también por acá colocamos:

***
<template x-for="t in filterTodo()">
    <input type="checkbox" x-model="t.completed">
    <span x-text="t.task"></span>
    <button @click="remove(t)">X</button>
</template>
***

Otra vez cuando recargues obviamente se mantiene lo que tenemos inicialmente porque lo tenemos en hardcode y si creamos alguno por aquí está y lo podemos eliminar sin problemas voy otra vez voy a colocar aquí otra cosa y fíjate que todo funciona correctamente así que ya con esto implementamos dicha funcionalidad

- Andrés Cruz

In english

Este material forma parte de mi curso y libro completo; puedes adquirirlos desde el apartado de libros y/o cursos Curso y Libro primeros pasos con Laravel 11 Livewire 3 + Alpine.js y Tailwind.css - 2025.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.

!Cursos desde!

10$

En Udemy

Quedan 1d 10:48!


Udemy

!Cursos desde!

4$

En Academia

Ver los cursos

!Libros desde!

1$

Ver los libros
¡Hazte afiliado en Gumroad!