Skip to content

tomasperezponisio/Perez.Ponisio.Tomas.Labo3.P2.3D

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Tomás Pérez Ponisio - ABM Petshop (Js puro, DOM, peticiones, asincronismo)

Link al sitio deployado: https://mitrepetshop.netlify.app

Requerimientos de la aplicación

  • Desarrollar una aplicación que muestre el listado de los anuncios de mascotas, así como un formulario para dar de alta a nuevos anuncios.
  • La lista de anuncios se genera dinámicamente (con código JS) trabajando con el DOM.
  • En el formulario se validan los datos, y clickeando un anuncio de la lista se puede editar o eliminar (manejados de eventos).
  • Los datos se traen con peticiones AJAX.

Anuncios

Anuncios

Petición AJAX (promesa) para traer los datos de los anuncios

// Exporto la funcion para traer los anuncios que hace una petición ajax, si se resuelve correctamente
// trae los datos, en caso contrario captura el error
export const getAnuncios = () => {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open("GET", URL);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.response);
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
};
const promesa = getAnuncios();
setSpinner(divSpinner, "./img/spinner.gif");
// Dentro del metodo .then (promesa fulfilled) con la data de todos los anuncios voy creandolos individualmente
// llamando la función crearTarjeta()
promesa.then((data) => {
    anuncios = JSON.parse(data);
    anuncios.forEach((elemento) => {
        const $nuevaTarjeta = crearTarjeta(
            elemento.titulo,
            elemento.descripcion,
            elemento.animal,
            elemento.precio,
            elemento.raza,
            elemento.fecha_nacimiento,
            elemento.vacuna);
        $divCards.append($nuevaTarjeta);
    });
    clearSpinner(divSpinner);
})
    .catch((err) => {
        console.error(err);
    });

Armado de anuncios con los elementos del DOM

// Recibo los datos de cada anuncio que traje con la peticion
function crearTarjeta(titulo, descripcion, animal, precio, raza, fecha_nacimiento, vacuna) {
    // Voy creando los tags html y agregando estilos
    const divCol = document.createElement("div");
    divCol.classList.add("col", "py-3");
    const divCard = document.createElement("div");
    divCard.classList.add("card", "border-danger");
    const divCardHeader = document.createElement("div");
    divCardHeader.classList.add("card-header");
    const divCardTitle = document.createElement("div");
    divCardTitle.classList.add("text-uppercase", "text-warning", "fs-3", "fw-bold");
    // Y agregando la info del anuncio
    divCardTitle.textContent = titulo;
    const divCardBody = document.createElement("div");
    divCardBody.classList.add("card-body");
    const divCardFooter = document.createElement("div");
    divCardFooter.classList.add("card-footer");
    const _descripcion = document.createElement("p");
    _descripcion.textContent = "Descripción: " + descripcion;
    const _precio = document.createElement("p");
    _precio.classList.add("text-uppercase", "text-warning", "fs-4", "fw-bold");
    _precio.textContent = "Precio: $" + precio;
    const _animal = document.createElement("p");
    _animal.textContent = "Animal: " + animal;
    const _raza = document.createElement("p");
    _raza.textContent = "Raza: " + raza;
    const _fecha_nacimiento = document.createElement("p");
    _fecha_nacimiento.textContent = "Fecha Nacimiento: " + fecha_nacimiento;
    const _vacuna = document.createElement("p");
    _vacuna.textContent = "Vacuna: " + vacuna;

    // Voy haciendo los append de cada elemento de la tarjeta
    divCol.appendChild(divCard);
    divCard.appendChild(divCardHeader);
    divCardHeader.appendChild(divCardTitle);
    divCard.appendChild(divCardBody);
    divCard.appendChild(divCardFooter);
    divCardBody.appendChild(_descripcion);
    divCardBody.appendChild(_animal);
    divCardBody.appendChild(_raza);
    divCardBody.appendChild(_fecha_nacimiento);
    divCardBody.appendChild(_vacuna);
    divCardFooter.appendChild(_precio);

    return divCol;
}
// Tomo referencia del main de la pagina
const $main = document.querySelector('main');
// Me creo una referencia del container donde iran las fichas
const $divContainer = document.createElement("div");
$divContainer.classList.add("container");
// Creo referencia del div donde iran las fichas
const $divCards = document.createElement("div");
$divCards.classList.add("row", "row-cols-1", "row-cols-md-3", "text-center");
// Hago los append, del container al main y del div de las fichas al container
$main.appendChild($divContainer);
$divContainer.appendChild($divCards);

