Validació de formularis del costat del client

Abans d’enviar dades al servidor és important assegurar-se que s’emplenen tots els controls de formulari necessaris en el format correcte. Es denomina validació de formularis del costat del client, i ajuda que les dades enviades coincideixin amb els requisits establerts en els diversos controls de formulari. Aquest article et permet conèixer els conceptes bàsics i veure exemples de validació de formularis del costat del client.

Prerequisits: Coneixements bàsics d'informàtica i nocions d'HTML, CSS i JavaScript.
Objectiu: Entendre què és la validació de formularis de costat del client, per què és important i conèixer-ne diverses tècniques d’implementació.

La validació del costat del client és una comprovació inicial i una característica important que garanteix una bona experiència d’usuari; si es detecten dades no vàlides del costat del client, l'usuari pot corregir-les immediatament. Si van al servidor i aquest les rebutja, es genera un retard perquè les dades s’envien de tornada a la banda del client perquè l'usuari les corregeixi.

Tanmateix, la validació del costat del client no s'ha de considerar una mesura de seguretat exhaustiva. Les aplicacions sempre han de dur a terme comprovacions de seguretat de qualsevol informació que s’envia en un formulari tant del costat del servidor com també del costat del client, perquè la validació del client és molt fàcil de desactivar i qualsevol usuari maliciós pot enviar fàcilment dades incorrectes al teu servidor. Llegeix La seguretat dels llocs web per a fer-te una idea de què podria passar; implementar la validació del costat del servidor és fora de l’àmbit d’aquest mòdul, però l’has de tenir en compte.

Què és la validació de formularis?

Ves a qualsevol lloc web popular que tingui un formulari d’inscripció i observa que et fan comentaris quan no introdueixes les dades en el format que s’espera. Rebràs missatges com ara:

  • «Aquest camp és obligatori» (no es pot deixar en blanc).
  • «Si et plau, introdueix el número de telèfon en el format xxx-xxxx» (cal un format de dades específic que es consideri vàlid).
  • «Si et plau, introdueix una adreça de correu electrònic vàlida» (les dades que has introduït no tenen el format adequat).
  • «La contrasenya ha de tenir entre 8 i 30 caràcters i ha de contenir una lletra majúscula, un símbol i un número» (cal un format de dades molt específic).

Això es coneix com validació de formulari. Quan introdueixes dades, el navegador i/o el servidor web comproven que les dades estan en el format correcte i són dins de les restriccions que l’aplicació estableix. La validació que es fa en el navegador s’anomena validació del costat del client, mentre que la validació que es fa en el servidor s’anomena validació del costat del servidor. En aquest article ens centrem en la validació del costat del client.

Si la informació està en el format correcte, l'aplicació permet que les dades que les dades s’enviïn al servidor i (normalment) es guarden en una base de dades; si la informació no té el format correcte, es proporciona a l'usuari un missatge d'error en què li explica què ha de corregir, i s'ha de tornar a provar.

Volem fer que l’emplenament dels formularis web sigui tan fàcil com sigui possible. Aleshores, per què insistim que cal validar els nostres formularis? Hi ha tres raons principals:

  • Volem recollir les dades correctes en el format adequat. Les aplicacions no funcionen correctament si les dades dels usuaris s’emmagatzemen en un format equivocat, si són incorrectes, o senzillament si no n’hi ha.
  • Volem protegir les dades dels nostres usuaris. Obligar els usuaris a introduir contrasenyes segures facilita la protecció de la informació del seu compte.
  • Volem protegir-nos. Un usuari maliciós té moltes maneres de fer un mal ús dels formularis que no disposen de protecció, i pot danyar l’aplicació (consulta La seguretat dels llocs web).
    Atenció: No et refiïs mai de les dades que passen del client al servidor. Fins i tot quan el teu formulari es valida correctament i s’evita l’entrada de dades en format incorrecte del costat del client, un usuari maliciós encara pot modificar la sol·licitud de xarxa.

Els diferents tipus de validació del costat del client

Els llocs web poden presentar dos tipus diferents de validació del costat del client

  • La validació de formulari integrada utilitza les funcions de validació dels formularis HTML5, que ja hem comentat en altres articles d'aquest mòdul. En general, aquesta validació no requereix JavaScript. La validació de formulari integrada té un rendiment més bo que el JavaScript, però no és tan personalitzable com la validació amb JavaScript.
  • La validació amb JavaScript es codifica en llenguatge JavaScript. Aquesta validació és totalment personalitzable, però cal crear-la tota (o bé fer servir una biblioteca de fitxers).

