Validation des formulaires par rapport aux normes avec l'API de validation

À un moment donné, presque tout le monde aimait Angular 2+, c'est un cadre bien conçu qui est un cran au-dessus du reste des cadres frontaux populaires en termes de performances d'ingénierie. Mais il avait aussi des défauts très étranges. L'un d'eux est l'impossibilité d'appeler manuellement la validation ou la revalidation du formulaire, qui a été observée au moins jusqu'à la 8e version. Cela ne veut pas dire qu'ils sont très friands de réactivité, mais dans ce sous-système, il semble que certaines considérations réactives aient incité les développeurs à implémenter la validation uniquement via la liaison, obligeant les développeurs d'applications à se tourner vers des béquilles comme la définition de l'état "intact" pour les champs et compliquant généralement l'écriture de validateurs complexes avec des logique et participation de plusieurs domaines à la fois.L'expérience de l'utilisation du validateur angulaire et de certaines autres fonctionnalités du framework a renforcé mon impression de l'élégance et de la simplicité de l'utilisation de l'API HTML5 pour la validation de formulaire, qui «fonctionne juste» dans n'importe quel navigateur moderne, même sans l'utilisation de frameworks et de bibliothèques.



Les attributs d'élément sont la base des validateurs. À l'aide d'attributs, nous pouvons immédiatement définir les restrictions suivantes:

obligatoire - le champ est obligatoire, c'est-à-dire nécessite de remplir l' étape

min max - les valeurs minimales et maximales autorisées, ainsi que l'étape de modification de minlength et maxlength - limiteurs du nombre de caractères d'entrée autorisés modèle - expression régulière Cela ne semble pas beaucoup, cependant, le modèle nous donne des opportunités assez riches pour vérifier les valeurs, les modèles réguliers sont facilement recherchés permettant de vérifier immédiatement les numéros de téléphone, les adresses e-mail et les URL et bien plus encore en demande.







Disposés sur des éléments de formulaire, ces attributs ne permettront pas automatiquement au bouton d'être déclenché à partir du même formulaire effectuant l'envoi de valeurs au serveur, bien qu'aujourd'hui un tel cas puisse sembler anachronique à beaucoup. Mais ce n'est pas un problème, car avec JavaScript côté client, nous pouvons utiliser tous ces validateurs de la même manière, voire mieux. Par conséquent, nous n'utiliserons pas input type = email, mais essayerons de créer notre propre champ en vérifiant que l'entrée est conforme aux règles de génération d'adresses e-mail. Faisons un formulaire 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>


Le validateur fonctionne immédiatement et lors d'une tentative d'appuyer sur le bouton, il émet un avertissement dans la langue des paramètres régionaux du navigateur.







En conséquence, la saisie de mail@example.com aboutit à une soumission de formulaire réussie.

Pour développer votre comportement, vous devez accéder à l'instance du formulaire, cela peut être fait via le document global par nom, index (id) ou ordinal à partir de zéro.

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


ou par un sélecteur utilisant l'une des méthodes, telles que document.getElementById () ou document.querySelector (),

pour vérifier les résultats, exécutez http-server

npx http-server


une fois la commande exécutée, vous pouvez ouvrir 127.0.0.1 : 8080 / ou l'adresse qu'elle vous écrit dans la console du navigateur et déboguer les résultats.



Remplaçons la soumission par un bouton normal et invoquons la validation du formulaire manuellement, en modifiant légèrement l'exemple.

<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>


Dans cet exemple, vous pouvez voir que le mappage des objets de formulaire par leur identifiant et leur nom fonctionne pour les éléments enfants par rapport au formulaire, qui semble très élégant. Maintenant, notre code imprime l'état de validité du formulaire sur la console.

La présence de méthodes pour démarrer manuellement la validation ne signifie pas qu'elle ne peut pas être effectuée sans les appeler.

Les résultats de l'entrée et d'autres modifications apportées au formulaire sont immédiatement reflétés dans son état, qui se manifeste en présence de pseudo-classes des styles valides et non valides . Si vous ajoutez une mise en évidence des couleurs, vous pouvez voir comment la validation fonctionne immédiatement.

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