Formulario

Formulario

// Dos escuchadores, al cargarse la pagina y al submit del form
window.addEventListener("load", () => {
  esconderBotonEliminar();

  $formulario.addEventListener("submit", (e) => {
    e.preventDefault();
    
    // me fijo si hay algun campo del form que no se haya completado
    // y valido los campos del form antes de submit
    if (!validarFormVacio() && validarSubmit()) {
      // borro el mensaje de error de submit
      $alertSubmit.textContent = "";
      $alertSubmit.classList.remove("danger", "text-danger", "fw-bold");

      // si el formulario esta para cargar un nuevo anuncio tomo los valores del form, el target,
      // y con esos datos creo el nuevo anuncio (objeto de la clase anuncio)
      if ($formulario.btnCargar.value == "Cargar") {
        console.log("Cargar");
        const { titulo, descripcion, precio, animal, raza, fecha_nacimiento, vacuna } = e.target;
        const nuevoAnuncio = new Anuncio_Mascota(
          null,
          titulo.value,
          descripcion.value,
          precio.value,
          animal.value,
          raza.value,
          fecha_nacimiento.value,
          vacuna.value);
          // si el anuncio se creo correctamentente, se lo paso a la funcion que crea el anuncio
          // y actualizo la tabla que se encuentra debajo con todos los anuncios
        if (nuevoAnuncio) {
          createAnuncio(nuevoAnuncio);
          actualizarTabla();
        }
      // Si el formulario esta para modificar, con el id del anuncio seleccionado, le paso los datos
      // a la funcion modificarAnuncio() que actualiza el objeto anuncio y despues a la funcion 
      // updateAnuncio() le paso el anuncio actualizado y ésta hace una peticion fetch(PUT) 
      // para actualizar la db, finalmente actualizo la tabla de anuncios
      } else if ($formulario.btnCargar.value == "Modificar") {
        console.log("Modificar");
        console.log(idSeleccionado);
        const anuncio = anuncios.find((element) => element.id == idSeleccionado);
        modificarAnuncio(anuncio);
        updateAnuncio(anuncio);
        actualizarTabla();
      }
    } else {
      console.log("ERROR DE SUBMIT");
      // cargo el mensaje de error de submit
      $alertSubmit.textContent = "Faltan campos requeridos o hay campos invalidos";
      $alertSubmit.classList.add("danger", "text-danger", "fw-bold");
    }
  });
});
// para traer los datos del elemento clickeado, un escuchador al click en la tabla
let idSeleccionado;
$divTabla.addEventListener("click", (e) => {
  $alertSubmit.textContent = "";
  $alertSubmit.classList.remove("danger");
  const emisor = e.target;
  if (emisor.matches("tbody tr td")) {
    let id = emisor.parentElement.dataset.id;
    const anuncio = anuncios.find((element) => element.id == id);
    console.log(anuncio);
    idSeleccionado = id;
    cargarFormulario(anuncio);
    $formulario.btnCargar.value = "Modificar";
    $formulario.btnCargar.classList.add("btn-primary");
    $formulario.btnCargar.classList.remove("btn-success");
    mostrarBotonEliminar();
    removerErrores();
  }
});

Tabla de anuncios

Tabla de anuncios

Petición fetch para traer los datos

let anuncios = await getAnunciosAsync();
actualizarTabla();
export const getAnunciosAsync = async () => {
  try {
    setSpinner(divSpinner, "./img/spinner.gif");
    const res = await fetch(URL);
    if (!res.ok) { throw new Error(`Error: ${res.status} - ${res.statusText} `) }
    const data = await res.json();
    return data;
  } catch (error) {
    console.error(err);
  }
  finally {
    clearSpinner(divSpinner);
  }
};

Armado de la tabla con los elementos del DOM

