Categoría: DOM

  • 3.1 – EL DOM (DOCUMENT OBJECT MODEL)

    3.1 – EL DOM (DOCUMENT OBJECT MODEL)

    1. ¿Qué es el DOM?

    El DOM (Document Object Model) es la representación en forma de árbol de objetos que el navegador crea a partir del HTML.

    El navegador no “lee HTML y ya”.
    Lo convierte en objetos manipulables con JavaScript.

    Ejemplo simple:

    HTML:

    <body>
      <h1>Hola</h1>
      <p>Texto</p>
    </body>

    El navegador lo convierte mentalmente en:

    document
     └── body
         ├── h1
         │   └── "Hola"
         └── p
             └── "Texto"

    Cada etiqueta es un nodo (node).
    Cada nodo es un objeto JavaScript.

    Eso significa que puedes:

    • Leerlo
    • Modificarlo
    • Crear nuevos nodos
    • Borrarlos
    • Moverlos

    El DOM es, literalmente, la memoria viva del HTML.


    2. El objeto document

    El punto de entrada al DOM es:

    document

    Es el objeto raíz del árbol. Desde aquí puedes acceder a todo el HTML.

    Ejemplo:

    console.log(document.title);
    console.log(document.body);

    3. Seleccionar elementos del DOM

    Antes de modificar algo, hay que localizar el nodo.

    3.1 getElementById (el clásico)

    HTML:

    document.querySelector("#titulo");      // por id
    document.querySelector(".clase");       // por clase
    document.querySelector("h1");           // por etiqueta
    document.querySelector("div p");        // descendiente

    JS:

    const titulo = document.getElementById("titulo");
    console.log(titulo);

    Devuelve un solo elemento.


    3.2 querySelector (el más versátil)

    Permite usar selectores CSS.

    document.querySelector("#titulo");      // por id
    document.querySelector(".clase");       // por clase
    document.querySelector("h1");           // por etiqueta
    document.querySelector("div p");        // descendiente

    Devuelve el primer elemento que coincide.


    3.3 querySelectorAll (varios elementos)

    const items = document.querySelectorAll("li");
    console.log(items);

    Devuelve una NodeList (colección).

    Se recorre así:

    items.forEach(item => {
      console.log(item.textContent);
    });

    4. Leer y modificar contenido

    4.1 textContent (forma segura)

    const titulo = document.getElementById("titulo");
    titulo.textContent = "Nuevo título";

    Nunca ejecuta HTML. Solo texto.


    4.2 innerHTML (usar con cuidado)

    titulo.innerHTML = "<b>Hola</b>";

    Inserta HTML real.
    Peligroso si el contenido viene del usuario (XSS).

    Regla:
    Si solo es texto → textContent.


    5. Manipular atributos

    Leer atributo

    const img = document.querySelector("img");
    console.log(img.getAttribute("src"));

    Modificar atributo

    img.setAttribute("src", "nueva.jpg");

    6. Manipular clases CSS

    Añadir clase

    elemento.classList.add("activo");

    Quitar clase

    elemento.classList.remove("activo");

    Alternar

    elemento.classList.toggle("activo");

    7. Crear elementos (crear nodos)

    Aquí empieza la verdadera manipulación del DOM.

    Crear un elemento

    const p = document.createElement("p");
    p.textContent = "Soy nuevo en el DOM";

    Todavía no está en la página.


    8. Insertar elementos en el DOM

    append (al final)

    document.body.append(p);

    prepend (al principio)

    document.body.prepend(p);

    append en otro nodo

    const contenedor = document.getElementById("contenedor");
    contenedor.append(p);

    9. Eliminar elementos

    p.remove();

    10. Ejercicio guiado — Pintar lista desde un array

    HTML:

    <ulid="lista"></ul>

    JS:

    const datos = ["Manzana", "Pera", "Plátano", "Kiwi"];
    
    const lista = document.getElementById("lista");
    
    datos.forEach(fruta => {
      const li = document.createElement("li");
      li.textContent = fruta;
      lista.append(li);
    });

    Resultado: el DOM se construye dinámicamente.


    11. Cómo piensa un programador al usar el DOM

    El flujo mental correcto es:

    1. Selecciono el nodo contenedor
    2. Creo elementos nuevos
    3. Les pongo contenido
    4. Los inserto en el DOM

    Es exactamente el mismo pensamiento que usarías manipulando objetos en Java.


    12. Errores comunes

    ❌ Usar innerHTML para todo

    Malo para seguridad y mantenimiento.

    ❌ Crear elementos sin insertarlos

    Si no haces append/prepend → no aparecen.

    ❌ Duplicar IDs

    Un ID debe ser único.

    ❌ Mezclar lógica y HTML sin orden

    Primero datos, luego render.


    13. Mini-reto

    Crea una tabla HTML y, desde JavaScript, genera 5 filas con:

    • Nombre
    • Edad
    • Ciudad

    Todo debe construirse con createElement.

    Nada de escribir filas en el HTML.


    14. Lo que debes haber aprendido

    Al terminar este bloque debes poder:

    • Entender qué es el DOM
    • Seleccionar elementos
    • Modificar texto
    • Manipular atributos y clases
    • Crear elementos dinámicamente
    • Insertar y eliminar nodos
    • Construir HTML desde datos

    Si esto está claro, en el siguiente bloque el cerebro da el salto natural:

    JSON → JavaScript → DOM

    Y ahí empieza el verdadero front conectado a tu backend JEE.

    El DOM no es difícil. Solo es un árbol.
    Y los árboles, curiosamente, se doman rama por rama. 🌿

    puedes hacerme una tabla con los metodos o atributos que puedo sacar de cada elemento.

    El DOM es como una criatura mitológica hecha de objetos. Cada elemento HTML hereda poderes de varias “clases ancestrales”: Node → Element → HTMLElement. Eso significa que casi todos los elementos comparten un mismo arsenal de propiedades y métodos. No memorizas etiquetas… entiendes la especie.

    Aquí tienes la tabla de referencia esencial que usarás constantemente.


    Métodos y atributos principales de un elemento DOM

    TipoNombreQué haceEjemplo
    📦 PropiedadidObtiene o cambia el id del elementoel.id = "nuevo"
    📦 PropiedadclassNameClases CSS como stringel.className = "rojo grande"
    📦 PropiedadclassListManejo avanzado de clasesel.classList.add("activo")
    📦 PropiedadtextContentTexto interno (seguro)el.textContent = "Hola"
    📦 PropiedadinnerHTMLHTML internoel.innerHTML = "<b>Hola</b>"
    📦 PropiedadchildrenElementos hijosel.children.length
    📦 PropiedadparentElementNodo padreel.parentElement
    📦 PropiedadstyleEstilos inlineel.style.color = "red"
    📦 PropiedadvalueValor (inputs, textarea)input.value
    📦 PropiedadcheckedEstado checkbox/radiocheck.checked
    📦 PropiedadsrcRuta de imagen/videoimg.src
    📦 PropiedadhrefEnlacesa.href
    📦 PropiedaddisabledHabilitar/deshabilitarbtn.disabled = true
    📦 PropiedaddatasetAcceso a data-*el.dataset.id

    Métodos de atributos

    MétodoQué haceEjemplo
    getAttribute(name)Lee atributoel.getAttribute("src")
    setAttribute(name, value)Cambia atributoel.setAttribute("alt","img")
    removeAttribute(name)Elimina atributoel.removeAttribute("disabled")
    hasAttribute(name)Comprueba atributoel.hasAttribute("id")

    Métodos de clases CSS

    MétodoQué haceEjemplo
    classList.add()Añade claseel.classList.add("rojo")
    classList.remove()Quita claseel.classList.remove("rojo")
    classList.toggle()Alterna claseel.classList.toggle("activo")
    classList.contains()Comprueba claseel.classList.contains("rojo")

    Métodos de creación y manipulación

    MétodoQué haceEjemplo
    createElement(tag)Crea nododocument.createElement("div")
    append()Inserta al finalpadre.append(hijo)
    prepend()Inserta al iniciopadre.prepend(hijo)
    remove()Elimina nodoel.remove()
    cloneNode(true)Clona nodoel.cloneNode(true)

    Métodos de búsqueda dentro de un elemento

    MétodoQué haceEjemplo
    querySelector()Primer descendienteel.querySelector("p")
    querySelectorAll()Todos los descendientesel.querySelectorAll("li")
    getElementsByClassName()Por claseel.getElementsByClassName("x")
    getElementsByTagName()Por etiquetael.getElementsByTagName("div")

    Eventos (interacción)

    MétodoQué haceEjemplo
    addEventListener()Escucha eventobtn.addEventListener("click", fn)
    removeEventListener()Quita eventobtn.removeEventListener("click", fn)

    Eventos comunes:

    • click
    • input
    • change
    • submit
    • keydown
    • mouseover

    PropiedadQué hace
    parentElementPadre
    childrenHijos elementos
    firstElementChildPrimer hijo
    lastElementChildÚltimo hijo
    nextElementSiblingHermano siguiente
    previousElementSiblingHermano anterior

  • 3.2 – EVENTOS EN JAVASCRIPT

    3.2 – EVENTOS EN JAVASCRIPT

    1. Qué es un evento

    Un evento es cualquier interacción que ocurre en la página:

    • El usuario hace clic
    • Escribe en un input
    • Envía un formulario
    • Mueve el ratón
    • Pulsa una tecla
    • La página termina de cargar

    Cuando ocurre algo → el navegador lo detecta → JavaScript puede reaccionar.

    El DOM no es solo un árbol… es un sistema reactivo.


    2. Qué es un Event Listener

    Un Event Listener es una función que espera a que ocurra un evento.

    Cuando el evento ocurre → se ejecuta la función.

    La forma moderna y correcta de escuchar eventos es:

    elemento.addEventListener("evento", funcion);

    3. Sintaxis de addEventListener

    boton.addEventListener("click", () => {
      console.log("Se hizo clic");
    });

    Parámetros:

    • Tipo de evento → "click"
    • Función a ejecutar → callback

    4. Ejemplo básico

    HTML:

    <buttonid="btn">Haz clic</button>

    JavaScript:

    const btn = document.getElementById("btn");
    
    btn.addEventListener("click", () => {
      alert("Botón pulsado");
    });

    5. El objeto event

    Cada vez que ocurre un evento, JavaScript genera un objeto llamado event que contiene información.

    btn.addEventListener("click", (event) => {
      console.log(event);
    });

    Propiedades útiles:

    PropiedadQué indica
    event.targetElemento que disparó el evento
    event.typeTipo de evento
    event.clientXPosición X del ratón
    event.clientYPosición Y del ratón
    event.keyTecla pulsada
    event.preventDefault()Evita comportamiento por defecto
    event.stopPropagation()Detiene propagación

    6. Eventos más comunes

    Click

    element.addEventListener("click", fn);

    Input (cuando el usuario escribe)

    input.addEventListener("input", fn);

    Change (cuando cambia valor)

    select.addEventListener("change", fn);

    Submit (formularios)

    form.addEventListener("submit", fn);

    Keydown (teclado)

    document.addEventListener("keydown", fn);

    Mouseover

    element.addEventListener("mouseover", fn);

    7. Evitar comportamiento por defecto

    Ejemplo: evitar que un formulario recargue la página.

    form.addEventListener("submit", (e) => {
      e.preventDefault();
      console.log("Formulario capturado");
    });

    8. Propagación de eventos (Bubbling)

    Cuando ocurre un evento, no solo afecta al elemento… sube por el árbol DOM.

    Ejemplo:

    <div id="padre">
      <button id="hijo">Click</button>
    </div>
    padre.addEventListener("click", () => console.log("Padre"));
    hijo.addEventListener("click", () => console.log("Hijo"));

    Resultado al hacer click:

    Hijo
    Padre

    Primero el elemento → luego sus padres.


    9. Detener propagación

    hijo.addEventListener("click", (e) => {
      e.stopPropagation();
    });

    10. Delegación de eventos (muy importante)

    En lugar de añadir eventos a cada elemento, se añade uno solo al contenedor.

    tabla.addEventListener("click", (e) => {
      if (e.target.classList.contains("btn-ver")) {
        const id = e.target.dataset.id;
        console.log("Ver registro", id);
      }
    });

    Ventajas:

    • Funciona con elementos creados dinámicamente
    • Mejor rendimiento
    • Menos código

    Esto es fundamental cuando el DOM se genera con JavaScript.


    11. Eliminar eventos

    function clickHandler() {
      console.log("Click");
    }
    
    btn.addEventListener("click", clickHandler);
    btn.removeEventListener("click", clickHandler);

    La función debe ser la misma referencia.


    12. Eventos en elementos creados dinámicamente

    Cuando creas un elemento con JavaScript, debes añadir el listener manualmente.

    const boton = document.createElement("button");
    boton.textContent = "Eliminar";
    
    boton.addEventListener("click", () => {
      console.log("Elemento eliminado");
    });

    Tabla de eventos en JavaScript

    🖱️ Eventos del ratón

    EventoCuándo ocurreUso típico
    clickClic normalBotones, enlaces
    dblclickDoble clicAcciones especiales
    mousedownPulsar botón ratónDrag, control
    mouseupSoltar botónFinalizar acción
    mousemoveMover ratónTracking, dibujo
    mouseoverEntrar en elementoHover
    mouseoutSalir de elementoQuitar hover
    mouseenterEntrar (sin bubbling)UI precisa
    mouseleaveSalir (sin bubbling)UI precisa
    contextmenuClic derechoMenú contextual

    ⌨️ Eventos del teclado

    EventoCuándo ocurreUso típico
    keydownTecla presionadaDetectar tecla
    keyupTecla liberadaConfirmar entrada
    keypressTecla mantenida (deprecated)Evitar usar

    Propiedad útil: event.key


    📝 Eventos de formularios / inputs

    EventoCuándo ocurreUso típico
    inputCambia el valor en tiempo realValidación viva
    changeValor confirmadoSelect, checkbox
    submitEnvío de formularioCapturar datos
    resetReset formularioRestaurar
    focusElemento recibe focoUX
    blurElemento pierde focoValidación
    invalidValidación HTML fallaFormularios

    📄 Eventos del documento / ventana

    EventoCuándo ocurreUso típico
    DOMContentLoadedDOM listoInicializar app
    loadPágina completamente cargadaRecursos
    resizeCambia tamaño ventanaResponsive
    scrollScroll de páginaLazy load
    beforeunloadAntes de salirConfirmación
    unloadPágina se cierraLimpieza

    🎯 Eventos de interacción avanzada

    EventoCuándo ocurreUso típico
    dragstartInicio dragDrag & Drop
    dragoverArrastrando encimaDrop zones
    dropSoltar elementoUpload
    touchstartTocar pantallaMóvil
    touchmoveDeslizarGestos
    touchendFin toqueMobile UI
    pointerdownInput universalMultiplataforma

    📡 Eventos de red y estado

    EventoCuándo ocurreUso típico
    onlineVuelve conexiónReintentar
    offlineSin conexiónAvisar
    errorError recursoDebug
    abortCancelaciónFetch

    🎬 Eventos multimedia

    EventoCuándo ocurreUso típico
    playReproducirVideo/audio
    pausePausarControl
    endedFinaliza mediaLoop
    timeupdateTiempo cambiaBarra progreso
    volumechangeVolumen cambiaUI

    🧠 Propiedades comunes del objeto event

    PropiedadQué indica
    event.targetElemento que disparó el evento
    event.currentTargetElemento con listener
    event.typeTipo de evento
    event.keyTecla
    event.clientX/YPosición ratón
    event.preventDefault()Evita comportamiento
    event.stopPropagation()Detiene bubbling

    Ejemplo guiado: cargar JSON por fetch al inicio y pintarlo en el DOM

    1. Al abrir la página, se ejecuta código al evento DOMContentLoaded
    2. Se llama a un endpoint con fetch()
    3. Se convierte la respuesta a JSON
    4. Se renderiza una tabla en el DOM
    5. Se manejan estados: cargando / error / sin datos

    1) HTML (estructura base)

    Crea un archivo index.html:

    <!doctype html>
    <html lang="es">
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width,initial-scale=1" />
      <title>JSON → DOM</title>
      <style>
        body { font-family: system-ui, Arial; padding: 20px; }
        .status { padding: 10px; border-radius: 8px; margin: 10px 0; }
        .loading { background: #fff3cd; }
        .error { background: #f8d7da; }
        .ok { background: #d1e7dd; }
        table { border-collapse: collapse; width: 100%; margin-top: 10px; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background: #f3f3f3; }
      </style>
    </head>
    
    <body>
      <h1>Listado de coches</h1>
    
      <div id="status" class="status loading">Cargando...</div>
    
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Marca</th>
            <th>Modelo</th>
            <th>Precio</th>
          </tr>
        </thead>
        <tbody id="rows"></tbody>
      </table>
    
      <script src="app.js"></script>
    </body>
    </html>

    Qué estamos preparando aquí

    • Un div#status para mostrar mensajes (cargando/error/vacío).
    • Un tbody#rows donde vamos a insertar filas dinámicamente.
    • Cargamos app.js al final.

    2) JavaScript (cargar y pintar)

    Crea un archivo app.js:

    // 1) Este evento se dispara cuando el DOM ya está construido.
    //    (Importante: aún puede que imágenes o recursos no hayan cargado, pero el HTML sí.)
    document.addEventListener("DOMContentLoaded", () => {
      loadCars();
    });
    
    // 2) Función principal: obtiene datos y renderiza
    async function loadCars() {
      try {
        setStatus("Cargando...", "loading");
    
        // Cambia esta URL por tu endpoint real (por ejemplo en JEE: /miApp/api/coches)
        const url = "coches.json"; // Para pruebas: archivo local con JSON
        const response = await fetch(url);
    
        // 3) Comprobamos si la respuesta HTTP es correcta
        if (!response.ok) {
          throw new Error(`HTTP ${response.status} - ${response.statusText}`);
        }
    
        // 4) Convertimos el body a JSON (array de objetos)
        const cars = await response.json();
    
        // 5) Si no hay datos, mostramos estado vacío
        if (!Array.isArray(cars) || cars.length === 0) {
          clearRows();
          setStatus("No hay datos disponibles.", "ok");
          return;
        }
    
        // 6) Pintamos los datos
        renderCars(cars);
        setStatus(`Cargados ${cars.length} registros.`, "ok");
    
      } catch (error) {
        clearRows();
        setStatus(`Error cargando datos: ${error.message}`, "error");
      }
    }
    
    // --- Renderizado ---
    
    function renderCars(cars) {
      const tbody = document.getElementById("rows");
      tbody.innerHTML = ""; // limpiamos antes de pintar
    
      // Creamos un fragmento para insertar todo de golpe (más eficiente)
      const fragment = document.createDocumentFragment();
    
      cars.forEach(car => {
        fragment.append(createRow(car));
      });
    
      tbody.append(fragment);
    }
    
    function createRow(car) {
      const tr = document.createElement("tr");
    
      const tdId = document.createElement("td");
      tdId.textContent = car.id;
    
      const tdMarca = document.createElement("td");
      tdMarca.textContent = car.marca;
    
      const tdModelo = document.createElement("td");
      tdModelo.textContent = car.modelo;
    
      const tdPrecio = document.createElement("td");
      tdPrecio.textContent = car.precio;
    
      tr.append(tdId, tdMarca, tdModelo, tdPrecio);
      return tr;
    }
    
    function clearRows() {
      document.getElementById("rows").innerHTML = "";
    }
    
    // --- Estado UI (mensajes) ---
    
    function setStatus(message, type) {
      const status = document.getElementById("status");
      status.textContent = message;
    
      // Reseteamos clases y aplicamos la nueva
      status.classList.remove("loading", "error", "ok");
      status.classList.add(type);
    }

    Qué has aprendido aquí

    • DOMContentLoaded asegura que el HTML existe antes de seleccionar nodos.
    • fetch() hace la petición.
    • response.ok comprueba si el HTTP fue bien.
    • response.json() parsea la respuesta.
    • renderCars() separa “pintar” de “cargar datos”.
    • setStatus() maneja estados.

    3) JSON de prueba (para que funcione sin backend)

    Crea coches.json en la misma carpeta:

    [
      { "id": 1, "marca": "Toyota", "modelo": "Corolla", "precio": 20000 },
      { "id": 2, "marca": "Ford", "modelo": "Focus", "precio": 18000 },
      { "id": 3, "marca": "Seat", "modelo": "Ibiza", "precio": 15500 }
    ]

    4) Nota importante (muy típica en clase)

    Si abres index.html haciendo doble clic (ruta file://), en algunos navegadores el fetch("coches.json") puede fallar por permisos.

    Soluciones sencillas para clase:

    • Servirlo desde un servidor local (ideal).
    • Si ya estás con JEE, sirve la página desde tu propio proyecto y el endpoint desde el servlet.

    5) Conectarlo a JEE

    Cuando tengas tu endpoint en JEE, normalmente será algo así:

    • URL: /miApp/api/coches
    • Devuelve JSON

    Solo cambias:

    consturl="/miApp/api/coches";

    Y listo.

  • 3.3 – DEL JSON AL DOM

    3.3 – DEL JSON AL DOM

    Este es el paso donde el frontend deja de ser estático y pasa a ser dinámico y conectado al backend.


    2. Qué es JSON

    JSON (JavaScript Object Notation) es el formato estándar para intercambiar datos entre backend y frontend.

    Ejemplo:

    [
      { "id": 1, "marca": "Toyota", "modelo": "Corolla", "precio": 20000 },
      { "id": 2, "marca": "Ford", "modelo": "Focus", "precio": 18000 }
    ]

    En JavaScript, JSON se convierte automáticamente en objetos reales:

    const coches = [
      { id: 1, marca: "Toyota", modelo: "Corolla", precio: 20000 },
      { id: 2, marca: "Ford", modelo: "Focus", precio: 18000 }
    ];

    3. Obtener datos desde el backend — fetch()

    El navegador permite hacer peticiones HTTP con fetch().

    Ejemplo básico

    fetch("/api/coches")
      .then(response => response.json())
      .then(data => {
        console.log(data);
      });

    Versión moderna con async/await:

    async function cargarDatos() {
    const response = await fetch("/api/coches");
    const data = await response.json();
    console.log(data);
    }

    cargarDatos();

    4. Patrón

    Todo frontend profesional sigue este patrón:

    1. Obtener datos
    2. Transformar datos
    3. Renderizar DOM

    Nunca mezclar todo en una sola función gigante.


    5. Separación de responsabilidades

    Estructura recomendada:

    • load() → obtiene datos del backend
    • render(data) → pinta el DOM
    • setLoading() → estado de carga
    • setError() → muestra errores

    Este patrón es equivalente a separar DAO / Service / Controller en Java.


    6. Renderizar datos en el DOM

    Supongamos este HTML:

    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Marca</th>
          <th>Modelo</th>
          <th>Precio</th>
        </tr>
      </thead>
      <tbody id="rows"></tbody>
    </table>

    Función para crear una fila

    function filaCoche(coche) {
      const tr = document.createElement("tr");
    
      const tdId = document.createElement("td");
      tdId.textContent = coche.id;
    
      const tdMarca = document.createElement("td");
      tdMarca.textContent = coche.marca;
    
      const tdModelo = document.createElement("td");
      tdModelo.textContent = coche.modelo;
    
      const tdPrecio = document.createElement("td");
      tdPrecio.textContent = coche.precio;
    
      tr.append(tdId, tdMarca, tdModelo, tdPrecio);
    
      return tr;
    }

    Función render

    function render(coches) {
      const tbody = document.getElementById("rows");
      tbody.innerHTML = "";
    
      coches.forEach(coche => {
        const fila = filaCoche(coche);
        tbody.append(fila);
      });
    }

    Conectar con fetch

    async function load() {
      try {
        setLoading(true);
    
        const response = await fetch("/api/coches");
        const coches = await response.json();
    
        render(coches);
    
      } catch (error) {
        setError("Error cargando datos");
      } finally {
        setLoading(false);
      }
    }
    
    load();

    7. Estados de la interfaz

    Toda aplicación debe manejar tres estados.

    Estado de carga

    function setLoading(estado) {
      const status = document.getElementById("status");
      status.textContent = estado ? "Cargando..." : "";
    }

    Estado de error

    function setLoading(estado) {
      const status = document.getElementById("status");
      status.textContent = estado ? "Cargando..." : "";
    }

    Estado vacío

    function setLoading(estado) {
      const status = document.getElementById("status");
      status.textContent = estado ? "Cargando..." : "";
    }

    8. Transformar datos antes de renderizar

    A veces el frontend necesita modificar los datos.

    Ejemplo:

    const cochesCaros = coches.filter(c => c.precio > 19000);
    render(cochesCaros);

    También puedes usar:

    • map() → transformar
    • filter() → filtrar
    • sort() → ordenar

    9. Eventos sobre elementos generados dinámicamente

    Si el DOM se crea con JavaScript, los eventos deben añadirse también dinámicamente.

    Ejemplo botón:

    const btn = document.createElement("button");
    btn.textContent = "Ver";
    
    btn.addEventListener("click", () => {
      console.log("Coche:", coche.id);
    });

    10. Delegación de eventos (concepto importante)

    En vez de poner un listener en cada fila:

    tbody.addEventListener("click", e => {
      if (e.target.classList.contains("ver")) {
        const id = e.target.dataset.id;
        console.log("Ver coche", id);
      }
    });

    Esto permite manejar eventos en elementos creados dinámicamente.

  • 3.4 ¿Qué es forEach() y para qué sirve?

    3.4 ¿Qué es forEach() y para qué sirve?

    forEach() es un método de los arrays que permite recorrer todos sus elementos y ejecutar una función (un bloque de código) para cada uno.

    Piensa en ello como:
    “Para cada elemento del array, haz esto…”

    Se usa mucho para:

    • Mostrar elementos por pantalla o en consola
    • Calcular totales o acumuladores
    • Transformar datos (aunque para transformar suele ser mejor map())
    • Buscar / filtrar (aunque para eso suelen ser mejores find() y filter())

    2) Sintaxis básica

    array.forEach(function(elemento) {
    // código que se ejecuta por cada elemento
    });

    Versión con función flecha (la más común hoy):

    array.forEach((elemento) => {
    // código por cada elemento
    });

    3) Parámetros de la función callback

    La función que pasas a forEach() puede recibir hasta 3 parámetros:

    array.forEach((elemento, indice, arrayCompleto) => {
    // elemento: valor actual
    // indice: posición del elemento
    // arrayCompleto: el array original
    });

    Ejemplo (elemento + índice)

    const nombres = ["Ana", "Luis", "Marta"];
    nombres.forEach((nombre, i) => {
      console.log(i, nombre);
    });

    Explicación: recorre el array y muestra el índice y el nombre de cada posición.


    4) Ejemplos típicos

    4.1 Mostrar cada elemento

    const frutas = ["manzana", "pera", "plátano"];
    frutas.forEach((fruta) => {
      console.log(fruta);
    });

    Explicación: imprime cada fruta en una línea.


    4.2 Sumar valores (acumulador)

    const precios = [10, 20, 5];
    let total = 0;
    precios.forEach((p) => {
      total += p;
    });
    console.log("Total:", total);

    Explicación: forEach() recorre los precios y vamos sumando cada uno en total.


    4.3 Construir un string con los elementos

    const letras = ["A", "B", "C"];
    let resultado = "";
    letras.forEach((l) => {
      resultado += l + "-";
    });
    console.log(resultado); // "A-B-C-"

    Explicación: concatenamos cada letra para crear una cadena final.


    4.4 Recorrer un array de objetos

    const alumnos = [
      { nombre: "Bea", nota: 8 },
      { nombre: "Dani", nota: 5 },
      { nombre: "Sara", nota: 9 }
    ];
    alumnos.forEach((a) => {
      console.log(`${a.nombre} tiene un ${a.nota}`);
    });

    Explicación: forEach() va pasando por cada objeto y accedemos a sus propiedades.


    4.5 Crear elementos en el DOM (lista HTML)

    HTML:

    <ul id="lista"></ul>

    JS:

    const tareas = ["Estudiar", "Entrenar", "Leer"];
    const ul = document.querySelector("#lista");
    tareas.forEach((tarea) => {
      const li = document.createElement("li");
      li.textContent = tarea;
      ul.appendChild(li);
    });

    Explicación: por cada tarea creamos un <li> y lo añadimos dentro del <ul>.


    5) Cosas IMPORTANTES que debes saber

    5.1 forEach() NO devuelve un array nuevo

    forEach() siempre devuelve undefined.

    const nums = [1, 2, 3];
    const r = nums.forEach((n) => n * 2);console.log(r); // undefined
    
    
    const nums = [1, 2, 3];
    const dobles = nums.map((n) => n * 2);console.log(dোবles); // [2, 4, 6]

    5.2 No puedes “parar” un forEach() con break

    Con forEach() no se usa break ni continue.

    Si necesitas parar cuando encuentras algo, mejor:

    • for...of
    • some() (para parar cuando se cumple una condición)
    • find() (para encontrar el primero que cumpla)

    Ejemplo con for...of:

    const nums = [2, 4, 7, 10];
    for (const n of nums) {
      if (n === 7) 
        console.log(n);
    }

    Explicación: aquí sí se puede detener el bucle con break.


    5.3 Puedes modificar el array (pero cuidado)

    Se puede, pero puede provocar efectos raros si borras/añades elementos mientras recorres.

    const a = [1, 2, 3];a.forEach((n, i) => {
    a[i] = n * 10;
    });console.log(a); // [10, 20, 30]

    Explicación: aquí funciona bien porque solo reemplazamos valores.


    6) forEach() vs otros métodos (mini guía)

    • forEach(): recorrer y “hacer algo” (mostrar, acumular, crear DOM…)
    • map(): crear un array nuevo transformado
    • filter(): crear un array nuevo filtrado
    • find(): obtener el primer elemento que cumpla
    • some(): comprobar si alguno cumple (y se puede “parar” antes)
    • every(): comprobar si todos cumplen

    7) Trabajando con el DOM

    Vamos a hacer algo muy realista: tienes un array con nombres en JavaScript y quieres que automáticamente se construya una lista <ul> en el HTML usando forEach().

    Dado este array:

    const nombres = ["Ana", "Luis", "Marta", "Carlos", "Beatriz"];

    Queremos generar dinámicamente esto en el HTML:

    <ul>
    <li>Ana</li>
    <li>Luis</li>
    <li>Marta</li>
    <li>Carlos</li>
    <li>Beatriz</li>
    </ul>

    Sin escribir los <li> a mano. Que lo haga JavaScript.


    HTML

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <title>Ejemplo forEach</title>
    </head>
    <body> <h2>Lista de alumnos</h2>
    <ul id="listaNombres"></ul> <script src="script.js"></script>
    </body>
    </html>

    Observa el detalle importante:

    <ul id="listaNombres"></ul>

    Ese id es el punto de anclaje. Ahí vamos a insertar los <li>.


    JavaScript (script.js)

    // Array de nombres
    const nombres = ["Ana", "Luis", "Marta", "Carlos", "Beatriz"];
    
    // Seleccionamos el <ul>
    const ul = document.getElementById("listaNombres");
    
    // Recorremos el array
    nombres.forEach((nombre) => {
    
      // 1. Crear el elemento <li>
      const li = document.createElement("li");
    
      // 2. Añadir el texto
      li.textContent = nombre;
    
      // 3. Insertarlo dentro del <ul>
      ul.appendChild(li);
    
    });

    ¿Qué está pasando exactamente?

    1. forEach() recorre cada nombre del array.
    2. En cada vuelta:
      • Creamos un <li>
      • Le ponemos el texto del nombre actual
      • Lo añadimos al <ul>

    Es como una pequeña fábrica automática de etiquetas HTML.


    Versión con índice incluido

    Si quieres que aparezca numerado:

    nombres.forEach((nombre, indice) => {  
    const li = document.createElement("li");
      li.textContent = (indice + 1) + ". " + nombre;  
    ul.appendChild(li);
    });

    Resultado:

    1. Ana
    2. Luis
    3. Marta
    4. Carlos
    5. Beatriz

    ⚠️ Error común de principiante

    ul.innerHTML += "<li>" + nombre + "</li>";

    Funciona… pero:

    • Es menos eficiente
    • Puede romper eventos
    • Es menos seguro si el contenido viene del usuario

    Crear elementos con createElement() es la forma correcta y profesional.


    Idea para subir un poco el nivel

    Puedes hacer que si el nombre empieza por “B” se pinte en rojo:

    nombres.forEach((nombre) => {  
    const li = document.createElement("li");
      li.textContent = nombre;  
    if (nombre.startsWith("B")) {
        li.style.color = "red";
      }  
    ul.appendChild(li);});

    Ahora ya no solo recorremos. También tomamos decisiones dentro del recorrido.

    Eso ya es pensar como programador y no como copiador de código.


    Si quieres, podemos convertir esto en una pequeña práctica gamificada para tus alumnos tipo “constructor automático de lista dinámica”, donde luego tengan que añadir botones para borrar nombres o añadir nuevos desde un input. Ahí empiezan a entender realmente el poder del DOM y los arrays trabajando juntos.

    8. Ejemplo con un JSON

    amos a hacer el caso típico:

    Tenemos un JSON con productos y queremos generar automáticamente la ficha de cada producto en HTML.

    Nada de copiar y pegar tarjetas manualmente. Que la máquina trabaje.


    1️⃣ El JSON de productos

    Imaginemos que tenemos esto en un archivo llamado productos.json:

    [
    {
    "id": 1,
    "nombre": "Portátil Gaming",
    "precio": 1299,
    "imagen": "https://via.placeholder.com/200",
    "descripcion": "Portátil potente para desarrollo y juegos."
    },
    {
    "id": 2,
    "nombre": "Teclado Mecánico",
    "precio": 89,
    "imagen": "https://via.placeholder.com/200",
    "descripcion": "Teclado con switches mecánicos retroiluminado."
    },
    {
    "id": 3,
    "nombre": "Ratón Inalámbrico",
    "precio": 49,
    "imagen": "https://via.placeholder.com/200",
    "descripcion": "Ratón ergonómico con batería recargable."
    }
    ]

    Es simplemente un array de objetos. Nada místico.


    2️⃣ HTML

    <!DOCTYPE html>
    <html lang="es">
    <head>
    <meta charset="UTF-8">
    <title>Productos</title>
    <style>
    .contenedor {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    } .producto {
    border: 1px solid #ccc;
    padding: 15px;
    width: 220px;
    border-radius: 8px;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    } .producto img {
    width: 100%;
    } .precio {
    font-weight: bold;
    color: green;
    }
    </style>
    </head>
    <body> <h2>Catálogo de Productos</h2>
    <div id="contenedorProductos" class="contenedor"></div> <script src="script.js"></script>
    </body>
    </html>

    Observa el div vacío:

    <div id="contenedorProductos"></div>

    Ahí vamos a inyectar todas las fichas dinámicamente.


    3️⃣ JavaScript (leer JSON y generar fichas)

    // Seleccionamos el contenedor
    const contenedor = document.getElementById("contenedorProductos");
    
    // Leer el JSON
    fetch("productos.json")
      .then(response => response.json())
      .then(productos => {
    
        productos.forEach(producto => {
    
          // Crear tarjeta
          const tarjeta = document.createElement("div");
          tarjeta.classList.add("producto");
    
          tarjeta.innerHTML = `
            <img src="${producto.imagen}" alt="${producto.nombre}">
            <h3>${producto.nombre}</h3>
            <p>${producto.descripcion}</p>
            <p class="precio">${producto.precio} €</p>
            <button>Comprar</button>
          `;
    
          contenedor.appendChild(tarjeta);
    
        });
    
      })
      .catch(error => {
        console.error("Error al cargar los productos:", error);
      });

    ¿Qué está pasando aquí?

    1. fetch() pide el archivo JSON.
    2. .json() convierte la respuesta en objeto JavaScript.
    3. forEach() recorre cada producto.
    4. Para cada producto:
      • Creamos un div
      • Insertamos su contenido dinámicamente
      • Lo añadimos al contenedor

    Es literalmente una fábrica automática de fichas.

    Si mañana el JSON tiene 200 productos, se generarán 200 tarjetas.
    Eso es separar datos de presentación. Arquitectura básica pero poderosa.


    Ejercicios propuestos

    Ejercicio 1

    Dado el array:

    const nums = [3, 6, 9, 12];

    Muestra en consola cada número y su índice.


    Ejercicio 2

    Calcula la suma total de:

    const carrito = [12.99, 5.5, 3.25, 20];

    Ejercicio 3

    Dado:

    const alumnos = [
    { nombre: "Ana", nota: 4 },
    { nombre: "Luis", nota: 7 },
    { nombre: "Marta", nota: 9 }
    ];

    Muestra solo un mensaje por alumno con “APTO” si la nota es >= 5, y “NO APTO” si es < 5.


    Ejercicio 4 (DOM)

    Crea una lista <ul> en HTML y rellénala con un array de strings usando forEach().


    Métodos y propiedades utilizados

    Método / PropiedadTipo¿Dónde se usa?¿Para qué sirve?¿Devuelve algo?
    document.getElementById()DOMdocument.getElementById("contenedorProductos")Selecciona un elemento del HTML por su idEl elemento encontrado
    fetch()Web APIfetch("productos.json")Realiza una petición HTTP para obtener datosUna Promise
    .then()Promisefetch(...).then(...)Ejecuta código cuando la promesa se resuelveOtra Promise
    .json()Responseresponse.json()Convierte la respuesta HTTP en objeto JavaScriptUna Promise con el JSON convertido
    .forEach()Arrayproductos.forEach(...)Recorre cada elemento del arrayundefined
    document.createElement()DOMdocument.createElement("div")Crea un nuevo elemento HTMLEl elemento creado
    .classList.add()DOMtarjeta.classList.add("producto")Añade una clase CSS a un elementoundefined
    .appendChild()DOMcontenedor.appendChild(tarjeta)Inserta un elemento dentro de otroEl nodo añadido
    .append()DOMtarjeta.append(...)Añade uno o varios elementos hijosundefined
    .textContentPropiedad DOMtitulo.textContent = producto.nombreAsigna texto a un elementoNo devuelve valor (es asignación)
    .innerHTMLPropiedad DOMtarjeta.innerHTML = \…«Inserta HTML directamente dentro de un elementoNo devuelve valor (es asignación)
    .catch()Promise.catch(error => {...})Captura errores en promesasUna Promise

  • [Reto] – Tu propio juego con Slider y DOM

    [Reto] – Tu propio juego con Slider y DOM

    En el siguiente video se muestra un pequeño juego interactivo construido con HTML, CSS y JavaScript, utilizando:

    • Manipulación del DOM
    • Eventos (click, teclado, etc.)
    • Gestión de estado
    • Lógica de juego
    • Datos estructurados (JSON con imágenes, título y ALT) o Arrays

    Ahora te toca a ti.

    No debes copiar el juego.
    Debes crear tu propia versión.


    Diseña y programaun pequeño juego interactivo basado en:

    • Un slider de imágenes
    • Interacción del usuario
    • Alguna regla o mecánica de juego

    No tiene que ser igual al del video.
    No tiene que ser perfecto.


    Material que recibirás

    • Carpeta con imágenes de paisajes
    • Video mostrando el funcionamiento del juego
    • (Más adelante) el código de referencia para comparar

    Requisitos

    Tu juego debe incluir:

    1. Un slider funcional
      • Cambiar imágenes
      • Mostrar título
      • Usar DOM
    2. Algún tipo de interacción
      • Botón
      • Teclado
      • Evento
    3. Una regla de juego
      • Adivinar imagen
      • Secuencia
      • Puntos
      • Vidas
      • Tiempo
      • O cualquier idea propia
    4. Mostrar feedback en pantalla
      • Mensaje
      • Resultado
      • Estado del juego

    Libertad creativa (muy importante)

    Puedes hacer:

    • Un juego más simple
    • Un juego más complejo
    • Algo distinto al video
    • Otra mecánica
    • Otra dificultad
    • Otra estética
    • Otra lógica

    No se evalúa que sea igual.
    Se evalúa que funcione y que lo entiendas.


    Pistas para empezar (no obligatorias)

    Puedes usar ideas como:

    • Imagen secreta
    • Vidas
    • Contador
    • Secuencia
    • Puntos
    • Cronómetro
    • Imagen aleatoria
    • Teclas izquierda/derecha
    • Botón “Probar”
    • JSON con imágenes

    Pero también puedes inventar tu propio sistema.


    Evaluación

    Se valorará:

    • Que el slider funcione
    • Uso correcto del DOM
    • Lógica del juego
    • Claridad del código
    • Que no esté copiado
    • Creatividad
    • Complejidad acorde a tu nivel

    No todos debéis hacer lo mismo.
    Cada alumno llegará hasta donde pueda.


    Segunda fase (muy importante)

    Cuando termines:

    1. Recibirás el código del juego mostrado en el video.
    2. Deberás compararlo con el tuyo.
    3. Analizar:
      • Qué hiciste diferente
      • Qué hiciste mejor
      • Qué no entendías antes y ahora sí
      • Qué mejorarías

    Esto forma parte del aprendizaje.


    Filosofía del ejercicio

    Programar no es copiar.
    Programar es entender, probar, fallar, ajustar y construir.

    Si tu juego funciona, aunque sea simple… has ganado.
    Si además lo entiendes… entonces ya estás programando de verdad.

    Y cuando compares tu código con otro, verás algo fascinante:
    dos soluciones distintas pueden resolver el mismo problema.

    Recursos


    Para poner emoticons facilmente:

    https://emojipedia.org/

    Aleatorios en Javascript

    function randomInt(min, max) {
           return Math.floor(Math.random() * (max - min + 1)) + min;
    }
  • ¿Qué es una expresión regular?

    ¿Qué es una expresión regular?

    Una expresión regular (RegExp) es un patrón que se utiliza para buscar, validar o extraer texto dentro de una cadena.

    Piensa en ellas como:

    🔎 Un detector de patrones dentro del texto.

    Sirven para:

    • Validar formularios (email, DNI, teléfono…)
    • Buscar palabras en textos
    • Reemplazar partes de una cadena
    • Extraer información estructurada

    2. Cómo se escriben en JavaScript

    En JavaScript existen dos formas:

    Forma literal (la más común)

    let regex = /patron/;

    Con el constructor RegExp

    let regex = new RegExp("patron");

    En clase usaremos principalmente la forma literal porque es más clara.


    3. Métodos principales para usar expresiones regulares

    test()

    Devuelve true o false.

    let texto = "Hola mundo";
    let regex = /Hola/;
    console.log(regex.test(texto)); // true

    match()

    Devuelve coincidencias.

    let texto = "Tengo 2 perros y 3 gatos";
    let regex = /\d/g;
    console.log(texto.match(regex)); // ["2", "3"]

    \d significa “digit”, es decir, cualquier número del 0 al 9.
    Es equivalente a escribir:

    /[0-9]/

    Segundo: la barra / /

    Las barras indican que lo que hay dentro es una expresión regular.

    Tercero: la g

    La g es una bandera (flag) que significa global.
    Le dice al motor:

    «No te quedes con la primera coincidencia. Busca todas.»


    replace()

    Permite reemplazar coincidencias.

    let texto = "Hola mundo";
    let regex = /mundo/;
    console.log(texto.replace(regex, "Antonio"));
    // Hola Antonio

    4. Sintaxis básica (los símbolos importantes)

    Aquí empieza la magia real.

    Texto literal

    /Hola/

    Busca exactamente “Hola”.


    . (punto)

    Representa cualquier carácter excepto salto de línea.

    /h.la/

    Coincide con:

    • hola
    • hXla
    • h9la

    \d

    Representa un número (0–9).

    /\d/

    \w

    Representa letra, número o guion bajo.


    \s

    Representa espacio en blanco.


    5. Cuantificadores (cuántas veces aparece algo)

    *

    Cero o más veces.

    /ho*/

    Coincide con:

    • h
    • ho
    • hoo
    • hooooo

    +

    Una o más veces.

    /ho+/

    Coincide con:

    • ho
    • hoo
    • hooo

    No coincide con solo “h”.


    ?

    Cero o una vez.


    {n}

    Exactamente n veces.

    /\d{3}/

    Tres números seguidos.


    {n,m}

    Entre n y m veces.

    /\d{2,4}/

    Entre 2 y 4 números seguidos.


    6. Grupos y alternativas

    Paréntesis ()

    Permiten agrupar.

    /(hola)+/

    |

    Equivale a “o”.

    /(perro|gato)/

    Coincide con:

    • perro
    • gato

    7. Anclas (inicio y fin)

    ^

    Inicio de texto.

    /^Hola/

    $

    Fin de texto.

    /mundo$/

    8. Banderas (modificadores)

    Se colocan al final:

    /patron/g

    g → global

    Busca todas las coincidencias.

    i → ignore case

    Ignora mayúsculas/minúsculas.

    m → multiline

    Ejemplo:

    /hola/i

    Coincide con:

    • hola
    • Hola
    • HOLA

    9. Casos prácticos reales

    Validar un email simple

    let email = "usuario@email.com";
    let regex = /^[\w.-]+@[\w.-]+\.\w{2,}$/;
    console.log(regex.test(email));

    Explicación simplificada:

    • Texto antes del @
    • @
    • Dominio
    • Punto
    • Extensión de al menos 2 letras

    Validar un número de teléfono español (9 dígitos)

    let telefono = "612345678";
    let regex = /^[6-9]\d{8}$/;
    console.log(regex.test(telefono));

    Extraer números de un texto

    let texto = "Pedido 123 con código 456";
    let regex = /\d+/g;
    console.log(texto.match(regex));

    10. Patrón mental para entenderlas

    Una expresión regular siempre responde a 3 preguntas:

    1. ¿Qué estoy buscando?
    2. ¿Cuántas veces debe aparecer?
    3. ¿Dónde debe estar (inicio, fin, en cualquier parte)?

    Si los alumnos entienden eso, ya dominan el 80%.


    11. Errores comunes

    • Olvidar la bandera g
    • No escapar caracteres especiales como .
    • Confundir * con +
    • No usar ^ y $ en validaciones

    12. Recomendación para practicar

    Sitios útiles:

    Permiten probar en tiempo real.

    Ejemplos

    1️⃣ Detectar si un texto contiene números

    function contieneNumeros(texto) {
    let regex = /\d/;
    return regex.test(texto);
    }console.log(contieneNumeros("Hola mundo")); // false
    console.log(contieneNumeros("Hola 2026")); // true

    Aquí usamos test() porque solo queremos verdadero o falso.


    2️⃣ Extraer todos los números de un texto

    function extraerNumeros(texto) {
    let regex = /\d+/g;
    return texto.match(regex);
    }console.log(extraerNumeros("Pedido 123 y código 456"));
    // ["123", "456"]

    Aquí usamos \d+ porque queremos números completos, no dígitos sueltos.


    3️⃣ Validar un email sencillo

    No vamos a hacer el monstruo RFC de 3 kilómetros. Algo razonable para clase.

    function validarEmail(email) {
        let regex = /^[\w.-]+@[\w.-]+\.\w{2,}$/;
        return regex.test(email);
    }
    console.log(validarEmail("antonio@email.com")); // true
    console.log(validarEmail("antonio@email"));     // false

    Observa el uso de ^ y $ para asegurar que coincide TODO el texto.


    4️⃣ Validar teléfono español (9 cifras empezando por 6, 7, 8 o 9)

    function validarTelefono(telefono) {
        let regex = /^[6-9]\d{8}$/;
        return regex.test(telefono);
    }
    console.log(validarTelefono("612345678")); // true
    console.log(validarTelefono("123456789")); // false

    Aquí enseñamos:

    • [6-9] → rango
    • \d{8} → exactamente 8 números
    • ^ y $ → validación completa

    5️⃣ Extraer hashtags de un texto

    function extraerHashtags(texto) {
        let regex = /#\w+/g;
        return texto.match(regex);
    }
    console.log(extraerHashtags("Aprendiendo #JavaScript y #Regex"));
    // ["#JavaScript", "#Regex"]

    Aquí aparece algo interesante: # es literal, pero \w+ captura letras y números después.


    6️⃣ Validar contraseña básica

    Condiciones:

    • mínimo 8 caracteres
    • al menos una mayúscula
    • al menos un número
    function validarPassword(password) {
        let regex = /^(?=.*[A-Z])(?=.*\d).{8,}$/;
        return regex.test(password);
    }
    console.log(validarPassword("Hola1234"));   // true
    console.log(validarPassword("hola1234"));   // false

    Aquí introduces algo más avanzado:
    (?=...)lookahead positivo.

    Es como decir:

    “Antes de aceptar esto, asegúrate de que en algún lugar hay una mayúscula y un número.”

    Es un nivel más pro, pero abre la puerta a conversaciones interesantes.


    7️⃣ Reemplazar espacios múltiples por uno solo

    function limpiarEspacios(texto) {
        let regex = /\s+/g;
        return texto.replace(regex, " ");
    }
    console.log(limpiarEspacios("Hola    mundo    cruel"));
    // "Hola mundo cruel"

    Elementos para construir una Expresión Regular (JavaScript)

    ElementoSímbolo¿Qué hace?EjemploCoincide con
    Texto literalholaBusca exactamente ese texto/hola/hola
    Cualquier carácter.Cualquier carácter excepto salto de línea/h.la/hola, h9la
    Número\dUn dígito (0-9)/\d/5
    No número\DCualquier cosa que NO sea número/\D/a, #
    Letra/número/_\wCarácter alfanumérico o _/\w/a, 3, _
    No alfanumérico\WLo contrario de \w/\W/@, #
    Espacio\sEspacio, tabulación, salto de línea/\s/» «
    No espacio\SCualquier cosa que no sea espacio/\S/a

    📌 Cuantificadores (cantidad)

    SímboloSignificadoEjemploCoincide con
    *0 o más veces/ho*/h, ho, hoo
    +1 o más veces/ho+/ho, hoo
    ?0 o 1 vez/colou?r/color, colour
    {n}Exactamente n veces/\d{3}/123
    {n,}n o más veces/\d{2,}/12, 1234
    {n,m}Entre n y m veces/\d{2,4}/12, 1234

    📌 Conjuntos y rangos

    SímboloSignificadoEjemploCoincide con
    [abc]a o b o c/[aeiou]/a, e
    [a-z]Rango/[a-z]/cualquier minúscula
    [A-Z]Mayúsculas/[A-Z]/A
    [0-9]Números/[0-9]/7
    [^abc]Todo excepto a, b o c/[^0-9]/letras

    📌 Posición (anclas)

    SímboloSignificadoEjemploCoincide con
    ^Inicio del texto/^Hola/Hola mundo
    $Fin del texto/mundo$/Hola mundo

    📌 Agrupación y alternativas

    SímboloSignificadoEjemploCoincide con
    ( )Agrupa/(hola)+/holahola
    ``Alternativa (o)`/(perro

    📌 Banderas (modificadores)

    Se colocan al final:

    BanderaSignificadoEjemplo
    gGlobal (todas las coincidencias)/\d/g
    iIgnora mayúsculas/minúsculas/hola/i
    mMultilínea/^hola/m

  • VALIDACIÓN DE FORMULARIOS EN JAVASCRIPT

    VALIDACIÓN DE FORMULARIOS EN JAVASCRIPT


    1. Introducción

    Validar un formulario significa comprobar que los datos introducidos cumplen ciertas reglas antes de enviarlos.

    Hay dos tipos de validación:

    • Cliente (JavaScript) → mejora la experiencia del usuario.
    • Servidor (backend) → garantiza seguridad real.

    Importante: La validación en JavaScript se puede saltar. Nunca sustituye la validación del servidor.


    2. Estructura base del formulario

    <form id="registroForm" novalidate>  
    <div class="field">
        <label for="nombre">Nombre</label>
        <input type="text" id="nombre" name="nombre">
        <small class="error" data-for="nombre"></small>
      </div>  
    <button type="submit">Enviar</button></form>

    Explicación

    • id="registroForm" permite acceder al formulario desde JavaScript.
    • novalidate desactiva la validación automática de HTML5 para que podamos controlarla manualmente.
    • <small class="error"> es donde mostraremos mensajes de error dinámicamente.
    • data-for="nombre" conecta el mensaje con el campo correspondiente.

    Esto separa contenido (HTML) de comportamiento (JS).


    3. Capturar el evento submit

    const form = document.getElementById("registroForm");
    form.addEventListener("submit", function(e){
        e.preventDefault();   
     if(validarFormulario()){
            alert("Formulario válido. Enviando...");
            form.reset();
        }
    });

    Explicación

    • addEventListener("submit") escucha cuando el usuario intenta enviar el formulario.
    • e.preventDefault() evita que el formulario se envíe automáticamente.
    • Se llama a validarFormulario().
    • Si devuelve true, el formulario se considera válido.

    Aquí estamos controlando el flujo manualmente.


    4. Función limpiarErrores()

    function limpiarErrores(){
    document.querySelectorAll(".error").forEach(e => e.textContent = "");
    document.querySelectorAll("input").forEach(i => i.removeAttribute("aria-invalid"));
    }

    Explicación

    • querySelectorAll(".error") selecciona todos los mensajes de error.
    • textContent = "" los vacía.
    • También eliminamos el atributo aria-invalid, que usamos para marcar visualmente campos erróneos.

    Siempre limpiamos antes de volver a validar para evitar acumular errores antiguos.


    5. Función mostrarError()

    function mostrarError(campo, mensaje){
    const error = document.querySelector(`.error[data-for="${campo}"]`);
    error.textContent = mensaje; const input = document.getElementById(campo);
    if(input){
    input.setAttribute("aria-invalid", "true");
    }
    }

    Explicación

    • Busca el elemento <small> correspondiente al campo.
    • Muestra el mensaje de error.
    • Marca el input con aria-invalid="true".

    aria-invalid mejora accesibilidad y permite aplicar estilos CSS al campo incorrecto.


    6. Validación SIN expresiones regulares


    6.1 Campo obligatorio

    if(nombre.trim() === ""){
    mostrarError("nombre", "El nombre es obligatorio");
    }

    Explicación

    • trim() elimina espacios al inicio y final.
    • Si el resultado es cadena vacía, el campo no contiene datos reales.
    • Es la validación más básica y necesaria.

    6.2 Longitud mínima

    if(nombre.length < 3){
    mostrarError("nombre", "Debe tener al menos 3 caracteres");
    }

    Explicación

    • length mide número de caracteres.
    • Permite exigir tamaño mínimo.
    • Útil para nombres, usuarios, contraseñas simples.

    6.3 Detectar números en un texto

    if([...nombre].some(c => c >= "0" && c <= "9")){
    mostrarError("nombre", "No debe contener números");
    }

    Explicación

    • [...nombre] convierte la cadena en array de caracteres.
    • some() comprueba si al menos uno cumple la condición.
    • Se evalúa si algún carácter está entre «0» y «9».

    Esto demuestra lógica sin usar regex.


    6.4 Validar número y rango

    const edad = Number(edadInput);if(!Number.isFinite(edad)){
    mostrarError("edad", "Debe ser un número válido");
    }
    else if(edad < 16 || edad > 120){
    mostrarError("edad", "Edad fuera de rango");
    }

    Explicación

    • Number() convierte texto en número.
    • Number.isFinite() verifica que sea número real.
    • Luego se comprueba rango lógico.

    Se valida tipo y regla de negocio.


    6.5 Email simple (sin regex)

    function emailSimple(email){
    const at = email.indexOf("@");
    const dot = email.lastIndexOf(".");
    return at > 0 && dot > at + 1 && dot < email.length - 1;
    }

    Explicación

    • Busca posición de @.
    • Busca posición del último punto.
    • Comprueba que:
      • El @ no esté al inicio.
      • El punto esté después del @.
      • El punto no esté al final.

    No es perfecto, pero didáctico.


    6.6 Comparar contraseñas

    if(password !== password2){
    mostrarError("password2", "Las contraseñas no coinciden");
    }

    Explicación

    • Compara cadenas directamente.
    • !== exige igualdad exacta.
    • Es una validación lógica, no de formato.

    6.7 Validar radio obligatorio

    const contacto = document.querySelector('input[name="contacto"]:checked');
    if(!contacto){
        mostrarError("contacto", "Seleccione una opción");
    }

    Explicación

    • :checked selecciona el radio marcado.
    • Si devuelve null, ninguno está seleccionado.
    • Obliga al usuario a tomar decisión.

    6.8 Validar checkbox obligatorio

    if(!document.getElementById("condiciones").checked){
    mostrarError("condiciones", "Debe aceptar las condiciones");
    }

    Explicación

    • .checked devuelve true o false.
    • Es típico en aceptación de condiciones legales.
    • Se usa como bloqueo final del envío.

    7. VALIDACIÓN CON EXPRESIONES REGULARES

    Las expresiones regulares permiten definir patrones complejos.


    7.1 Email con regex

    const RE_EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;if(!RE_EMAIL.test(email)){
    mostrarError("email", "Email inválido");
    }

    Explicación del patrón

    • ^ inicio de cadena
    • [^\s@]+ uno o más caracteres que no sean espacio ni @
    • @ símbolo obligatorio
    • [^\s@]+ dominio
    • \. punto literal
    • [^\s@]{2,} al menos 2 caracteres después del punto
    • $ final de cadena

    .test() devuelve true o false.


    7.2 Contraseña fuerte

    const RE_PASS = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/;

    Explicación

    • (?=.*[a-z]) al menos una minúscula
    • (?=.*[A-Z]) al menos una mayúscula
    • (?=.*\d) al menos un número
    • (?=.*[^A-Za-z0-9]) al menos un símbolo
    • .{8,} mínimo 8 caracteres

    Los (?=...) son “lookaheads”: condiciones que deben cumplirse.


    7.3 Teléfono (ejemplo España)

    const RE_TEL = /^[6789]\d{8}$/;

    Explicación

    • ^[6789] empieza por 6,7,8 o 9
    • \d{8} ocho dígitos
    • $ final de cadena

    Valida números de 9 cifras típicos en España.


    8. Validación en tiempo real

    form.nombre.addEventListener("blur", validarFormulario);
    form.password.addEventListener("input", validarFormulario);

    Explicación

    • blur se activa al salir del campo.
    • input se activa cada vez que cambia el valor.
    • Permite validar mientras el usuario escribe.

    Mejora experiencia.


    9. Validación HTML5 nativa

    <input type="email" required>
    <input type="number" min="16" max="120">
    <input type="text" pattern="[A-Za-z]{3,}">

    Explicación

    • required obliga a rellenar.
    • min y max definen rango.
    • pattern usa expresión regular directamente en HTML.

    Es útil, pero menos flexible que JavaScript personalizado.


    La validación no es solo técnica. Es diseño de interacción. Es impedir datos absurdos sin tratar al usuario como enemigo.


    Formas de enviar un formulario

    1️⃣ Envío tradicional (HTML puro)

    El navegador lo hace todo.

    <form action="procesar.php" method="POST">
    <input type="text" name="nombre">
    <button type="submit">Enviar</button>
    </form>

    Explicación

    • action → URL donde se envían los datos.
    • method → GET o POST.
    • El navegador recarga la página.
    • No necesitamos JavaScript.

    Es simple y robusto. Pero no es dinámico.


    2️⃣ Envío tradicional + validación JS

    Bloqueamos el envío si hay errores, pero dejamos que el navegador envíe normalmente si todo está bien.

    form.addEventListener("submit", function(e){    
    if(!validarFormulario()){
            e.preventDefault(); // bloquea envío
        }});

    Explicación

    Aquí no usamos preventDefault() siempre.
    Solo bloqueamos si hay errores.

    Si la validación devuelve true, el navegador enviará el formulario usando action y method.

    Este es el enfoque híbrido más común.


    3️⃣ Envío manual usando form.submit()

    Podemos decidir cuándo enviar el formulario manualmente.

    form.addEventListener("submit", function(e){
        e.preventDefault();  
     
     if(validarFormulario()){
            form.submit();
        }
    });

    Explicación

    • Se bloquea el envío automático.
    • Si todo está correcto, lo forzamos manualmente.

    Útil si queremos hacer lógica adicional antes de enviar.


    4️⃣ Envío con GET (construyendo URL manualmente)

    form.addEventListener("submit", function(e){
        e.preventDefault();   
     if(validarFormulario()){        
            const nombre = form.nombre.value;
            const email = form.email.value;        
            const url = `procesar.php?nombre=${encodeURIComponent(nombre)}&email=${encodeURIComponent(email)}`;             
            window.location.href = url;
        }
    });

    Explicación

    • Construimos la URL manualmente.
    • encodeURIComponent() evita errores con espacios y símbolos.
    • El navegador navega a esa URL.

    GET muestra los datos en la barra del navegador.


    5️⃣ Envío con fetch (moderno y recomendado)

    Aquí no recargamos la página.

    form.addEventListener("submit", async function(e){
        e.preventDefault();    
    
    if(!validarFormulario()) return;    
    
    const datos = {
            nombre: form.nombre.value,
            email: form.email.value,
            edad: form.edad.value
        };  
     try{
            const respuesta = await fetch("procesar.php", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json"
                },
                body: JSON.stringify(datos)
            });       
     const resultado = await respuesta.text();       
     alert("Respuesta del servidor: " + resultado);   
     } catch(error){
            console.error("Error:", error);
        }});

    Explicación

    • fetch() envía datos sin recargar página.
    • Convertimos el objeto a JSON.
    • El servidor debe estar preparado para recibir JSON.
    • await pausa hasta recibir respuesta.

    Este es el método más moderno.


    6️⃣ Envío con FormData (muy práctico)

    Ideal si tienes muchos campos.

    form.addEventListener("submit", async function(e){
        e.preventDefault();  
    
      if(!validarFormulario()) return;   
    
     const formData = new FormData(form);    
    
    const respuesta = await fetch("procesar.php", {
            method: "POST",
            body: formData
        });  
    
    const texto = await respuesta.text();
        alert(texto);
    });

    Explicación

    • new FormData(form) recoge todos los campos automáticamente.
    • No necesitas construir objeto manual.
    • Perfecto para enviar archivos.
    • No necesitas definir Content-Type.

    Muy recomendable para formularios grandes.


    7️⃣ Envío tipo AJAX clásico (XMLHttpRequest)

    Más antiguo, pero didáctico.

    const xhr = new XMLHttpRequest();
    xhr.open("POST", "procesar.php");
    xhr.setRequestHeader("Content-Type", "application/json");
    xhr.onload = function(){
        console.log(xhr.responseText);
    };
    xhr.send(JSON.stringify({
        nombre: form.nombre.value
    }));

    Explicación

    • Era la forma anterior a fetch.
    • Más verboso.
    • Útil para entender evolución histórica.

    8️⃣ Envío con confirmación previa

    A veces queremos preguntar antes de enviar.

    form.addEventListener("submit", function(e){
        e.preventDefault();   
    
    if(!validarFormulario()) return;  
    
    if(confirm("¿Seguro que quieres enviar los datos?")){
            form.submit();
        }
    });

    Explicación

    • confirm() devuelve true o false.
    • Solo enviamos si el usuario confirma.
    • Útil para acciones importantes.

    9️⃣ Mostrar resumen antes de enviar

    form.addEventListener("submit", function(e){
        e.preventDefault();   
    
     if(!validarFormulario()) return;  
    
    const resumen = `
    Nombre: ${form.nombre.value}
    Email: ${form.email.value}
    Edad: ${form.edad.value}
    `; 
    if(confirm(resumen + "\n\n¿Confirmar envío?")){
            form.submit();
        }
    });

    Explicación

    • Construimos texto resumen.
    • Mostramos al usuario los datos antes de enviarlos.
    • Evita errores humanos.

    🔟 Envío parcial (solo algunos campos)

    const datos = {
    nombre: form.nombre.value,
    email: form.email.value
    };

    Explicación

    No siempre se envían todos los campos.
    Podemos decidir qué mandar y qué no.


    Comparación rápida

    MétodoRecarga páginaModernoRecomendado
    HTML puroBásico✔ para cosas simples
    submit() manualIntermedio
    fetch + JSONNoMuy moderno⭐⭐⭐
    FormDataNoMuy práctico⭐⭐⭐
    XMLHttpRequestNoAntiguoSolo didáctico