Afin d'éviter que le formulaire ne gêne les yeux avec du rouge avant que l'utilisateur n'essaye d'y entrer quelque chose, vous pouvez utiliser un hack de vie avec un espace réservé:

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


Les gestionnaires externes pour les événements de validation peuvent être accrochés aux éléments de formulaire.

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


Dans ce cas, le mécanisme de hook est utilisé par le nom de l'événement, s'il y a un événement supporté par l'élément, puis en lui assignant une fonction nommée sur + <event_name>, nous pouvons être sûrs qu'il sera appelé lorsqu'il se déclenchera.



Et un autre point merveilleux ici est qu'ils ne seront plus appelés lorsque des données sont saisies, mais uniquement lors de la validation par saccade par programme, c'est-à-dire appelant la méthode checkValidity ().



En conséquence, nous pouvons gérer ce comportement:

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


Dans la vraie vie, nous pouvons également avoir besoin d'appeler event.preventDefault () si la validation échoue à abandonner la procédure de soumission de formulaire.



À checkValidity () se trouve un rapport analogique reportValidity () , qui renvoie le résultat sans provoquer de revalidation.



Comment savez-vous quel champ est erroné?



Chaque élément d'entrée de formulaire a la propriété .validity, ainsi que la possibilité d'appeler des méthodes de validation dessus, la propriété a la structure suivante:



ValueState: {

valid - signe général de l'exactitude de la

valeurMissing - la valeur est requise, mais pas définie

typeMismatch - le mauvais type de valeur

a été entré patternMismatch - introduit valeur non concordante

tooLong - valeur supérieure à maxlength

tooShort - valeur inférieure à minlength

rangeUnderflow - valeur inférieure à min

rangeOverflow - valeur supérieure à max

stepMismatch - la valeur ne correspond pas à l'étape

badInput - l'entrée ne peut pas être

forcée à la valeur customError - erreur arbitraire

}



Fondamentalement, comme nous pouvons le voir, propriétés d'erreur correspondant aux attributs de validation standard, tandis que .customError est notre marge pour l'extension. En

appelant la méthode .setCustomValidity () avec une chaîne d'erreur comme argument, nous pouvons marquer l'élément de formulaire comme invalide. Vous pouvez également définir ou obtenir le texte d'erreur via la propriété .validationMessage...

Afin de ne pas définir de validations de navigateur, vous pouvez utiliser la propriété .willValidate , qui indique si les validations standard seront appelées sur le champ.

En passant une chaîne vide comme argument à .setCustomValidity (), nous pouvons rendre son état valide.

Ajoutons la prise en charge de notre propre attribut my-pattern , qui vérifiera la valeur par rapport à une expression régulière de la même manière pour plus de clarté.

En cas d'erreur, le message, en plus de celui fourni dans le navigateur, s'affichera à côté du champ. La

validation sera déclenchée lorsque la valeur de notre champ alternatif change et lorsque le bouton sera enfoncé.

<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>


Maintenant, nous avons deux champs similaires qui vérifient la valeur avec un validateur standard et un que nous avons écrit nous-mêmes.







Les possibilités peuvent ne pas sembler riches, cependant, avec leur aide, vous pouvez implémenter toutes les validations, incl. groupes de domaines sans trébucher sur les limitations techniques comme avec les frameworks populaires.



Parmi les limitations de l'API de validation, je ne me souviens que de l'invalidation initiale des champs. Pour cela, en plus de l'astuce avec un espace réservé ou des états spéciaux à la fois intacts, vous pouvez effectuer toute la validation par programme sur l'entrée et soumettre des événements en combinant vos propres validateurs avec ceux standard.

En résolvant mes tâches, j'en suis venu à la nécessité de créer mon propre composant qui effectue les tâches du formulaire en même temps pour prendre en charge mes propres éléments d'entrée, vous permettant de définir différents comportements de validation et de notification et de raccrocher tous les validateurs et d'utiliser l'API de validation standardisée. Vous pouvez le voir ici: https://bitbucket.org/techminded/skinny-widgets/src/master/src/form/

et l'exemple de code de cet article peut être trouvé ici:

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



All Articles