Ús de la validació de formulari integrada

Una de les característiques més significatives dels controls de formulari HTML5 és la capacitat de validar la majoria de les dades de l'usuari sense dependre de JavaScript. Això es fa gràcies als atributs de validació dels elements del formulari. Ja n'hem vist uns quants, però en fem una recapitulació:

  • required: Especifica si cal emplenar un camp de formulari abans de poder enviar el formulari.
  • minlength i maxlength: Especifica la longitud mínima i màxima de les dades textuals (cadenes)
  • min i max: Especifica els valors mínims i màxims dels tipus d'entrada numèrics.
  • type: Especifica si les dades han de ser un número, una adreça de correu electrònic o algun altre tipus específic preestablert.
  • pattern: Especifica una expressió regular que defineix un patró que han de seguir les dades introduïdes.

Si les dades que s’introdueixen en un camp de formulari segueixen les regles especificades pels atributs anteriors, es consideren vàlides. Si no és així, es consideren no vàlides.

Quan un element és vàlid, es compleixen els aspectes següents:

  • L’element coincideix amb la pseudoclasse :valid de CSS, que et permet aplicar un estil específic als elements vàlids.
  • Quan l’usuari valida les dades, el navegador envia el formulari, sempre que no hi hagi res més que ho impedeixi (per exemple, JavaScript).

Quan un element no és vàlid, es verifica el següent:

  • L'element coincideix amb la pseudoclasse :invalid de CSS, i de vegades amb altres pseudoclasses de la interfície d'usuari (per exemple, :out-of-range), segons el tipus d'error, i això et permet aplicar un estil específic als elements no vàlids.
  • Quan l’usuari valida les dades, el navegador bloca l’enviament del formulari i mostra un missatge d’error.

Nota: Els diversos errors que impedeixen enviar el formulari inclouen badInput, patternMismatch, rangeOverflow o rangeUnderflow, stepMismatch, tooLong o tooShort, typeMismatch, valueMissing, o customError.

Exemples de validació de formularis integrada

En aquesta secció provarem alguns dels atributs que hem esmentat abans.

Un fitxer d’inici senzill

Comencem amb un exemple senzill: una entrada que permet triar si prefereixes un plàtan o una cirera. Aquest exemple inclou una entrada de text <input> senzilla amb una etiqueta <label> associada i un <button> de validació. En pots trobar el codi d’origen a GitHub, en el fitxer fruit-start.html, i l’exemple en viu a continuació.

<form>
  <label for="choose">Would you prefer a banana or a cherry?</label>
  <input id="choose" name="i_like">
  <button>Submit</button>
</form>
input:invalid {
  border: 2px dashed red;
}

input:valid {
  border: 2px solid black;
}

Per començar, fes una còpia del fitxer fruit-start.html en un directori nou del teu disc dur.

L’atribut required

La característica de validació HTML5 més simple és l’atribut required (obligatori). Afegeix aquest atribut a l'element si vols que una entrada sigui obligatòria. Quan es defineix aquest atribut, l'element coincideix amb la pseudoclasse :required de la interfície d'usuari i el formulari no s’envia; si l'entrada és buida, en el moment de validar mostra un missatge d'error. L’entrada, tot i que és buida, es considera no vàlida i coincideix amb la pseudoclasse de la interfície d'usuari :invalid.

Afegeix un atribut required a la teva entrada, com es mostra a continuació.

<form>
  <label for="choose">Would you prefer a banana or a cherry? (requested)</label>
  <input id="choose" name="i_like" required>
  <button>Submit</button>
</form>

Tingues en compte el CSS que s'ha inclòs en el fitxer d'exemples:

input:invalid {
  border: 2px dashed red;
}

input:invalid:required {
  background-image: linear-gradient(to right, pink, lightgreen);
}

input:valid {
  border: 2px solid black;
}

Aquest CSS afegeix una vora vermella quan l’entrada no és vàlida i una vora negra més subtil quan és vàlida. També hi afegeix un degradat de fons quan l’entrada és necessària i no vàlida. Prova’n el comportament nou en l'exemple següent:

Nota: Pots trobar aquest exemple en directe a GitHub en el fitxer fruit-validation.html (consulta’n també el codi d’origen.)

Prova de validar el formulari sense cap valor. Observa que l’entrada no vàlida pren el focus, apareix un missatge d’error per defecte («Emplena aquest camp») i el formulari no s’envia.