function actualizarTabla() {
  // limpio de hijos div tabla
  while ($divTabla.hasChildNodes()) {
    $divTabla.removeChild($divTabla.firstChild);
  }
  // y le meto la tabla que me crea la funcion con la data actualizada
  $divTabla.appendChild(crearTabla(anuncios));
}
export function crearTabla(data) {
    if (!Array.isArray(data)) {
        return null;
    }
    const tabla = document.createElement("table");
    tabla.setAttribute("class", "table table-hover")
    tabla.appendChild(crearCabecera(data[0]));
    tabla.appendChild(crearCuerpo(data));
    return tabla;
}
// el row que me pasan es el primer objeto del array
function crearCabecera(row) {
    const cabecera = document.createElement("thead"),
        tr = document.createElement("tr");
    // recorro con un for in las keys del objeto, no quiero el valor, quiero las keys
    for (const key in row) {
        if (key === "id") {
            // el continue salta a la siguiente iteracion, entonces cuando me encuentre con id no ejecuto
            // el codigo de las lineas 14-17 y salteo a la siguiente iteracion
            continue;
        }
        // por cada elemento del objeto, creo una th y le agrego como contenido el nombre de la key
        const th = document.createElement("th");
        th.classList.add("text-capitalize");
        th.textContent = key;
        tr.appendChild(th);
    }
    cabecera.appendChild(tr);
    return cabecera;
}
function crearCuerpo(data) {
    const cuerpo = document.createElement("tbody");
    data.forEach(elemento => {
        const fila = document.createElement("tr");
        for (const atributo in elemento) {
            if (atributo === "id") {
                fila.setAttribute("data-id", elemento[atributo]);
                // el continue salta a la siguiente iteracion, entonces cuando me encuentre con id no ejecuto
                // el codigo de las lineas 14-17 y salteo a la siguiente iteracion
                continue;
            }
            const celda = document.createElement("td");
            if (atributo == "precio") {
                celda.textContent = "$" + elemento[atributo];
            } else {
                celda.textContent = elemento[atributo];
            }
            fila.appendChild(celda);
            fila.classList.add("puntero");
        }
        const filas = cuerpo.children;
        for (let i = 0; i < filas.length; i++) {
            if (!(i % 2)) {
                filas[i].classList.add("gris");
            }
        }
        cuerpo.appendChild(fila);
    });
    return cuerpo;
}

Filtros

Filtros

// -------- Checkboxes ------- //
// Obtengo una referencia de los checkboxes
const $checkboxes = document.querySelectorAll(".checkboxes");

// Obtengo un arrary con los keys a utilizar
const keys = ["id"];
$checkboxes.forEach((elemento) => {
  if (elemento.hasAttribute("checked")) {
    keys.push(elemento.value);
  }
});

// Guardo el orden de las keys asi no se me desordena al filtrar con los  checkboxes
const keysOrder = ["id", "titulo", "descripcion", "precio", "animal", "raza", "fecha_nacimiento", "vacuna"]

$checkboxes.forEach((element) =>
  // En el evento click, si marcan un check lo pusheo al array de keys, si lo desmarcan lo saco
  element.addEventListener("click", (e) => {
    console.log(keysOrder);
    if (e.target.checked) {
      keys.push(e.target.value);
    } else {
      keys.splice(keys.indexOf(e.target.value), 1);
    }
    
    // Para que quede segun el orden original
    keys.sort(function (a, b) {
      return keysOrder.indexOf(a) - keysOrder.indexOf(b);
    });
    
    // Guardo el map de anuncios con los elementos según los keys que tengo guardados
    const anunciosFiltrado = anuncios.map((item) => {
      const nuevoAnuncio = [];
      keys.forEach((key) => {
        nuevoAnuncio[key] = item[key];        
      });
      return nuevoAnuncio;
    });
    actualizarTablaFiltrada(anunciosFiltrado);
  })
);
// ----------- Filtros / Promedios  ----------- //
// Obtengo referencia del input donde va el promedio
const $promedio = document.getElementById("txtPromedio");
$promedio.value = "N/A";

let parametro;
$selFiltro.addEventListener('change', (e) => {
  parametro = e.target.value;
  $promedio.value = "$" + promedio(anuncios, parametro);
  if (parametro == "todos"){
    actualizarTabla();    
  } else {
    let listaFiltrada = anuncios.filter((anuncio) => {
      return anuncio.animal.toLowerCase().includes(parametro.toLowerCase())
    })
    actualizarTablaFiltrada(listaFiltrada);
  }
});
export const promedio = (anuncios, parametro) => {
    let total;
    let totalAnimal;
    if (parametro == "todos") {
        total = anuncios.reduce((total, a) => {
            return total += parseFloat(a.precio);
        }, 0);        
        return (total / anuncios.length).toFixed(2);
    } else {
        totalAnimal = anuncios.filter(p => p.animal == parametro);        
        total = totalAnimal.reduce((total, a) => {
            return total += parseFloat(a.precio);
        }, 0);
        return (total / totalAnimal.length).toFixed(2);
    }
}

About

Segundo Parcial Laboratorio 3

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published