el DOM

DOM Saga: Guía básica sobre el Document Object Model | Parte #3

Última actualización:

¡Por fin llegamos a la última parte de esta DOM saga! 🚀  Si acabas de aterrizar aquí, puedes ver las partes #1 y #2 antes.

Eventos del DOM relacionados con formularios

Hasta ahora hemos visto cómo manipular el DOM usando eventos. Lo siguiente es aprender cómo interactuar con los formularios web. Los formularios sirven para recabar información que el usuario inserte. Por ejemplo, su email y su contraseña. 

Para capturar esa información debemos hacerlo a través del DOM. Concretamente, trabajando con el submit event. Este evento es un 2x1, porque produce un click event + emite información sobre el formulario (form) al que esté vinculado. 

Aquí tienes la lista completa de los JavaScript events de MDN

Primeros pasos con un evento de tipo submit

Vamos a trabajar con 3 archivos para explicar esta parte #3: un archivo HTML, un archivo JavaScript (JS) y un archivo CSS. Los llamaremos index.html, forms.js styles.css respectivamente. 

Aquí el contenido inicial del index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="styles.css">
    <title>JavaScript DOM</title>
</head>
<body>
    
    <form class="signup-form">
        <input type="text" id="username" placeholder="Username">
        <input type="submit" value="enviar">
    </form>
    
    <script src="forms.js"></script>
</body>
</html>

Si guardas y accedes a tu navegador, ya podrás ver un sencillo formulario un poco feo 🙄. Le añadimos el siguiente estilo en el archivo styles.css: 

form {
    border: 2px solid sandybrown;
    display: flex;
    flex-direction: column;
    align-items: center;
    border-radius: 8px;
    padding: 10px;
    margin: 20px auto;
    max-width: 200px;
}

input {
    margin: 10px;
}

Con esto ya tenemos un formulario algo más decente. Ahora vamos a añadirle funcionalidad con JS.

formulario simple

El hecho de que nuestro input sea de tipo submit ya le indica a JS que debe disparar un evento submit cuando se haga click en el botón "enviar". Pero dicho evento no debemos vincularlo al botón en sí, sino al formulario (form). 

Porque lo que queremos recibir es la información recogida en el form, no en el botón. El trabajo del botón "enviar" se limita a enviar (submit) la información. ✉️

​​De esta manera, capturamos la información del formulario tanto si el usuario hace click en el botón "enviar" como si escribe algo en la casilla del username y le da a enter en el teclado. Aquí un esquemita para ubicarnos. A continuación vamos a desarrollarlo.

esquema evento submit

1. Cogemos una referencia del form y del input del username, ​​​​usando nuestro ya conocido querySelector.

2. Le añadimos un event listener al form con el evento submit. Vamos a necesitar el event object para que nos de información sobre el submit event. ​​

3. Prevenimos que la página se recargue usando el método preventDefault().

4. Obtenemos el valor (value) del username. Esto es sencillamente el texto que el usuario introduzca en el campo a rellenar. Hacemos en console.log para ver el valor en la consola.

Aquí el bloque de código que hemos añadido:​​ 

const form = document.querySelector('.signup-form');
const username = document.querySelector('#username');

form.addEventListener('submit', e => {
    e.preventDefault();
    console.log(username.value);
});

Verás que, si introduces algo en el campo y le das a "enviar" o a enter, en la consola te aparecerá el texto que has escrito. ¡Chachi! 😄  Esto significa que ya sabemos capturar la información que introduzca el usuario.

5. Esta no es la única manera de capturar la información del usuario. También podríamos no usar la variable username y acceder a los inputs de dentro del formulario directamente a través del formulario. Esto funciona porque JS reconoce que hemos creado un formulario (<form>) y asocia los <input> con el formulario. 

Eso nos permite acceder a los atributos de los inputs usando dot notation desde el formulario. Eso sí, los atributos aceptados son solamente el id o el name. Teniendo esto, también debemos especificar que queremos el value de ese input. ​​​​

Aquí el bloque de código que hemos editado:

const form = document.querySelector('.signup-form');
// const username = document.querySelector('#username');

form.addEventListener('submit', e => {
    e.preventDefault();
    // console.log(username.value);
    console.log(form.username.value);
});

Recuerda que también funcionaría si en nuestro index.html tuviésemos esta línea:

        <input type="text" name="username" placeholder="Username">

en lugar de esta:​​

        <input type="text" id="username" placeholder="Username">

Introducción a las Regular Expresions

Ya sabemos cómo capturar la información que escribe el usuario. Ahora vamos a aprender a definir el valor que queremos recibir del usuario. Es decir, si queremos que el usuario cree un nombre de usuario, podemos darle unos rangos válidos para hacerlo, a saber, nombre de más cuatro letras, que contenga al menos dos números, etc.

🔧 Todo esto lo podemos definir y validar usando una herramienta llamada Regular Expressions (o RegEx). Las RegEx no son exclusivas de JS, sino que se usan en muchos lenguajes de programación.

Confieso que la primera vez que se cruzaron en mi camino las RegEx no entendía absolutamente nada. Aquello me parecía una especie de lenguaje encriptado para abrir criptas secretas. 😩 Pero la verdad es que, a menos que quieras convertirte en un especialista en RegEx, existen multitud de recursos gratuitos para ayudarte a definir tus patrones. El que más uso es regex101.

Tiene una interface muy intuitiva. Por ejemplo, abajo a la derecha, en la sección quick reference tienes una lista con los patrones más comunes. 🧐

Pero vayamos por partes . ¿Qué son exactamente las RegEx? Son ​​​​combinaciones de letras y símbolos que nos permiten definir un patrón. Por ejemplo, queremos que el usuario sólo escriba cuatro letras y dos números. Ese patrón se contrasta posteriormente con lo que el usuario ha escrito, y si coincide, decimos que ha producido un match con la Regular Expression. ​​👍

Es como establecer una criba. Si lo que escribe el usuario pasa las condiciones que hemos establecido, ese input será válido.​​

Por tanto, los pasos a seguir serían:

Definir el patrón que queremos crear. Ejemplo: cuatro letras entre la ​a ​y la ​z ​y dos números entre el ​0 ​y el ​9.

Crear el patrón usando una ​Regular Expression.​​​​​​

Contrastar el patrón con el input que corresponda para ver si coinciden.

Practiquemos un poco con la web regex101. Fíjate que cualquier RegEx empieza y termina con una barra. Esta sería su sintaxis:

/RegEx aquí/flags (opcionales)

1. Selecciona el lenguaje que quieras usar (ECMAScript JavaScript). 

2. Una RegEx puede ser también cualquier palabra, por ejemplo "pepe". Si ahora introduces "pepe" como tu patrón a comparar con el texto, y escribes "pepe" en el texto, verás que coinciden. 

regular expressions ejemplo

Sigue funcionando si escribes cualquier caracter delante o detrás de la palabra "pepe". Si queremos que pase nuestra criba usando sólo la palabra "pepe", sin nada delante ni detrás, usamos los caracteres ^ y $, así:

/^pepe$/

💡 Verás que tienes una explicación a la derecha de su web. 

3. Muy bien hasta aquí, pero lo habitual es que queramos contrastar un patrón más complejo, por ejemplo, "cualquier letra de la a la z, tanto mayúsculas como minúsculas​​". Es decir, trabajamos con rangos. Así lo haríamos:

/^[a-zA-Z]$/

Pero esto únicamente pasaría nuestra criba si sólo escribimos una letra. Para indicar cuántos caracteres queremos recibir, podemos establecer un mínimo o establecer un rango. Por ejemplo, queremos una palabra entre 6 y 8 caracteres. Así lo haríamos:

/^[a-zA-Z]{6,8}$/

Con este patrón, "pepe" ya no pasaría nuestra criba, pero "pepito" sí, porque tiene entre 6 y 8 caracteres. 