La presència de l'atribut required en qualsevol element que admet aquest atribut significa que l'element coincideix amb la pseudoclasse :required, tant si té un valor com si no. Si <input> no té cap valor, l’element input coincideix amb la pseudoclasse :invalid.

Nota: Si vols oferir una bona experiència d'usuari, indica quan són obligatoris els camps de formulari. No és només una bona experiència d’usuari, sinó que ho demanen les directrius d’accessibilitat de WCAG. A més, demana només les dades que necessites realment. Per què necessites saber, per exemple, el gènere o el títol d’algú?

Validar una expressió regular

Una altra característica útil de la validació és l’atribut pattern, que espera una expressió regular com a valor. Una expressió regular (regex) és un patró que es pot utilitzar per a establir combinacions de caràcters en cadenes de text, de manera que resulten ideals per a la validació de formularis i serveixen per a molts altres usos en JavaScript.

Els regex són força complexos i no pretenem ensenyar-los exhaustivament en aquest article. A continuació te’n mostrem alguns exemples perquè et puguis fer una idea bàsica de com funcionen.

  • a: Coincideix amb un caràcter que és a (ni b, ni aa, etc.).
  • abc: Coincideix amb a, seguit de b i de c.
  • ab?c: Coincideix amb a, seguit opcionalment d’un sol b, seguit de c ( ac o abc)
  • ab*c: Coincideix amb a, opcionalment seguit de qualsevol nombre de caràcters b, seguit de c. (ac, abc, abbbbbc, etc.).
  • a|b: Coincideix amb un caràcter que és a o b.
  • abc|xyz: Coincideix exactament amb abc o exactament amb xyz (però no amb abcxyz o a o y, etc.).

Hi ha moltes més possibilitats, que no presentem aquí. Per a obtenir-ne una llista completa i molts exemples, consulta la nostra documentació sobre expressions regulars.

Posem-ho en pràctica amb un exemple. Afegeix al teu codi HTML un atribut pattern, d'aquesta manera:

<form>
  <label for="choose">Would you prefer a banana or a cherry?</label>
  <input id="choose" name="i_like" required pattern="[Bb]anana|[Cc]herry">
  <button>Submit</button>
</form>

Això ens proporciona l’actualització següent. Prova-ho:

Nota: Pots trobar aquest exemple en directe a GitHub en el fitxer fruit-pattern.html (consulta’n també el codi d’origen).

En aquest exemple, l’element <input> accepta un dels quatre valors possibles: les cadenes «banana», «Banana», «cherry» o «Cherry». Les expressions regulars distingeixen entre majúscules i minúscules, però hem eliminat aquesta característica utilitzant un patró «Aa» extra situat entre claudàtors.

En aquest punt, intenta canviar el valor de l’atribut pattern per a igualar alguns dels exemples que has vist abans, i observa com això afecta els valors que pots introduir perquè que el valor d’entrada sigui vàlid. Prova d'escriure-hi alguna cosa i observa què passa. Intenta tant com sigui possible que estiguin relacionats amb la fruita perquè els teus exemples siguin coherents.

Si un valor <input> no buit no coincideix amb el patró de l'expressió regular, input coincideix amb la pseudoclasse :invalid.

Nota: Alguns tipus d'elements <input> no necessiten validar una expressió regular amb l’atribut pattern. Si especifiques el tipus email, per exemple, el valor d’entrada es valida amb un patró d’adreça de correu electrònic ben formada, o amb un patró que coincideix amb una llista d’adreces de correu electrònic separades per comes si té l’atribut multiple.

Nota: L'element <textarea> no admet l'atribut pattern.

Restringir la longitud de les entrades

Pots restringir la longitud de caràcters de tots els camps de text creats amb <input> o <textarea> amb els atributs minlength i maxlength. Un camp no és vàlid si té un valor que té menys caràcters que el valor assignat a minlength, o més que el valor assignat a maxlength.

Els navegadors sovint no permeten que l'usuari escrigui un valor més llarg del que s'espera en els camps de text. Una experiència d’usuari encara més bona que utilitzar només maxlength és proporcionar també comentaris de recompte de caràcters d’una manera accessible, i deixar editar el contingut fins que sigui d’una mida més reduïda. Un exemple d'això és el límit de caràcters de Twitter. Per a això pots utilitzar JavaScript, incloses les solucions que fan servir maxlength.

Restringir els valors de les entrades

