DEV Community

Cover image for Firebase CRUD con JS y HTML: Read, Update y Delete
Javier Rodriguez
Javier Rodriguez

Posted on

Firebase CRUD con JS y HTML: Read, Update y Delete

En la segunda parte de este proyecto, terminaremos de implementar las otras funciones (Read, Update y Delete), siguiendo dando estilos con Bootstrap. Al final de este art铆culo, tendremos una app funcional para guardar, editar o borrar tareas.

1. Leamos datos

馃煥 Agreguemos otro cachito de c贸digo a nuestro script para que pueda leer datos. Para esto, vamos a necesitar tener alg煤n "container" en nuestro archivo html para poder contener todas las tareas, y debe ser con un id. En mi caso, pongo esto debajo del form:

<div id="task_todo">
</div>
Enter fullscreen mode Exit fullscreen mode

Y luego desde el script, obtengo el elemento e inserto los datos consultados de la DB (pongo todo el script entero, ya que hice un par de cambios de nombres con respecto al anterior art铆culo):

const db = firebase.firestore();

const todoForm = document.getElementById('todo_form');
const taskToDo = document.getElementById('task_todo');

const createTask = (name, url, description) => {
    db.collection('tasks').doc().set({
        name,
        url,
        description
    });
};

const getTasks = (callback) => db.collection('tasks').onSnapshot(callback);

window.addEventListener('DOMContentLoaded', async (e) => {
    getTasks((querySnapshot) => {
        taskToDo.innerHTML = '';
        querySnapshot.forEach(doc => {
            console.log(doc.data());
            const if_url = `<a href="${doc.data().url}">URL de tarea</a>` 
            taskToDo.innerHTML += `
                <div>
                    <h4>${doc.data().name}</h4>
                    <p>${doc.data().description}</p>
                    ${doc.data().url ? 
                        if_url
                        : ''
                    }
                </div>
            `
        });
    });
});

todoForm.addEventListener('submit', async e => {
    e.preventDefault();
    const name = todoForm['todo_name'].value;
    const url = todoForm['todo_url'].value;
    const description = todoForm['todo_description'].value;

    await createTask(name, url, description); // Llamo a mi funci贸n create
    todoForm.reset(); // Reseteamos los campos
});
Enter fullscreen mode Exit fullscreen mode

馃煥 Como el campo de URL es opcional, entonces coloco un condicional if in line para insertar o no una etiqueta a.
Estas tareas se visualizan utilizando window.addEventListener('DOMContentLoaded', ... ), dando uso del m茅todo onSnapshot que nos brinda Firebase para actualizar 煤nicamente si hay nuevos datos.
Visualmente nos quedar铆a as铆:
Leer tareas

2. Eliminemos datos

馃煥 Tener tantas tareas es medio molesto, no? Ahora agreguemos dos botones: Eliminar y Editar. Ahora solo laburaremos para el bot贸n Eliminar.
Estos botones los agregamos dentro de innerHTML que usamos al leer datos, quedar铆a as铆 (agrego un par de estilos de Bootstrap de paso):

const deleteTask = id => db.collection('tasks').doc(id).delete();