4. También podemos construir un patrón que admita, a parte de letras, números del 0 al 9, por ejemplo. Así lo haríamos:

/^[a-zA-Z0-9]{6,8}$/

5. Si quisiéramos crear un patrón que admitiese cualquier caracter imaginable, podríamos usar simplemente un punto. Así lo haríamos:

/^.{6,8}$/

Vistos los conceptos básicos de las Regular Expressions, vamos a crear un patrón dentro de nuestra mini demo-app para comprobar que el usuario inserte lo que nosotros definamos. El patrón lo vamos a contrastar con unusername que vamos a escribir (hardcoded), que debe contener sólo letras minúsculas, un mínimo de seis y un ningún máximo. ¡Vamos allá! 🤗

6. En el archivo forms.js creamos una variable con un username, el que quieras, en mi caso, "pepe". 

7. Creamos nuestro patrón usando una Regular Expression y lo guardamos en una variable. Puede parecer extraño (o incluso incompleto), pero para definir que queremos recibir un mínimo de letras, sin límite, debemos poner el número mínimo seguido por una coma, y luego cerrar llaves. 🤨

Por estas cosas te decía que la primera vez que vi las RegEx me parecieron jeroglíficos... 😋

8. Existen varias maneras de contrastar nuestro patrón con algún elemento. Aquí vamos a ver dos. La primera sería usando un método de las Regular Expressions: test(). Así que debemos aplicarlo sobre la variable que contenga nuestra RegEx. Este método devuelve un boolean. True si el elemento cumple con nuestro patrón, y false si no lo hace. 

Para poder ver el resultado, creamos una variable que guarde dicho resultado y la imprimimos por consola. ​​​​  

Aquí el bloque de código que hemos añadido:

const username = 'pepe';
const pattern = /[a-z]{6,}/;

const result = pattern.test(username);
console.log(result);

Si compruebas tu consola, verás que nos devuelve false, porque "pepe" tiene cuatro letras, y hemos indiciado que como mínimo debe tener seis. Prueba ahora a escribir un username de seis letras y verás como la consola te devuelve true. 

Sin embargo, nuestro patrón tiene un nivel de comprobación un tanto débil, porque si ahora añadimos cualquier caracter delante y/o detrás de nuestro username, siempre y cuando existe en algún lugar de nuestro username 6 letras minúsculas consecutivas, JS considerará que el patrón se cumple

9. Para arreglar esto, debemos indicar que esas seis letras minúsculas consecutivas deben estar tanto al principio del username como al final, siendo los únicos elementos que constituyan nuestro usernameEsto se consigue añadiendo ^ al principio y $ al final, como hemos visto antes. 

10. Con este cambio, ahora podemos hacer una comprobación usando un if else statement, para que nos imprima por consola algo más intuitivo que true false. 

Aquí el bloque de código que hemos editado/añadido:

const username = 'pepito';
const pattern = /^[a-z]{6,}$/;

const result = pattern.test(username);
// console.log(result);

if(result) {
    console.log('great! the pattern matches :)');
} else {
    console.log('oops! the pattern does not match :(');
}

Vamos a ver la segunda manera de contrastar nuestro patrón con un elemento.

11. Esto se hace usando el método search sobre nuestro username, no sobre nuestro pattern, como hacíamos antes. Así que esta forma sería lo opuesto a usar el método test(). 😌

Lo que hace este método es devolver un número integral. Devolverá -1 si el patrón no se cumple, y un número positivo si el patrón se cumple. El número positivo equivaldrá a la posición donde empieza a cumplirse el patrón, que en nuestro caso sería la posición cero.

12. Puedes comentar el bloque de código anterior para que no nos moleste.

Aquí el bloque de código que hemos añadido/editado:

// const result = pattern.test(username);
// // console.log(result);

// if(result) {
//     console.log('great! the pattern matches :)');
// } else {
//     console.log('oops! the pattern does not match :(');
// }

let result = username.search(pattern);
console.log(result);

