Al genera HTML dinámico, lo mejor sería guardar los datos en un arreglo y de esta manera será más fácil poder trabajar esta información.
Más adelante vamos a ver cómo consumir un API, y cómo poder traer información de forma externa.
De momento vamos a realizar un ejemplo sencillo con una lista de tareas con dos estados (completa true y completa false) Y a través de un filtro vamos a mostrar toda la lista de tareas o bien filtradas por tareas completas y tareas incompletas:
El código HTML será el siguiente:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ejemplo de DOM</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>Ejemplo de listas</h1>
<select id="select_filtro" class="form-select mb-3">
<option value=""> Mostrar todo </option>
<option value="completas"> Mostrar completas </option>
<option value="incompletas"> Mostrar incompletas </option>
</select>
<button type="button" id="btn_mostrar_tareas" class="btn btn-primary mb-3"> Mostrar lista de tareas </button>
<ul id="ul_lista" class="list-group">
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL"
crossorigin="anonymous"></script>
<script src="js/scripts.js"></script>
</body>
</html>
En cuanto al código Javascript, primero vamos a tener un array de objetos:
const tareas = [
{titulo: "Tarea 1", completa: false},
{titulo: "Tarea 2", completa: false},
{titulo: "Tarea 3", completa: false},
{titulo: "Tarea 4", completa: true},
{titulo: "Tarea 5", completa: false},
{titulo: "Tarea 6", completa: true},
{titulo: "Tarea 7", completa: false},
{titulo: "Tarea 8", completa: true},
{titulo: "Tarea 9", completa: true},
{titulo: "Tarea 10", completa: false}
];
Cómo se mencionó en una publicación pasada, un array puede guardar cualquier información, y es muy común utilizar el formato JSON, porque de esta manera, como se puede ver en el ejemplo, podemos guardar el nombre de la tarea y también su estado.
También vamos a crear las referencias al botón el <select> para seleccionar el tipo, el botón para filtrar y el <ul> donde se va a mostrar el resultado:
const ul_lista = document.querySelector("#ul_lista");
const select_filtro = document.querySelector("#select_filtro");
const btn_mostrar_tareas = document.querySelector("#btn_mostrar_tareas");
Siguiendo el ejemplo de listas de bootstrap:
https://getbootstrap.com/docs/5.0/components/list-group/
Vamos a crear una función que agrega elementos <li> dentro del <ul>:
const renderizarTareas = (p_lista) => {
//Limpiamos el <ul> por si ya había elementos previamente.
ul_lista.innerHTML = "";
//Recorremos un array que se va a pasar como parámetro en la función.
p_lista.forEach(item => {
//Creamos un elemento <li>
let li = document.createElement("li");
//Le agregamos una clase con el nombre "list-group-item"
li.classList.add("list-group-item");
//Verificamos si la tarea está completa.
if(item.completa){
//Si lo está, le agregamos la clase list-group-item-success.
li.classList.add("list-group-item-success");
}else{
//Si NO lo está, le agregamos la clase list-group-item-danger.
li.classList.add("list-group-item-danger");
}
//Insertamos el título de la tarea en la etiqueta <li>
li.innerText = item.titulo;
//Agregamos la etiqueta <li> dentro del <ul>
ul_lista.appendChild(li);
});
}
Propiedad classList
Notar en el código que a los elementos HTML podemos acceder a las clases mediante la propiedad classList:
//Le agregamos una clase con el nombre "list-group-item"
li.classList.add("list-group-item");
//Verificamos si la tarea está completa.
if(item.completa){
//Si lo está, le agregamos la clase list-group-item-success.
li.classList.add("list-group-item-success");
}else{
//Si NO lo está, le agregamos la clase list-group-item-danger.
li.classList.add("list-group-item-danger");
}
El método add() agrega clases, también podemos usar remove() para eliminar clases de un elemento o contains() para saber si un elemento tiene una clase.
Filtrar información
En esta primera etapa, no vamos a filtrar la lista, por lo cual que cualquier cosa que hagamos siempre nos devolverá la lista completa.
También vamos a agregar el evento que va a llamar a esta función:
const mostrarTareas = () => {
//Sin ningún filtro, guardamos en un array el array de tareas completo.
let tareas_filtradas = tareas;
//Llamamos a la función que dibuja todo el código HTML.
renderizarTareas(tareas_filtradas);
}
btn_mostrar_tareas.addEventListener("click", mostrarTareas);
Método .filter()
El método .filter() es un método que poseen los arrays que nos devuelve un nuevo array, pero con aquellos elementos que cumplan determinados filtros.
Teniendo en cuenta el <select>:
<select id="select_filtro" class="form-select mb-3">
<option value=""> Mostrar todo </option>
<option value="completas"> Mostrar completas </option>
<option value="incompletas"> Mostrar incompletas </option>
</select>
Vamos a cambiar la función mostrarTareas() de modo que dependiendo de la opción seleccionada por el usuario se le pase a la función renderizarTareas() tres arrays distintos:
- Las tareas completas
- Las tareas incompletas
- Sin filtros, tal cual como es el array tareas
const mostrarTareas = () => {
let tareas_filtradas = [];
if(select_filtro.value == "completas"){
tareas_filtradas = tareas.filter(item => item.completa == true);
}else if(select_filtro.value == "incompletas"){
tareas_filtradas = tareas.filter(item => item.completa == false);
}else{
tareas_filtradas = tareas;
}
renderizarTareas(tareas_filtradas);
}
El código finalmente quedará:
const tareas = [
{titulo: "Tarea 1", completa: false},
{titulo: "Tarea 2", completa: false},
{titulo: "Tarea 3", completa: false},
{titulo: "Tarea 4", completa: true},
{titulo: "Tarea 5", completa: false},
{titulo: "Tarea 6", completa: true},
{titulo: "Tarea 7", completa: false},
{titulo: "Tarea 8", completa: true},
{titulo: "Tarea 9", completa: true},
{titulo: "Tarea 10", completa: false}
];
const ul_lista = document.querySelector("#ul_lista");
const select_filtro = document.querySelector("#select_filtro");
const btn_mostrar_tareas = document.querySelector("#btn_mostrar_tareas");
const renderizarTareas = (p_lista) => {
//Limpiamos el <ul> por si ya había elementos previamente.
ul_lista.innerHTML = "";
//Recorremos un array que se va a pasar como parámetro en la función.
p_lista.forEach(item => {
//Creamos un elemento <li>
let li = document.createElement("li");
//Le agregamos una clase con el nombre "list-group-item"
li.classList.add("list-group-item");
//Verificamos si la tarea está completa.
if(item.completa){
//Si lo está, le agregamos la clase list-group-item-success.
li.classList.add("list-group-item-success");
}else{
//Si NO lo está, le agregamos la clase list-group-item-danger.
li.classList.add("list-group-item-danger");
}
//Insertamos el título de la tarea en la etiqueta <li>
li.innerText = item.titulo;
//Agregamos la etiqueta <li> dentro del <ul>
ul_lista.appendChild(li);
});
}
const mostrarTareas = () => {
let tareas_filtradas = [];
if(select_filtro.value == "completas"){
tareas_filtradas = tareas.filter(item => item.completa == true);
}else if(select_filtro.value == "incompletas"){
tareas_filtradas = tareas.filter(item => item.completa == false);
}else{
tareas_filtradas = tareas;
}
renderizarTareas(tareas_filtradas);
}
btn_mostrar_tareas.addEventListener("click", mostrarTareas);