Per als camps d’entrada de números (és a dir, <input type="number">), es poden utilitzar els atributs min i max, que proporcionen un rang de valors vàlids. Un camp que conté un valor que cau fora d'aquest interval no és vàlid.

Observem-ne un altre exemple. Crea una còpia nova del fitxer fruit-start.html.

A continuació suprimeix el contingut de l'element <body> i substitueix-lo pel següent:

<form>
  <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input type="text" id="choose" name="i_like" required minlength="6" maxlength="6">
  </div>
  <div>
    <label for="number">How many would you like?</label>
    <input type="number" id="number" name="amount" value="1" min="1" max="10">
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
  • Observa que aquí hem donat al camp de text una longitud mínima (minlength) i una longitud màxima (maxlength) de sis, la mateixa longitud que tenen banana i cherry.
  • També hem donat al camp number un valor min d’1 i un valor max de 10. Els números introduïts fora d'aquest interval es presenten com no vàlids; els usuaris no poden utilitzar les fletxes d’increment/decrement per a desplaçar el valor fora d’aquest interval. Si l’usuari introdueix manualment un número que està fora d’aquest interval, les dades no són vàlides. El número no és obligatori, de manera que eliminar el valor encara dona un valor vàlid.

Aquí tens l’execució en viu de l’exemple:

Nota: Pots trobar aquest exemple en viu a GitHub en el fitxer fruit-length.html (o també consultar-ne el codi d’origen.)

Nota: <input type="number"> (i altres tipus, com ara range i date) també poden tenir un atribut step, que especifica quin increment augmenta o disminueix el valor quan s'utilitzen els controls d'entrada (com ara els botons numèrics d’increment i decrement). En l'exemple anterior no hem inclòs un atribut step, de manera que el valor per defecte és 1. Això vol dir que els números de coma flotant (com ara el 3,2) també es mostren com a no vàlids.

Exemple complet

A continuació hi ha un exemple complet que mostra l'ús de les funcions de validació integrades en HTML. En primer lloc, una mica d'HTML:

<form>
  <p>
    <fieldset>
      <legend>Do you have a driver's license?<abbr title="This field is mandatory" aria-label="required">*</abbr></legend>
      <!-- While only one radio button in a same-named group can be selected at a time,
           and therefore only one radio button in a same-named group having the "required"
           attribute suffices in making a selection a requirement --> 
      <input type="radio" required name="driver" id="r1" value="yes"><label for="r1">Yes</label>
      <input type="radio" required name="driver" id="r2" value="no"><label for="r2">No</label>
    </fieldset>
  </p>
  <p>
    <label for="n1">How old are you?</label>
    <!-- The pattern attribute can act as a fallback for browsers which
         don't implement the number input type but support the pattern attribute.
         Please note that browsers that support the pattern attribute will make it
         fail silently when used with a number field.
         Its usage here acts only as a fallback -->
    <input type="number" min="12" max="120" step="1" id="n1" name="age"
           pattern="\d+">
  </p>
  <p>
    <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory" aria-label="required">*</abbr></label>
    <input type="text" id="t1" name="fruit" list="l1" required
           pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range">
    <datalist id="l1">
      <option>Banana</option>
      <option>Cherry</option>
      <option>Apple</option>
      <option>Strawberry</option>
      <option>Lemon</option>
      <option>Orange</option>
    </datalist>
  </p>
  <p>
    <label for="t2">What's your e-mail address?</label>
    <input type="email" id="t2" name="email">
  </p>
  <p>
    <label for="t3">Leave a short message</label>
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
  </p>
  <p>
    <button>Submit</button>
  </p>
</form>

I ara, una mica de CSS per a aplicar estil al codi HTML:

form {
  font: 1em sans-serif;
  max-width: 320px;
}

p > label {
  display: block;
}

input[type="text"],
input[type="email"],
input[type="number"],
textarea,
fieldset {
  width: 100%;
  border: 1px solid #333;
  box-sizing: border-box;
}

input:invalid {
  box-shadow: 0 0 5px 1px red;
}

input:focus:invalid {
  box-shadow: none;
}

Això dona la sortida següent:

Consulta una llista completa d’atributs que es poden utilitzar per a restringir els valors d’entrada i els tipus d’entrada que els admeten en els atributs relacionats amb la validació.

Nota: Pots trobar aquest exemple en viu a GitHub, en el fitxer full-example.html (o consultar-ne també el codi d’origen).

Validació de formularis amb JavaScript