Sin embargo, si volviésemos a definir un patrón más débil (quitando los símbolos ^ y $), podríamos probar a insertar caracteres (distintos a letras minúsculas) delante de nuestro username, y entonces, la posición que nos daría el método search sería distinta

Aquí tienes un ejemplo:​​​​

const username = '55pepito';
const pattern = /[a-z]{6,}/;

let result = username.search(pattern);
console.log(result);  // 2

Validando la información enviada por el usuario usando Regular Expresions

Sabiendo esto, vamos a validar la información que el usuario introduzca en el campo Username e informarle sobre si lo que ha enviado es válido o no según el patrón que definamos.

1. Comentamos el bloque de código anterior para que no nos moleste.

2. Accedemos al value del <input id="username"> a través del form, como hemos aprendido antes. Lo guardamos en una variable.

 3. Definimos un patrón para que el usuario sólo pueda introducir un username con letras mayúsculas o minúsculas, sin números, entre seis y ocho caracteres. Lo guardamos en una variable.

4. Preparamos el código para informar al usuario sobre si su username es válido o no, usando un if statement y el método test. 

Aquí el bloque de código que hemos editado/añadido:

form.addEventListener('submit', e => {
    e.preventDefault();
    // console.log(username.value);
    // console.log(form.username.value);

    // validation
    const username = form.username.value;
    const usernamePattern = /^[a-zA-Z]{6,8}$/;

    if(usernamePattern.test(username)) {
        // positive feedback
        
    } else {
        // negative feedback

    }

});

5. Para darle feedback al usuario, nos creamos un <div> en el index.html justo debajo del botón "enviar". Así:

        <input type="submit" value="enviar">
        <div class="feedback"></div>

​​​​​6. Volvemos al forms.js y creamos una referencia para capturar el <div> que acabamos de crear.

7. Cogemos dicha referencia y la usamos para mostrar un texto en nuestra página según si el patrón se cumpla o no. 

Aquí el bloque de código que hemos editado:

const feedback = document.querySelector(".feedback");

form.addEventListener("submit", e => {
  e.preventDefault();
  // console.log(username.value);
  // console.log(form.username.value);

  // validation
  const username = form.username.value;
  const usernamePattern = /^[a-zA-Z]{6,8}$/;

  if (usernamePattern.test(username)) {
    // positive feedback
    feedback.textContent = "Nombre de usuario válido :)";
  } else {
    // negative feedback
    feedback.textContent =
      "Nombre incorrecto. El nombre debe contener mayúsculas o mínisculas y debe ser entre 6 y 8 letras y no contener caracteres especiales";
  }
});

¡Y ya está! 😊 Pruébalo en tu navegador escribiendo diferentes combinaciones.

validación regular expresions

Eventos de teclado ⌨️

Los eventos de teclado (o keyboard events) son los eventos que gestionan lo que ocurre cuando pulsamos alguna tecla de nuestro teclado.​​

Son muy útiles para capturar información del usuario en directo, conforme va a escribiendo, sin tener que esperar a que pulse en "enviar". Esto nos da la posibilidad de informarlo en directo sobre si está cometiendo algún error o si la información escrita cumple con los requisitos que hayamos establecido. 

Vamos a seguir con nuestra mini demo-app para configurar una validación en directo de lo que el usuario escriba. Mantendremos nuestro patrón de la sección anterior y configuraremos un keyboard event para generar un borde rojo mientras el patrón no se cumpla y un borde verde cuando sí lo haga. ¡Vamos allá! 👩‍💻

El keyup event es un evento que gestiona lo que ocurre cuando dejamos de pulsar una tecla. Es decir, cuando pulsamos un tecla y levantamos el dedo. Ahí es cuando se dispara el keyboard event. 

1. Vinculamos un nuevo event listener al input field del username. Para acceder a ese input, lo hacemos a través de la variable form. ​Le pasamos a nuestro event listener el evento keyup y el event object. Recuerda que el event object nos da información concreta sobre el evento pasado como primer parámetro (el keyup). 

Si quieres saber qué información es esa, no tienes más que hacer un console.log del event object. 🤓