window.addEventListener('DOMContentLoaded', async (e) => {
    getTasks((querySnapshot) => {
        taskToDo.innerHTML = '';
        querySnapshot.forEach(doc => {
            const if_url = `<a href="${doc.data().url}">URL de tarea</a>` 
            taskToDo.innerHTML += `
                <div class="card my-2 p-2">
                    <h4>${doc.data().name}</h4>
                    <p>${doc.data().description}</p>
                    ${doc.data().url ? 
                        if_url
                        : ''
                    }
                    <div>
                        <button class="btn btn-secondary btn-edit" data-id="${doc.id}">Editar</button>
                        <button class="btn btn-primary btn-delete" data-id="${doc.id}">Eliminar</button>
                    </div>
                </div>
            `;

            const deleteButtons = document.querySelectorAll('.btn-delete');
            deleteButtons.forEach(btn => {
                btn.addEventListener('click', async (e) => {
                    await deleteTask(e.target.dataset.id);
                })
            })
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

馃煥 Al leer cada documento, guardamos los datos en doc. Con doc.data() obtenemos la informaci贸n que guardamos y con doc.id obtenemos el id generado para cada documento. Esto 煤ltimo nos sirve para identificar cada par de buttons.
Cuando escucho los eventos click en los buttons Eliminar, me fijo el id puesto en data-id y llamo a la funci贸n deleteTask para eliminar la tarea del button accionado.
Nos queda algo as铆:
Eliminar tareas

3. Editemos datos

馃煥 Para terminar, tenemos que crear la funcionalidad de editar las tareas para hacer. Es similar a lo que hicimos para eliminar, solo que deseamos que nos aparezca los datos en el formulario y luego enviar los datos actualizados. A modo de listado de lo que debemos implementar, ser铆a:

  • Obtener el id del bot贸n accionado
  • Cambiar el texto del bot贸n del form por "Editar"
  • Obtener los valores de cada campo del form
  • Enviar estos datos a Firebase, usando el id del bot贸n
  • Cambiar el texto del bot贸n del form por "Guardar"

馃煥 Teniendo en cuenta esto, debemos crear un par de variables para cambiar entre el estado Editar y Guardar, las cuales llamaremos editState y id.
El c贸digo final ser铆a este:

const db = firebase.firestore();

const todoForm = document.getElementById('todo_form');
const taskToDo = document.getElementById('task_todo');

let editState = false;
let id = '';

const createTask = (name, url, description) => {
    db.collection('tasks').doc().set({
        name,
        url,
        description
    });
};

const getTask = id => db.collection('tasks').doc(id).get();

const getTasks = (callback) => db.collection('tasks').onSnapshot(callback);

const deleteTask = id => db.collection('tasks').doc(id).delete();

const updateTask = (id, updatedTask) => db.collection('tasks').doc(id).update(updatedTask);

window.addEventListener('DOMContentLoaded', async (e) => {
    getTasks((querySnapshot) => {
        taskToDo.innerHTML = '';
        querySnapshot.forEach(doc => {
            const if_url = `<a href="${doc.data().url}">URL de tarea</a>` 
            taskToDo.innerHTML += `
                <div class="card my-2 p-2">
                    <h4>${doc.data().name}</h4>
                    <p>${doc.data().description}</p>
                    ${doc.data().url ? 
                        if_url
                        : ''
                    }
                    <div>
                        <button class="btn btn-secondary btn-edit" data-id="${doc.id}">Editar</button>
                        <button class="btn btn-primary btn-delete" data-id="${doc.id}">Eliminar</button>
                    </div>
                </div>
            `;

            const deleteButtons = document.querySelectorAll('.btn-delete');
            deleteButtons.forEach(btn => {
                btn.addEventListener('click', async (e) => {
                    await deleteTask(e.target.dataset.id);
                })
            })

            const editButtons = document.querySelectorAll('.btn-edit');
            editButtons.forEach(btn => {
                btn.addEventListener('click', async (e) => {
                    const doc = await getTask(e.target.dataset.id);
                    const task = doc.data();

                    editState = true;
                    id = doc.id;

                    todoForm['todo_name'].value = task.name;
                    todoForm['todo_url'].value = task.url;
                    todoForm['todo_description'].value = task.description;
                    todoForm['btn_todo_form'].innerHTML = 'Editar';
                })
            })
        });
    });
});

todoForm.addEventListener('submit', async e => {
    e.preventDefault();
    const name = todoForm['todo_name'].value;
    const url = todoForm['todo_url'].value;
    const description = todoForm['todo_description'].value;

    if (!editState) {
        await createTask(name, url, description); // Llamo a mi funci贸n create
    } else {
        await updateTask(id, {name, url, description});
        editState = false;
        id = '';
        todoForm['btn_todo_form'].innerHTML = 'Guardar';
    }

    todoForm.reset(); // Reseteamos los campos
});
Enter fullscreen mode Exit fullscreen mode

Al apretar uno de los botones Editar de las tareas, tenemos esto:
Editar tarea


Ahora mismo tenemos una aplicaci贸n web funcionando. Hay varias cosas para editar y que en esta serie de art铆culos no tendremos en cuenta:

  • Cualquiera puede editar, guardar y eliminar datos.
  • No hay autenticaci贸n.
  • Dise帽o no es responsive.
  • Otras m谩s pero no graves. Si leemos la documentaci贸n de Firebase, podemos solucionar gran parte del problema (agregando autenticaci贸n, reglas en la DB y dem谩s).

En el pr贸ximo y 煤ltimo art铆culo, haremos el deploy para tenerlo en l铆nea!

Discussion (4)

Collapse
jk9maker profile image
JK9maker

excelente, tengo una duda. se puede variar el valor del filtro que muestra en la siguiente linea
const getTasks = (callback) => db.collection('tasks').onSnapshot(callback);

por ejemplo:
const getTasks = (callback) => db.collection('tasks').where("aqui la parte que se pueda variar desde un input para el filtro").onSnapshot(callback);

excelente explicado saludos.

Collapse
sturpin profile image
Sergio Turp铆n

Muy bien explicado, enhorabuena Javier 馃憣馃徎馃槈

Collapse
javicerodriguez profile image
Javier Rodriguez Author

Muchas gracias Sergio! 馃槃

Some comments have been hidden by the post's author - find out more