Has d’utilitzar JavaScript si vols controlar l’aspecte dels missatges d’error originals o fer-los compatibles amb els navegadors antics que no admeten la validació de formularis integrada en HTML. En aquesta secció veurem les diferents maneres de fer això.

L’API de validació de restriccions

La majoria dels navegadors admeten l'API de validació de restriccions, que consta d'un conjunt de mètodes i propietats disponibles en les interfícies DOM per als elements de formulari següents:

L’API de validació de restriccions posa a la disposició dels elements anteriors les propietats següents.

  • validationMessage: Retorna un missatge localitzat que descriu les restriccions de validació que el control no satisfà (si n'hi ha). Si el control de formulari no és candidat a validació de restriccions (willValidate és false) o si el valor de l’element satisfà les restriccions (és vàlid), retorna una cadena buida.
  • validity: Retorna un objecte ValidityState que conté diverses propietats que descriuen l'estat de validesa de l'element. Pots trobar tots els detalls de les propietats disponibles a la pàgina de referència ValidityState; a continuació se n'enumeren uns quants dels més comuns:
    • patternMismatch: Retorna true si el valor no coincideix amb el pattern especificat, i false si hi coincideix. Si és true, l'element coincideix amb la pseudoclasse :invalid de CSS.
    • rangeOverflow: Retorna true si el valor és superior al màxim especificat per l’atribut max, o false si és inferior o igual al màxim. Si és true, l'element coincideix amb les pseudoclasses :invalid i :out-of-range de CSS.
    • rangeUnderflow: Retorna true si el valor és inferior al mínim especificat per l’atribut min, o false si és superior o igual al mínim. Si és true, l'element coincideix amb les pseudoclasses :invalid i :out-of-range de CSS.
    • typeMismatch: Retorna true si el valor no està en la sintaxi requerida (quan type és un correu electrònic o una url), o false si la sintaxi és correcta. Si és true, l'element coincideix amb la pseudoclasse :invalid de CSS.
    • valid: Retorna true si l'element compleix totes les limitacions de validació i es considera que és vàlid, o false si falla alguna restricció. Si és true, l'element coincideix amb la pseudoclasse :valid de CSS; o amb la pseudo-classe :invalid de CSS en cas contrari.
    • valueMissing: Retorna true si l'element té un atribut required sense cap valor, o false en cas contrari. Si és true, l'element coincideix amb la pseudoclasse :invalid de CSS.
  • willValidate: Retorna true si l'element es valida en enviar-se el formulari; false en cas contrari.

L'API de validació de restriccions també ofereix als elements anteriors els mètodes següents:

  • checkValidity(): Retorna true si el valor de l'element no té problemes de validesa; false en cas contrari. Si l'element no és vàlid, aquest mètode també activa un esdeveniment no vàlid (invalid event) sobre l'element.
  • setCustomValidity(message): Afegeix un missatge d'error personalitzat a l'element; si configures un missatge d’error personalitzat, es considera que l’element no és vàlid i es mostra l’error especificat. Això et permet utilitzar el codi JavaScript per a establir un error de validació diferent dels que ofereixen les restriccions de validació estàndard en HTML5. El missatge es mostra a l'usuari en informar del problema.

Missatges d’error personalitzats

Com has vist en els exemples de restricció de validació HTML5 anteriors, cada vegada que un usuari intenta enviar un formulari no vàlid, el navegador mostra un missatge d'error. La manera com es mostra aquest missatge depèn del navegador.

Aquests missatges automatitzats tenen dos inconvenients:

  • No hi ha una manera estàndard de canviar-ne l’aparença amb CSS.
  • Depenen de la configuració regional del navegador, que significa que pots tenir una pàgina en un idioma, però que un missatge d'error es mostri en un altre idioma, com es pot veure a la captura de pantalla de Firefox següent.

Exemple d’un missatge d’error a Firefox en francès en una pàgina en anglès

La personalització d’aquests missatges d’error és un dels casos d’ús més comuns de l’API de validació de restriccions. Vegem la manera de fer-ho amb un exemple senzill.

Començarem amb alguns elements senzills d’HTML (no dubtis a posar-ho en un fitxer HTML en blanc; utilitza una còpia nova del fitxer fruit-start.html com a base, si vols):

<form>
  <label for="mail">I would like you to provide me with an e-mail address: </label>
  <input type="email" id="mail" name="mail">
  <button>Submit</button>
</form>

I afegeix a la pàgina el JavaScript següent:

const email = document.getElementById("mail");

email.addEventListener("input", function (event) {
  if (email.validity.typeMismatch) {
    email.setCustomValidity(«I am expecting an e-mail address!»);
  } else {
    email.setCustomValidity("");
  }
});

Aquí emmagatzemem una referència a l’entrada de correu electrònic, i a continuació afegim un detector d’esdeveniments que executa el codi de content cada vegada que es modifica el valor dins de l’entrada.

Dins del codi de content, comprovem si la propietat validity.typeMismatch de l’entrada de correu electrònic retorna true, que significa que el valor que conté no coincideix amb el patró d’una adreça de correu electrònic ben formada. Si és així, cridem el mètode setCustomValidity() amb un missatge personalitzat. Això fa que l’entrada no sigui vàlida, de manera que quan intentes enviar el formulari, l’enviament falla i es mostra el missatge d’error personalitzat.

Si la propietat validity.typeMismatch retorna false, cridem el mètode setCustomValidity() amb una cadena buida. Això fa que l’entrada sigui vàlida, i el formulari s’envia.

Pots provar-ho a continuació:

Nota: Pots trobar aquest exemple en viu a GitHub en el fitxer custom-error-message.html (consulta’n també el codi d’origen).

Un exemple més detallat

Ara que hem vist un exemple molt senzill; observem com podem utilitzar aquesta API per a crear una validació personalitzada una mica més complexa.

En primer lloc, el codi HTML. Un cop més, no dubtis a construir-lo amb nosaltres:

<form novalidate>
  <p>
    <label for="mail">
      <span>Please enter an email address:</span>
      <input type="email" id="mail" name="mail" required minlength="8">
      <span class="error" aria-live="polite"></span>
    </label>
  </p>
  <button>Submit</button>
</form>

Aquest formulari senzill utilitza l’atribut novalidate, que desactiva la validació automàtica del navegador; això permet que el nostre codi prengui el control de la validació. Però això no desactiva la compatibilitat per a l’API de validació de restriccions ni l’aplicació de pseudoclasses CSS com :valid, etc. Això vol dir que, tot i que el navegador no comprova automàticament la validesa del formulari abans d’enviar les dades, encara pots fer-ho tu mateix i dissenyar el formulari en conseqüència.

La nostra entrada per validar és <input type="email">, que està marcada com a required i té una longitud mínima (minlength) de 8 caràcters. Comprovem-ho amb el nostre codi i mostrem un missatge d'error personalitzat per a cada element.

El nostre objectiu és mostrar els missatges d'error dins d'un element <span>. L'atribut aria-live està establert a <span> per a assegurar-nos que el missatge d'error personalitzat serà visible per a tothom, inclosos els usuaris que empren lectors de pantalla.

Nota: Un element clau aquí és el fet que establir l’atribut novalidate en el formulari impedeix el formulari de mostrar els quadres de diàleg de missatge d’error propis, i permet de mostrar els missatges d’error personalitzats en el DOM de la manera que escollim.

Ara una mica de CSS bàsic per a millorar una mica l’aspecte del formulari i proporcionar informació visual quan les dades d’entrada no són vàlides:

body {
  font: 1em sans-serif;
  width: 200px;
  padding: 0;
  margin : 0 auto;
}

p * {
  display: block;
}

input[type=email]{
  -webkit-appearance: none;
  appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  box-sizing: border-box;
}

/* Aquest és el nostre estil per als camps no vàlids */
input:invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus:invalid {
  outline: none;
}

/* Aquest és l'estil per als nostres missatges d'error */
.error {
  width  : 100%;
  padding: 0;

  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;

  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}

A continuació veurem el JavaScript que implementa la validació d'errors personalitzada.

// Hi ha moltes maneres de triar un node DOM; amb aquest obtenim el formulari en si i el control de formulari de tipus caixa d’entrada 
// de correu electrònic, i també l’element span en què col·locarem el missatge d’error.
const form  = document.getElementsByTagName('form')[0];

const email = document.getElementById('mail');
const emailError = document.querySelector('#mail + span.error');

email.addEventListener('input', function (event) {
  // Cada vegada que l’usuari escriu alguna cosa, comprovem si els
  // camps del formulari són vàlids.

  if (email.validity.valid) {
    // En cas que hi hagi un missatge d’error visible, si el camp
    // és vàlid, n’eliminem el missatge d'error.
    emailError.innerHTML = ''; // Restablim el contingut del missatge
    emailError.className = 'error'; // Restablim l'estat visual del missatge
  } else {
    // Si encara hi ha un error, mostrem l'error correcte
    ShowError();
  }
});

form.addEventListener('submit', function (event) {
  // si el camp de correu electrònic és vàlid, enviem el formulari

  if(!email.validity.valid) {
    // Si no és així, mostrem el missatge d'error corresponent
    showError();
    // Aleshores, cancel·lem l’esdeveniment i evitem que s’enviï el formulari
    event.preventDefault();
  }
});

function showError() {
  if(email.validity.valueMissing) {
    // Si el camp està buit
    // mostra el missatge d'error següent.
    emailError.textContent = 'You need to enter an e-mail address.';
  } else if(email.validity.typeMismatch) {
    // Si el camp no conté una adreça de correu electrònic
    // mostra el missatge d'error següent.
    emailError.textContent = 'Entered value needs to be an e-mail address.';
  } else if(email.validity.tooShort) {
    // Si les dades són massa curtes
    // mostra el missatge d'error següent.
    emailError.textContent = `el correu electrònic ha de tenir com a mínim $ {email.minLength} caràcters; n'heu introduït $ {email.value.length}. ';
  }

  // Configura l’estil de manera adequada
  emailError.className = 'error active';
}

Els comentaris expliquen les coses força bé, però de manera breu:

  • Cada vegada que canviem el valor de l’entrada, comprovem si conté dades vàlides. Si n’hi ha, eliminem qualsevol missatge d'error que es mostri. Si les dades no són vàlides, executem showError() perquè es mostri l'error adequat.
  • Cada vegada que intentem enviar el formulari, tornem a comprovar si les dades són vàlides. En cas afirmatiu, enviem el formulari. Si no, executem showError() perquè es mostri l’error adequat i aturem l’enviament del formulari amb preventDefault().
  • La funció showError() utilitza diverses propietats de l'objecte validity de l'entrada de text per a determinar de quin error es tracta, i a continuació mostra el missatge d'error que hi correspon.

Aquest és el resultat en viu:

Nota: Pots trobar aquest exemple en viu a GitHub en el fitxer detailed-custom-validation.html (consulta’n també el codi d’origen).

L'API de validació de restriccions t’ofereix una eina poderosa per a gestionar la validació de formularis i et proporciona un gran control sobre la interfície d'usuari, més enllà del que hi pots fer només amb l’HTML i el CSS.

Nota: Per obtenir més informació, consulta la nostra guia de validació de restriccions i la referència de l'API de validació de restriccions.

Validació dels formularis sense una API integrada

En alguns casos, com ara la compatibilitat amb navegadors antics o els controls personalitzats, no podràs o no voldràs utilitzar l'API de validació de restriccions. Aleshores pots utilitzar JavaScript per a validar el teu formulari, només que l'hauràs d’escriure.

Per a validar un formulari, planteja’t unes quantes preguntes:

Quin tipus de validació he de fer?
Has de determinar com validar les dades: operacions amb variables de cadena, conversió de tipus, expressions regulars, etc. Tot depèn de tu.
Què he de fer si el formulari no es valida?
Això és clarament una qüestió de la interfície d'usuari. Has de decidir com es comporta el formulari. El formulari ha d’enviar les dades igualment? Has de destacar els camps que tenen un error? Has de mostrar missatges d’error?
Com puc ajudar l’usuari a corregir dades no vàlides?
Per a reduir la frustració de l’usuari és molt important proporcionar la informació més útil possible i orientar-lo en la correcció de les entrades. Has d’oferir suggeriments anticipats perquè sàpiguen què se n’espera, i missatges d’error clars. Si vols aprofitar els requisits de la interfície d'usuari de validació de formularis, aquí tens alguns articles útils:

Un exemple que no utilitza l'API de validació de restriccions

A continuació es mostra una versió simplificada de l'exemple anterior que funciona amb navegadors antics.

L’HTML és gairebé el mateix; només n’hem tret les funcions de validació HTML.

<form>
  <p>
    <label for="mail">
        <span>Please enter an email address::</span>
        <input type="text" class="mail" id="mail" name="mail">
        <span class="error" aria-live="polite"></span>
    </label>
  </p>
  <!-- Alguns navegadors antics han de tenir l’atribut «type»
       definit explícitament com «submit» en l'element «button»
  <button type="submit">Submit</button>
</form>

De la mateixa manera, el CSS no ha de canviar gaire; acabem de convertir la pseudoclasse :invalid de CSS en una classe real i hem evitat utilitzar el selector d'atributs que no funciona en Internet Explorer 6.

body {
  font: 1em sans-serif;
  width: 200px;
  padding: 0;
  margin : 0 auto;
}

form {
  max-width: 200px;
}

p * {
  display: block;
}

input.mail {
  -webkit-appearance: none;

  width: 100%;
  border: 1px solid #333;
  margin: 0;

  font-family: inherit;
  font-size: 90%;

  box-sizing: border-box;
}

/* Aquest és el nostre estil per als camps no vàlids */
input.invalid{
  border-color: #900;
  background-color: #FDD;
}

input:focus.invalid {
  outline: none;
}

/* Aquest és l'estil dels nostres missatges d'error */
.error {
  width  : 100%;
  padding: 0;
 
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}

.error.active {
  padding: 0.3em;
}

Els grans canvis es produeixen en el codi JavaScript, que ha de fer molta més feina feixuga.

// Hi ha menys maneres de seleccionar un node DOM amb navegadors antics
const form  = document.getElementsByTagName('form')[0];
const email = document.getElementById('mail');

// A continuació es mostra un truc per a arribar al node següent d’elements germans en el DOM.
// Això és perillós perquè pots crear fàcilment un bucle infinit.
// En els navegadors moderns és preferible utilitzar element.nextElementSibling
let error = email;
while ((error = error.nextSibling).nodeType != 1);

// segons l'especificació HTML5
const emailRegExp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

// Molts navegadors antics no són compatibles amb el mètode addEventListener.
// Aquesta és una manera senzilla de tractar això; però no n’és l’única.
function addEvent(element, event, callback) {
  let previousEventCallBack = element["on"+event];
  element["on"+event] = function (e) {
    const output = callback(e);

    // Una crida que retorna «false» atura la cadena de devolució
    // i interromp l'execució de l'esdeveniment de retorn de la crida
    if (output === false) return false;

    if (typeof previousEventCallBack === 'function') {
      output = previousEventCallBack(e);
      if(output === false) return false;
    }
  }
};

// Ara podem reconstruir la nostra restricció de validació
// Com que no ens basem en cap pseudoclasse de CSS, hem 
// d'establir explícitament la classe vàlida/invàlida en el nostre camp de correu electrònic
addEvent(window, "load", function () {
  // Aquí comprovem si el camp està buit (recorda que no és un camp obligatori)
  // Si no ho està, comprovem si el contingut és una adreça de correu electrònic ben formada.
  const test = email.value.length === 0 || emailRegExp.test(email.value);

  email.className = test ? "valid" : "invalid";
});

// Això defineix què passa quan l'usuari escriu en el camp
addEvent(email, "input", function () {
  const test = email.value.length === 0 || emailRegExp.test(email.value);
  if (test) {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  } else {
    email.className = "invalid";
  }
});

// Això defineix què passa quan l’usuari intenta enviar les dades
addEvent(form, "submit", function () {
  const test = email.value.length === 0 || emailRegExp.test(email.value);

  if (!test) {
    email.className = "invalid";
    error.innerHTML = "I expect an e-mail, darling!";
    error.className = "error active";

    // Alguns navegadors antics no admeten el mètode event.preventDefault ()
    return false;
  } else {
    email.className = "valid";
    error.innerHTML = "";
    error.className = "error";
  }
});

El resultat és el següent:

Com pots veure, no és tan difícil construir un sistema de validació pel teu compte. La part difícil és que sigui prou genèric perquè es pugui utilitzar tant en múltiples plataformes com en qualsevol formulari que puguis crear. Disposes de moltes biblioteques de fitxers que et permeten executar una validació de formulari, com ara Validate.js.

Resum

De vegades, la validació de formulari del costat del client necessita JavaScript si vols personalitzar els missatges d’estil i d’error, però sempre requereix que pensis detingudament en l’usuari. Recorda d’ajudar sempre els usuaris a corregir les dades que et proporcionen. Per a això, assegura’t de:

  • Mostrar missatges d’error explícits.
  • Ser permissiu amb els formats d’entrada.
  • Assenyalar exactament on es produeix l’error, sobretot en els formularis grans.

Un cop comprovat que el formulari s'ha emplenat correctament, pots procedir a enviar-lo. A continuació exposarem l’enviament de les dades d’un formulari.

En aquest mòdul

Temes avançats