Hacemos un console.log del e.target.value para ver por consola cómo se imprime cada letra simultáneamente. También podríamos acceder al valor usando form.username.value, pero vamos a ceñirnos a utilizar la propiedad target porque es más general.

Aquí el bloque de código que hemos añadido:​​

// live feedback
form.username.addEventListener('keyup', e => {
    console.log(e.target.value);
});

Si guardas y vas a la consola de tu navegador, verás como se imprime ahí todo lo que vas escribiendo. Chulo, ¿verdad? 🤗

2. Con esto, ya podemos comprobar si el usuario ha introducido un valor válido (según nuestro patrón). Pero dado que necesitamos nuestro patrón y ahora éste está dentro de una función, lo sacamos de ahí y lo colocamos en el global scope para poder tener acceso a él.​​

Hacemos un console.log para ver por consola si nuestra función está bien construida.

Aquí el bloque de código que hemos editado/añadido:​​

const usernamePattern = /^[a-zA-Z]{6,8}$/;

form.addEventListener("submit", e => {
  e.preventDefault();
  // console.log(username.value);
  // console.log(form.username.value);

  // validation
  const username = form.username.value;

  if (usernamePattern.test(username)) {
    // positive feedback
    feedback.textContent = "Nombre de usuario válido :)";
  } else {
    // negative feedback
    feedback.textContent =
      "Nombre incorrecto. El nombre debe contener mayúsculas o mínisculas y debe ser entre 6 y 8 letras y no contener caracteres especiales";
  }
});

// live feedback
form.username.addEventListener('keyup', e => {
    // console.log(e.target.value);
    if(usernamePattern.test(e.target.value)) {
        console.log('test pasado! :)');
    } else {
        console.log('test fallido :(');
    }
});

¡Funciona! Eso sí, recuerda que no estamos aceptando ningún caracter especial, y la Ñ entraría dentro de esta categoría. 🙄

3. Creamos unas clases CSS para definir un borde verde y otro rojo, según lo que introduzca el usuario sea válido o no, respectivamente. Este es el bloque de código que hemos añadido en nuestro styles.css:

.success {
    border: 2px solid lime;
}

.error {
    border: 2px solid red;
}

4. Volvemos al archivo forms.js y aplicamos dichas clases en lugar de nuestros console.logs. Utilizamos el método setAttribute porque queremos sobrescribir las clases, no complementarlas. Cuando se aplique una, no se debe aplicar la otra, y a la inversa.​​​​​​

Aquí el bloque de código que hemos editado:

// live feedback
form.username.addEventListener('keyup', e => {
    // console.log(e.target.value);
    if(usernamePattern.test(e.target.value)) {
        // console.log('test pasado! :)');
        form.username.setAttribute('class', 'success');
    } else {
        // console.log('test fallido :(');
        form.username.setAttribute('class', 'error');
    }
});

Y ¡tachááán!  🥳  Si ahora empiezas a teclear cualquier palabra, verás que el borde es rojo hasta que cumplas con los requisitos del patrón que hemos establecido, momento en el cual se volverá verde. 💚

THE END!

¡Y hasta aquí hemos llegado! Espero que hayas aprendido algo nuevo 😊.  Si te queda alguna duda, ¡nos vemos en los comentarios!

Y si crees que este post puede serle útil a alguien, ¡compártelo!

Otros artículos que pueden interesarte

Días del 353 al 386
Objetivos versus realidad Y nuevamente, llegó otro día clave. Llegó…y pasó. El pasado 4 de marzo este Reto Computer Geek[...]
Dates en JavaScript: Guía completa
IntroducciónLos dates son un tipo de objetos de JavaScript (JS), muy útiles para trabajar con fechas, como podría ser la fecha de[...]
Días del 2 al 4
"Si buscas resultados distintos no hagas siempre lo mismo" - Albert Einstein Estos días estoy aprendiendo a hacer loops en[...]

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Como toda web legal que se precie, utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si continúas utilizando este sitio asumiremos que estás de acuerdo. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar