Validación de formularios frente a estándares con la API de validación

En un momento, a casi todos les gustaba Angular 2+, es un marco bien diseñado que está muy por encima de otros marcos frontales populares en términos de rendimiento de ingeniería. Pero también tenía defectos muy extraños. Uno de ellos es la imposibilidad de llamar manualmente a la validación o revalidación del formulario, que se observó al menos hasta la 8ª versión. Esto no quiere decir que les guste mucho la reactividad, pero en este subsistema, parece que algunas consideraciones reactivas llevaron a los desarrolladores a implementar la validación solo a través del enlace, lo que obligó a los desarrolladores de aplicaciones a recurrir a muletas como establecer el estado "intacto" para los campos y, en general, complicar la escritura de validadores complejos con lógica y la participación de varios campos a la vez.Mi experiencia con el validador angular y algunas otras características del marco reforzó mi impresión de lo elegante y simple que fue después de eso usar la API HTML5 para la validación de formularios, que "simplemente funciona" en cualquier navegador moderno, incluso sin marcos y bibliotecas.



Los atributos de los elementos son la base de los validadores. Usando atributos, podemos establecer inmediatamente las siguientes restricciones:

obligatorio : el campo es obligatorio, es decir, requiere rellenar

min max paso - los valores máximos y mínimos autorizados y, así como el paso de cambiar

minLength y maxlength - limitadores del número de caracteres de entrada permitido

patrón - expresión regular

Parece ser que no mucho, sin embargo, el patrón nos da oportunidades bastante ricos para la comprobación de valores, patrones regulares se googled facilidad lo que permite verificar inmediatamente los números de teléfono, las direcciones de correo electrónico y las URL y mucho más en la demanda.

Organizados en elementos de formulario, estos atributos no permitirán que el botón se active automáticamente desde el mismo formulario realizando los valores de envío al servidor, aunque hoy en día tal caso puede parecer anacrónico para muchos. Pero esto no es un problema, porque con JavaScript del lado del cliente, podemos usar todos estos validadores de la misma manera o incluso mejor. Por lo tanto, no usaremos input type = email, pero trataremos de crear nuestro propio campo verificando que la entrada cumpla con las reglas para generar direcciones de correo electrónico. Hagamos una forma simple:

<form name="myform" id="myform">
   <input type="text" pattern="^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" placeholder="email here"/>
   <input type="submit">
</form>


El validador funciona de inmediato y al intentar presionar el botón, emite una advertencia en el idioma de la configuración regional del navegador.







En consecuencia, ingresar mail@example.com da como resultado un envío exitoso del formulario.

Para desarrollar su comportamiento, debe acceder a la instancia del formulario, esto se puede hacer a través del documento global por nombre, índice (id) u ordinal comenzando desde cero.

<script type="module">
   document.forms.myform.onsubmit = (event) => {
       console.log('validate');
       return false;
   };
</script>


o por el selector usando uno de los métodos, como document.getElementById () o document.querySelector (),

para verificar los resultados, ejecute http-server

npx http-server


después de que se ejecuta el comando, puede abrir 127.0.0.1 : 8080 / o la dirección que le escribe en la consola en el navegador y depurar los resultados.



Reemplacemos el envío con un botón normal e invoquemos la validación del formulario manualmente, cambiando ligeramente el ejemplo.

<form id="myform" action="#">
   <input type="text" pattern="^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" required placeholder="email here" />
   <input type="button" name="subm" value="OK" />
</form>

<script type="module">;
   myform.subm.onclick = (event) => {
       console.log(form.checkValidity());
       return false;
   };
</script>


En este ejemplo, puede ver que la asignación de objetos de formulario por su identificación y nombre funciona para elementos secundarios en relación con el formulario, que se ve muy elegante. Ahora nuestro código imprime el estado de validez del formulario en la consola.

La presencia de métodos para iniciar manualmente la validación no significa que no se pueda realizar sin llamarlos.

Los resultados de la entrada y otros cambios en el formulario se reflejan inmediatamente en su estado, que se manifiesta en presencia de pseudoclases de estilos válidos e inválidos . Si agrega resaltado de color, puede ver cómo funciona la validación de inmediato.

<style>
  :valid {
       border: 1px solid green;
   }
  :invalid {
       border: 1px solid red;
   }
</style>








Para evitar que el formulario moleste a los ojos con rojo antes de que el usuario intente ingresar algo en él, puede usar un truco de vida con un marcador de posición:

<style>
   input:valid {
       border: 1px solid green;
   }
   input:not(:placeholder-shown):invalid {
       border: 1px solid red;
   }
</style>


Los controladores externos para eventos de validación se pueden colgar en elementos de formulario.

<script type="module">
   myform.email.oninvalid = (event) => {
       alert('Wrong email !!11');
   };
   myform.subm.onclick = (event) => {
       console.log(form.checkValidity());
       return false;
   };
</script>


En este caso, el mecanismo de gancho es usado por el nombre del evento, si hay algún evento soportado por el elemento, entonces al asignarle una función nombrada en + <event_name>, podemos estar seguros de que será llamado cuando se dispare.



Y un punto maravilloso más aquí es que ya no se les llamará al ingresar datos, sino solo cuando se haga una validación mediante programación, es decir, llamando al método checkValidity ().



En consecuencia, podemos manejar este comportamiento:

myform.subm.onclick = (event) => {
   if (myform.checkValidity()) {
       alert('Valid !');
   } else {
       alert('Invalid !')
   }
   return false;
};


En la vida real, es posible que también necesitemos llamar a event.preventDefault () si la validación no logra abortar el procedimiento de envío del formulario.



En checkValidity () es un reportValidity () analógico , que devuelve el resultado sin causar revalidación.



¿Cómo saber qué campo es incorrecto?



Cada elemento de entrada de formulario tiene la propiedad .validity, así como la capacidad de llamar a métodos de validación en él, la propiedad tiene la siguiente estructura:



ValueState: {

válido - signo general de la corrección del

valor Falta - el valor es obligatorio, pero no establecido

typeMismatch -

se ha introducido el tipo de valor incorrecto patternMismatch - introducido valor no coincidente

tooLong - el valor es mayor que maxlength

tooShort - el valor es menor que minlength

rangeUnderflow - el valor es menor que el min

rangeOverflow - el valor es mayor que

el paso

máximoMismatch - el valor no coincide con el paso badInput - la entrada no se puede convertir al valor

customError - error arbitrario

}



Básicamente, como podemos ver, propiedades de error correspondientes a los atributos de validación estándar, mientras que .customError es nuestro margen para la extensión. Al

llamar al método .setCustomValidity () con una cadena de error como argumento, podemos marcar el elemento del formulario como no válido. También puede establecer u obtener el texto de error a través de la propiedad .validationMessage...

Para no establecer validaciones del navegador, puede utilizar la propiedad .willValidate , que indica si se llamarán validaciones estándar en el campo.

Al pasar una cadena vacía como argumento a .setCustomValidity () podemos devolver su estado a válido.

Agreguemos soporte para nuestro propio atributo my-pattern , que, para mayor claridad, comparará el valor con una expresión regular de la misma manera.

En caso de error, junto al campo se mostrará el mensaje, además del proporcionado en el navegador, la

validación se disparará al cambiar el valor de nuestro campo alternativo y al hacer clic en el botón.

<form id="myform" action="#">
   <div>
       <input type="text" name="email" id="email" value="" pattern="^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" required placeholder="email here" />
       <span class="msg"></span>
   </div>
   <div>
       <input type="text" name="customInput" id="customInput" my-pattern="^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$" required placeholder="text here" />
       <span class="msg"></span>
   </div>
   <button type="submit" name="subm" value="OK">OK</button>
</form>
<style>
   input:valid {
       border: 1px solid green;
   }
   input:not(:placeholder-shown):invalid {
       border: 1px solid red;
   }
</style>
<script type="module">
   myform.customInput.oninvalid = (event) => {
       let el = event.target;
       let msg = el.parentElement.querySelector('.msg');
       msg.innerText = el.validationMessage;
       console.log('oninvalid, id: ', el.id);
   };
   myform.customInput.oninput = (event) => {
       let el = event.currentTarget;
       validateWithMyPattern(el);
       markValidity(el);
   };
   function markValidity(el) {
       el.checkValidity();
       let msg = el.parentElement.querySelector('.msg');
       if (el.validity.valid) {
           msg.innerText = '';
       } else {
           msg.innerText = el.validationMessage;
       }
   }
   function validateWithMyPattern(field) {
       if (field.value) {
           if (field.hasAttribute('my-pattern') &&
               field.value.match(field.getAttribute('my-pattern'))) {
               field.setCustomValidity('');
           } else {
               field.setCustomValidity('My pattern error');
           }
       }
   }
   myform.subm.onclick = (event) => {
       for (let formEl of myform.querySelectorAll('input')) {
           validateWithMyPattern(formEl);
           markValidity(formEl);
       }
       if (myform.reportValidity()) {
           alert('Valid !');
       } else {
           alert('Invalid !')
       }
       return false;
   };
</script>


Ahora tenemos dos campos similares que verifican el valor con un validador estándar y uno que hemos escrito nosotros mismos.







Las posibilidades pueden no parecer ricas, sin embargo, con la ayuda de ellas puede implementar cualquier validación, incl. grupos de campo sin demasiada limitación técnica como con los marcos populares.



De las limitaciones de la API de validación, solo recuerdo la invalidación inicial de campos. Para ello, además del truco con marcador de posición o estados especiales a-la sin tocar, puedes realizar toda la validación programáticamente en la entrada y enviar eventos combinando tus propios validadores con los estándar.

Resolviendo mis problemas, llegué a la necesidad de crear mi propio componente que realiza las tareas del formulario al mismo tiempo para admitir mis propios elementos de entrada, lo que le permite establecer diferentes comportamientos de validación y notificación y colgar cualquier validador y utiliza la API de validación estandarizada. Puede verlo aquí: https://bitbucket.org/techminded/skinny-widgets/src/master/src/form/

y el código de ejemplo de este artículo se puede encontrar aquí:

https://bitbucket.org/techminded/myform /



All Articles