1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
|
---
title: Validació de formularis del costat del client
slug: Learn/HTML/Forms/Validacio_formularis
translation_of: Learn/Forms/Form_validation
---
<div>{{LearnSidebar}}</div>
<div>{{PreviousMenuNext("Learn/Forms/UI_pseudo-classes", "Learn/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</div>
<p>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 <strong>validació de formularis del costat del client</strong>, 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.</p>
<table class="learn-box standard-table">
<tbody>
<tr>
<th scope="row">Prerequisits:</th>
<td>Coneixements bàsics d'informàtica i nocions d'<a href="/ca/docs/Learn/HTML">HTML</a>, <a href="/ca/docs/Learn/CSS">CSS</a> i <a href="/ca/docs/Learn/JavaScript">JavaScript</a>.</td>
</tr>
<tr>
<th scope="row">Objectiu:</th>
<td>Entendre què és la validació de formularis de costat del client, per què és important i conèixer-ne diverses tècniques d’implementació.</td>
</tr>
</tbody>
</table>
<p>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.</p>
<p>Tanmateix, la validació del costat del client <em>no s'ha de considerar</em> 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 <em>tant del costat del servidor</em> com <strong>també</strong> <em>del costat del client</em>, 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 <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">La seguretat dels llocs web</a> per a fer-te una idea de què <em>podria</em> passar; implementar la validació del costat del servidor és fora de l’àmbit d’aquest mòdul, però l’has de tenir en compte.</p>
<h2 id="Què_és_la_validació_de_formularis">Què és la validació de formularis?</h2>
<p>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:</p>
<ul>
<li>«Aquest camp és obligatori» (no es pot deixar en blanc).</li>
<li>«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).</li>
<li>«Si et plau, introdueix una adreça de correu electrònic vàlida» (les dades que has introduït no tenen el format adequat).</li>
<li>«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).</li>
</ul>
<p>Això es coneix com <strong>validació de formulari</strong>. 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 <strong>validació del costat del client</strong>, mentre que la validació que es fa en el servidor s’anomena <strong>validació del costat del servidor</strong>. En aquest article ens centrem en la validació del costat del client.</p>
<p>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.</p>
<p>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:</p>
<ul>
<li><strong>Volem recollir les dades correctes en el format adequat.</strong> 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.</li>
<li><strong>Volem protegir les dades dels nostres usuaris</strong>. Obligar els usuaris a introduir contrasenyes segures facilita la protecció de la informació del seu compte.</li>
<li><strong>Volem protegir-nos</strong>. 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 <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">La seguretat dels llocs web</a>).
<div class="warning"><strong>Atenció:</strong> 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.</div>
</li>
</ul>
<h2 id="Els_diferents_tipus_de_validació_del_costat_del_client"><strong>Els diferents tipus de validació del costat del client</strong></h2>
<p>Els llocs web poden presentar dos tipus diferents de validació del costat del client</p>
<ul>
<li>La <strong>validació de formulari integrada</strong> 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.</li>
<li>La <strong>validació amb JavaScript</strong> es codifica en llenguatge JavaScript. Aquesta validació és totalment personalitzable, però cal crear-la tota (o bé fer servir una biblioteca de fitxers).</li>
</ul>
<h2 id="Ús_de_la_validació_de_formulari_integrada">Ús de la validació de formulari integrada</h2>
<p>Una de les característiques més significatives dels <a href="/en-US/docs/Learn/Forms/HTML5_input_types">controls de formulari HTML5</a> é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ó:</p>
<ul>
<li><code><a href="/en-US/docs/Web/HTML/Attributes/required">required</a></code>: Especifica si cal emplenar un camp de formulari abans de poder enviar el formulari.</li>
<li><code><a href="/en-US/docs/Web/HTML/Attributes/minlength">minlength</a></code> i <code><a href="/en-US/docs/Web/HTML/Attributes/maxlength">maxlength</a></code>: Especifica la longitud mínima i màxima de les dades textuals (cadenes)</li>
<li><code><a href="/en-US/docs/Web/HTML/Attributes/min">min</a></code> i <code><a href="/en-US/docs/Web/HTML/Attributes/max">max</a></code>: Especifica els valors mínims i màxims dels tipus d'entrada numèrics.</li>
<li><code>type</code>: Especifica si les dades han de ser un número, una adreça de correu electrònic o algun altre tipus específic preestablert.</li>
<li><code><a href="/en-US/docs/Web/HTML/Attributes/pattern">pattern</a></code>: Especifica una <a href="/ca/docs/Web/JavaScript/Guide/Regular_Expressions">expressió regular</a> que defineix un patró que han de seguir les dades introduïdes.</li>
</ul>
<p>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.</p>
<p>Quan un element és vàlid, es compleixen els aspectes següents:</p>
<ul>
<li>L’element coincideix amb la pseudoclasse {{cssxref(":valid")}} de CSS, que et permet aplicar un estil específic als elements vàlids.</li>
<li>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).</li>
</ul>
<p>Quan un element no és vàlid, es verifica el següent:</p>
<ul>
<li>L'element coincideix amb la pseudoclasse {{cssxref(":invalid")}} de CSS, i de vegades amb altres pseudoclasses de la interfície d'usuari (per exemple, {{cssxref(":out-of-range")}}), segons el tipus d'error, i això et permet aplicar un estil específic als elements no vàlids.</li>
<li>Quan l’usuari valida les dades, el navegador bloca l’enviament del formulari i mostra un missatge d’error.</li>
</ul>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Els diversos errors que impedeixen enviar el formulari inclouen {{domxref('validityState.badInput', 'badInput')}}, {{domxref('validityState.patternMismatch','patternMismatch')}}, {{domxref('validityState.rangeOverflow','rangeOverflow')}} o {{domxref('validityState.rangeUnderflow','rangeUnderflow')}}, {{domxref('validityState.stepMismatch','stepMismatch')}}, {{domxref('validityState.tooLong','tooLong')}} o {{domxref('validityState.tooShort','tooShort')}}, {{domxref('validityState.typeMismatch','typeMismatch')}}, {{domxref('validityState.valueMissing','valueMissing')}}, o {{domxref('validityState.customError','customError')}}.</p>
</div>
<h2 id="Exemples_de_validació_de_formularis_integrada"><strong>Exemples de validació de formularis integrada</strong></h2>
<p>En aquesta secció provarem alguns dels atributs que hem esmentat abans.</p>
<h3 id="Un_fitxer_d’inici_senzill">Un fitxer d’inici senzill</h3>
<p>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 {{HTMLElement("input")}} senzilla amb una etiqueta {{htmlelement("label")}} associada i un {{htmlelement("button")}} de validació. En pots trobar el codi d’origen a GitHub, en el fitxer <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a>, i l’exemple en viu a continuació.</p>
<pre class="brush: html notranslate"><form>
<label for="choose">Would you prefer a banana or a cherry?</label>
<input id="choose" name="i_like">
<button>Submit</button>
</form></pre>
<pre class="brush: css notranslate">input:invalid {
border: 2px dashed red;
}
input:valid {
border: 2px solid black;
}</pre>
<p>{{EmbedLiveSample("Un_fitxer_d’inici_senzill", "100%", 80)}}</p>
<p>Per començar, fes una còpia del fitxer <code>fruit-start.html</code> en un directori nou del teu disc dur.</p>
<h3 id="L’atribut_required">L’atribut required</h3>
<p>La característica de validació HTML5 més simple és l’atribut <code><a href="/en-US/docs/Web/HTML/Attributes/required">required</a></code> (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 {{cssxref(':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 {{cssxref(':invalid')}}.</p>
<p>Afegeix un atribut <code>required</code> a la teva entrada, com es mostra a continuació.</p>
<pre class="brush: html notranslate"><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></pre>
<p>Tingues en compte el CSS que s'ha inclòs en el fitxer d'exemples:</p>
<pre class="brush: css notranslate">input:invalid {
border: 2px dashed red;
}
input:invalid:required {
background-image: linear-gradient(to right, pink, lightgreen);
}
input:valid {
border: 2px solid black;
}</pre>
<p>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 <em>i</em> no vàlida. Prova’n el comportament nou en l'exemple següent:</p>
<p>{{EmbedLiveSample("L’atribut_required", "100%", 80)}}</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en directe a GitHub en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/fruit-required.html">fruit-validation.html</a> (consulta’n també el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-required.html">codi d’origen</a>.)</p>
</div>
<p>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.</p>
<p>La presència de l'atribut <code>required</code> en qualsevol element que admet aquest atribut significa que l'element coincideix amb la pseudoclasse {{cssxref(':required')}}, tant si té un valor com si no. Si {{HTMLElement("input")}} no té cap valor, l’element <code>input</code> coincideix amb la pseudoclasse {{cssxref(':invalid')}}.</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: 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’<a href="/ca/docs/Learn/Accessibility">accessibilitat</a> 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ú?</p>
</div>
<h3 id="Validar_una_expressió_regular">Validar una expressió regular</h3>
<p>Una altra característica útil de la validació és l’atribut <a href="/en-US/docs/Web/HTML/Attributes/pattern"><code>pattern</code></a>, que espera una <a href="/ca/docs/Web/JavaScript/Guide/Regular_Expressions">expressió regular</a> com a valor. Una expressió regular (<em>regex</em>) é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.</p>
<p>Els <em>regex</em> 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.</p>
<ul>
<li><code>a</code>: Coincideix amb un caràcter que és <code>a</code> (ni <code>b</code>, ni <code>aa</code>, etc.).</li>
<li><code>abc</code>: Coincideix amb <code>a</code>, seguit de <code>b</code> i de <code>c</code>.</li>
<li><code>ab?c</code>: Coincideix amb <code>a</code>, seguit opcionalment d’un sol <code>b</code>, seguit de <code>c</code> ( <code>ac</code> o <code>abc</code>)</li>
<li><code>ab*c</code>: Coincideix amb <code>a</code>, opcionalment seguit de qualsevol nombre de caràcters <code>b</code>, seguit de <code>c</code>. (<code>ac</code>, <code>abc</code>, <code>abbbbbc</code>, etc.).</li>
<li><code>a|b</code>: Coincideix amb un caràcter que és <code>a</code> o <code>b</code>.</li>
<li><code>abc|xyz</code>: Coincideix exactament amb <code>abc</code> o exactament amb <code>xyz</code> (però no amb <code>abcxyz</code> o <code>a</code> o <code>y</code>, etc.).</li>
</ul>
<p>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.</p>
<p>Posem-ho en pràctica amb un exemple. Afegeix al teu codi HTML un atribut <a href="/ca/docs/Web/JavaScript/Guide/Regular_Expressions"><code>pattern</code></a>, d'aquesta manera:</p>
<pre class="brush: html notranslate"><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>
</pre>
<div class="hidden">
<pre class="brush: css notranslate">input:invalid {
border: 2px dashed red;
}
input:valid {<strong>
</strong>border: 2px solid black;
}</pre>
</div>
<p>Això ens proporciona l’actualització següent. Prova-ho:</p>
<p>{{EmbedLiveSample("Validar_una_expressió_regular", "100%", 80)}}</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en directe a GitHub en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/fruit-pattern.html">fruit-pattern.html</a> (consulta’n també el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-pattern.html">codi d’origen</a>).</p>
</div>
<p>En aquest exemple, l’element {{HTMLElement("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.</p>
<p>En aquest punt, intenta canviar el valor de l’atribut <a href="/en-US/docs/Web/HTML/Attributes/pattern"><code>pattern</code></a> 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.</p>
<p>Si un valor {{HTMLElement("input")}} no buit no coincideix amb el patró de l'expressió regular, <code>input</code> coincideix amb la pseudoclasse {{cssxref(':invalid')}}.</p>
<div class="blockIndicator note">
<p><strong>Nota:</strong> Alguns tipus d'elements {{HTMLElement("input")}} no necessiten validar una expressió regular amb l’atribut <a href="/en-US/docs/Web/HTML/Attributes/pattern"><code>pattern</code></a>. Si especifiques el tipus <code>email</code>, 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 <a href="/en-US/docs/Web/HTML/Attributes/multiple"><code>multiple</code></a>.</p>
</div>
<div class="blockIndicator note">
<p><strong><strong>Nota</strong>: </strong>L'element {{HTMLElement("textarea")}} no admet l'atribut <a href="/en-US/docs/Web/HTML/Attributes/pattern"><code>pattern</code></a>.</p>
</div>
<h3 id="Restringir_la_longitud_de_les_entrades">Restringir la longitud de les entrades</h3>
<p>Pots restringir la longitud de caràcters de tots els camps de text creats amb {{HTMLElement("input")}} o {{HTMLElement("textarea")}} amb els atributs <a href="/en-US/docs/Web/HTML/Attributes/minlength"><code>minlength</code></a> i <code><a href="/en-US/docs/Web/HTML/Attributes/maxlength">maxlength</a></code>. Un camp no és vàlid si té un valor que té menys caràcters que el valor assignat a <a href="/en-US/docs/Web/HTML/Attributes/minlength"><code>minlength</code></a>, o més que el valor assignat a <code><a href="/en-US/docs/Web/HTML/Attributes/maxlength">maxlength</a></code>.</p>
<p>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 <code>maxlength</code> é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 <a href="https://github.com/mimo84/bootstrap-maxlength">solucions que fan servir <code>maxlength</code></a>.</p>
<h3 id="Restringir_els_valors_de_les_entrades">Restringir els valors de les entrades</h3>
<p>Per als camps d’entrada de números (és a dir, <code><a href="/en-US/docs/Web/HTML/Element/input/number"><input type="number"></a></code>), es poden utilitzar els atributs <code><a href="/en-US/docs/Web/HTML/Attributes/min">min</a></code> i <code><a href="/en-US/docs/Web/HTML/Attributes/max">max</a></code>, que proporcionen un rang de valors vàlids. Un camp que conté un valor que cau fora d'aquest interval no és vàlid.</p>
<p>Observem-ne un altre exemple. Crea una còpia nova del fitxer <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a>.</p>
<p>A continuació suprimeix el contingut de l'element <code><body></code> i substitueix-lo pel següent:</p>
<pre class="brush: html notranslate"><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></pre>
<ul>
<li>Observa que aquí hem donat al camp de <code>text</code> una longitud mínima (<code>minlength</code>) i una longitud màxima (<code>maxlength</code>) de sis, la mateixa longitud que tenen <em>banana</em> i <em>cherry</em>.</li>
<li>També hem donat al camp <code>number</code> un valor <code>min</code> d’1 i un valor <code>max</code> 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.</li>
</ul>
<div class="hidden">
<pre class="brush: css notranslate">input:invalid {
border: 2px dashed red;
}
input:valid {
border: 2px solid black;
}
div {
margin-bottom: 10px;
}</pre>
</div>
<p>Aquí tens l’execució en viu de l’exemple:</p>
<p>{{EmbedLiveSample("Restringir_els_valors_de_les_entrades", "100%", 100)}}</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en viu a GitHub en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/fruit-length.html">fruit-length.html</a> (o també consultar-ne el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-length.html">codi d’origen</a>.)</p>
</div>
<div class="blockIndicator note">
<p><strong>Nota</strong>: <code><input type="number"></code> (i altres tipus, com ara <code>range</code> i <code>date</code>) també poden tenir un atribut <a href="/en-US/docs/Web/HTML/Attributes/step"><code>step</code></a>, 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 <code>step</code>, de manera que el valor per defecte és <code>1</code>. Això vol dir que els números de coma flotant (com ara el 3,2) també es mostren com a no vàlids.</p>
</div>
<h3 id="Exemple_complet">Exemple complet</h3>
<p>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:</p>
<pre class="brush: html line-numbers language-html notranslate"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>form</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>fieldset</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>legend</span><span class="punctuation token">></span></span>Do you have a driver's license?<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>abbr</span> <span class="attr-name token">title</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>This field is mandatory<span class="punctuation token">"</span></span> <span class="attr-name token">aria-label</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>required<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>*<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>abbr</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>legend</span><span class="punctuation token">></span></span>
<span class="comment token"><!-- 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 --></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>radio<span class="punctuation token">"</span></span> <span class="attr-name token">required</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>driver<span class="punctuation token">"</span></span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>r1<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>yes<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>r1<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>Yes<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>radio<span class="punctuation token">"</span></span> <span class="attr-name token">required</span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>driver<span class="punctuation token">"</span></span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>r2<span class="punctuation token">"</span></span> <span class="attr-name token">value</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>no<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>r2<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>No<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>fieldset</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>n1<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>How old are you?<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="comment token"><!-- 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 --></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>number<span class="punctuation token">"</span></span> <span class="attr-name token">min</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>12<span class="punctuation token">"</span></span> <span class="attr-name token">max</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>120<span class="punctuation token">"</span></span> <span class="attr-name token">step</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>1<span class="punctuation token">"</span></span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>n1<span class="punctuation token">"</span></span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>age<span class="punctuation token">"</span></span>
<span class="attr-name token">pattern</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>\d+<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t1<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>What's your favorite fruit?<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>abbr</span> <span class="attr-name token">title</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>This field is mandatory<span class="punctuation token">"</span></span> <span class="attr-name token">aria-label</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>required<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>*<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>abbr</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>text<span class="punctuation token">"</span></span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t1<span class="punctuation token">"</span></span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>fruit<span class="punctuation token">"</span></span> <span class="attr-name token">list</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>l1<span class="punctuation token">"</span></span> <span class="attr-name token">required</span>
<span class="attr-name token">pattern</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>datalist</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>l1<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Banana<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Cherry<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Apple<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Strawberry<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Lemon<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>option</span><span class="punctuation token">></span></span>Orange<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>option</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>datalist</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t2<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>What's your e-mail address?<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>input</span> <span class="attr-name token">type</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>email<span class="punctuation token">"</span></span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t2<span class="punctuation token">"</span></span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>email<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>label</span> <span class="attr-name token">for</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t3<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>Leave a short message<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>label</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>textarea</span> <span class="attr-name token">id</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>t3<span class="punctuation token">"</span></span> <span class="attr-name token">name</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>msg<span class="punctuation token">"</span></span> <span class="attr-name token">maxlength</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>140<span class="punctuation token">"</span></span> <span class="attr-name token">rows</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>5<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>textarea</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>button</span><span class="punctuation token">></span></span>Submit<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>button</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span>
<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>form</span><span class="punctuation token">></span></span></code></pre>
<p>I ara, una mica de CSS per a aplicar estil al codi HTML:</p>
<pre class="brush: css notranslate">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;
}</pre>
<p>Això dona la sortida següent:</p>
<p>{{EmbedLiveSample("Exemple_complet", "100%", 420)}}</p>
<p>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 <a href="/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation#Validation-related_attributes">atributs relacionats amb la validació</a>.</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en viu a GitHub, en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/full-example.html">full-example.html</a> (o consultar-ne també el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/full-example.html">codi d’origen</a>).</p>
</div>
<h2 id="Validació_de_formularis_amb_JavaScript"><strong>Validació de formularis amb JavaScript</strong></h2>
<p>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ò.</p>
<h3 id="L’API_de_validació_de_restriccions">L’API de validació de restriccions</h3>
<p>La majoria dels navegadors admeten l'<a href="/en-US/docs/Web/API/Constraint_validation">API de validació de restriccions</a>, que consta d'un conjunt de mètodes i propietats disponibles en les interfícies DOM per als elements de formulari següents:</p>
<ul>
<li><code><a href="/en-US/docs/Web/API/HTMLButtonElement">HTMLButtonElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/button"><button></a></code>)</li>
<li><code><a href="/en-US/docs/Web/API/HTMLFieldSetElement">HTMLFieldSetElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/fieldset"><fieldset></a></code>)</li>
<li><code><a href="/en-US/docs/Web/API/HTMLInputElement">HTMLInputElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/input"><input></a></code>)</li>
<li><code><a href="/en-US/docs/Web/API/HTMLOutputElement">HTMLOutputElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/output"><output></a></code>)</li>
<li><code><a href="/en-US/docs/Web/API/HTMLSelectElement">HTMLSelectElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/select"><select></a></code>)</li>
<li><code><a href="/en-US/docs/Web/API/HTMLTextAreaElement">HTMLTextAreaElement</a></code> (representa un element <code><a href="/en-US/docs/Web/HTML/Element/textarea"><textarea></a></code>)</li>
</ul>
<p id="Constraint_validation_API_properties">L’API de validació de restriccions posa a la disposició dels elements anteriors les propietats següents.</p>
<ul>
<li><code>validationMessage</code>: 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 (<code>willValidate</code> és <code>false</code>) o si el valor de l’element satisfà les restriccions (és vàlid), retorna una cadena buida.</li>
<li><code>validity</code>: Retorna un objecte <code>ValidityState</code> 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 {{domxref("ValidityState")}}; a continuació se n'enumeren uns quants dels més comuns:
<ul>
<li>{{domxref("ValidityState.patternMismatch", "patternMismatch")}}: Retorna <code>true</code> si el valor no coincideix amb el {{htmlattrxref("pattern", "input")}} especificat, i <code>false</code> si hi coincideix. Si és <code>true</code>, l'element coincideix amb la pseudoclasse {{cssxref(":invalid")}} de CSS.</li>
<li>{{domxref("ValidityState.rangeOverflow", "rangeOverflow")}}: Retorna <code>true</code> si el valor és superior al màxim especificat per l’atribut {{htmlattrxref("max", "input")}}, o <code>false</code> si és inferior o igual al màxim. Si és <code>true</code>, l'element coincideix amb les pseudoclasses {{cssxref(":invalid")}} i {{cssxref(":out-of-range")}} de CSS.</li>
<li>{{domxref("ValidityState.rangeUnderflow", "rangeUnderflow")}}: Retorna <code>true</code> si el valor és inferior al mínim especificat per l’atribut {{htmlattrxref("min", "input")}}, o <code>false</code> si és superior o igual al mínim. Si és <code>true</code>, l'element coincideix amb les pseudoclasses {{cssxref(":invalid")}} i {{cssxref(":out-of-range")}} de CSS.</li>
<li>{{domxref("ValidityState.typeMismatch", "typeMismatch")}}: Retorna <code>true</code> si el valor no està en la sintaxi requerida (quan {{htmlattrxref("type", "input")}} és un correu electrònic o una url), o <code>false</code> si la sintaxi és correcta. Si és <code>true</code>, l'element coincideix amb la pseudoclasse {{cssxref(":invalid")}} de CSS.</li>
<li><code>valid</code>: Retorna <code>true</code> si l'element compleix totes les limitacions de validació i es considera que és vàlid, o <code>false</code> si falla alguna restricció. Si és <code>true</code>, l'element coincideix amb la pseudoclasse {{cssxref(":valid")}} de CSS; o amb la pseudo-classe {{cssxref(":invalid")}} de CSS en cas contrari.</li>
<li><code>valueMissing</code>: Retorna <code>true</code> si l'element té un atribut {{htmlattrxref("required", "input")}} sense cap valor, o <code>false</code> en cas contrari. Si és <code>true</code>, l'element coincideix amb la pseudoclasse {{cssxref(":invalid")}} de CSS.</li>
</ul>
</li>
<li><code>willValidate</code>: Retorna <code>true</code> si l'element es valida en enviar-se el formulari; <code>false</code> en cas contrari.</li>
</ul>
<p id="Constraint_validation_API_methods">L'API de validació de restriccions també ofereix als elements anteriors els mètodes següents:</p>
<ul>
<li><code>checkValidity()</code>: Retorna <code>true</code> si el valor de l'element no té problemes de validesa; <code>false</code> en cas contrari. Si l'element no és vàlid, aquest mètode també activa un esdeveniment no vàlid (<a href="/en-US/docs/Web/API/HTMLInputElement/invalid_event"><code>invalid</code> event</a>) sobre l'element.</li>
<li><code>setCustomValidity(<em>message</em>)</code>: 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.</li>
</ul>
<h4 id="Missatges_d’error_personalitzats"><strong>Missatges d’error personalitzats</strong></h4>
<p>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.</p>
<p>Aquests missatges automatitzats tenen dos inconvenients:</p>
<ul>
<li>No hi ha una manera estàndard de canviar-ne l’aparença amb CSS.</li>
<li>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.</li>
</ul>
<p><img alt="Exemple d’un missatge d’error a Firefox en francès en una pàgina en anglès" src="/files/4329/error-firefox-win7.png" style="height: 97px; width: 228px;"></p>
<p>La personalització d’aquests missatges d’error és un dels casos d’ús més comuns de l’<a href="/en-US/docs/Web/API/Constraint_validation" rel="external">API de validació de restriccions</a>. Vegem la manera de fer-ho amb un exemple senzill.</p>
<p>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 <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/fruit-start.html">fruit-start.html</a> com a base, si vols):</p>
<pre class="brush: html notranslate"><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></pre>
<p>I afegeix a la pàgina el JavaScript següent:</p>
<pre class="brush: js notranslate">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("");
}
});</pre>
<p>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 <code>content</code> cada vegada que es modifica el valor dins de l’entrada.</p>
<p>Dins del codi de <code>content</code>, comprovem si la propietat <code>validity.typeMismatch</code> de l’entrada de correu electrònic retorna <code>true</code>, 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 <a href="/en-US/docs/HTML/HTML5/Constraint_validation#Constraint_API's_element.setCustomValidity()"><code>setCustomValidity()</code></a> 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.</p>
<p>Si la propietat <code>validity.typeMismatch</code> retorna <code>false</code>, cridem el mètode <code>setCustomValidity()</code> amb una cadena buida. Això fa que l’entrada sigui vàlida, i el formulari s’envia.</p>
<p>Pots provar-ho a continuació:</p>
<p>{{EmbedGHLiveSample("learning-area/html/forms/form-validation/custom-error-message.html", '100%', 80)}}</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en viu a GitHub en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/custom-error-message.html">custom-error-message.html</a> (consulta’n també el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/custom-error-message.html">codi d’origen</a>).</p>
</div>
<h4 id="Un_exemple_més_detallat"><strong>Un exemple més detallat</strong></h4>
<p>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.</p>
<p>En primer lloc, el codi HTML. Un cop més, no dubtis a construir-lo amb nosaltres:</p>
<pre class="brush: html notranslate"><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></pre>
<p>Aquest formulari senzill utilitza l’atribut <code><a href="/en-US/docs/Web/HTML/Attributes/novalidate">novalidate</a></code>, 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 {{cssxref(":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.</p>
<p>La nostra entrada per validar és <code><a href="/en-US/docs/Web/HTML/Element/input/email"><input type="email"></a></code>, que està marcada com a <code>required</code> i té una longitud mínima (<code>minlength</code>) de 8 caràcters. Comprovem-ho amb el nostre codi i mostrem un missatge d'error personalitzat per a cada element.</p>
<p>El nostre objectiu és mostrar els missatges d'error dins d'un element <code><span></code>. L'atribut <a href="/en-US/docs/Accessibility/ARIA/ARIA_Live_Regions"><code>aria-live</code></a> està establert a <code><span></code> per a assegurar-nos que el missatge d'error personalitzat serà visible per a tothom, inclosos els usuaris que empren lectors de pantalla.</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Un element clau aquí és el fet que establir l’atribut <code>novalidate</code> 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.</p>
</div>
<p>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:</p>
<pre class="brush: css notranslate">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;
}</pre>
<p>A continuació veurem el JavaScript que implementa la validació d'errors personalitzada.</p>
<pre class="brush: js notranslate">// 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';
}</pre>
<p>Els comentaris expliquen les coses força bé, però de manera breu:</p>
<ul>
<li>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 <code>showError()</code> perquè es mostri l'error adequat.</li>
<li>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 <code>showError()</code> perquè es mostri l’error adequat i aturem l’enviament del formulari amb <code><a href="/en-US/docs/Web/API/Event/preventDefault">preventDefault()</a></code>.</li>
<li>La funció <code>showError()</code> utilitza diverses propietats de l'objecte <code>validity</code> de l'entrada de text per a determinar de quin error es tracta, i a continuació mostra el missatge d'error que hi correspon.</li>
</ul>
<p>Aquest és el resultat en viu:</p>
<p>{{EmbedGHLiveSample("learning-area/html/forms/form-validation/detailed-custom-validation.html", '100%', 150)}}</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Pots trobar aquest exemple en viu a GitHub en el fitxer <a href="https://mdn.github.io/learning-area/html/forms/form-validation/detailed-custom-validation.html">detailed-custom-validation.html</a> (consulta’n també el <a href="https://github.com/mdn/learning-area/blob/master/html/forms/form-validation/detailed-custom-validation.html">codi d’origen</a>).</p>
</div>
<p>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.</p>
<div class="blockIndicator note">
<p><strong>Nota</strong>: Per obtenir més informació, consulta la nostra <a href="/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation">guia de validació de restriccions</a> i la referència de l'<a href="/en-US/docs/Web/API/Constraint_validation">API de validació de restriccions</a>.</p>
</div>
<h3 id="Validació_dels_formularis_sense_una_API_integrada">Validació dels formularis sense una API integrada</h3>
<p>En alguns casos, com ara la compatibilitat amb navegadors antics o els <a href="/en-US/docs/Learn/Forms/How_to_build_custom_form_controls">controls personalitzats</a>, 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.</p>
<p>Per a validar un formulari, planteja’t unes quantes preguntes:</p>
<dl>
<dt><strong>Quin tipus de validació he de fer?</strong></dt>
<dd>Has de determinar com validar les dades: operacions amb variables de cadena, conversió de tipus, expressions regulars, etc. Tot depèn de tu.</dd>
<dt><strong>Què he de fer si el formulari no es valida?</strong></dt>
<dd>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?</dd>
<dt><strong>Com puc ajudar l’usuari a corregir dades no vàlides?</strong></dt>
<dd>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:
<ul>
<li>SmashingMagazine: <a href="http://uxdesign.smashingmagazine.com/2012/06/27/form-field-validation-errors-only-approach/" rel="external">Form-Field Validation: The Errors-Only Approach</a> [Validació dels camps d’un formulari: L’enfocament de només errors]</li>
<li>SmashingMagazine: <a href="http://www.smashingmagazine.com/2009/07/07/web-form-validation-best-practices-and-tutorials/" rel="external">Web Form Validation: Best Practices and Tutorials</a> [Validació de formularis web: Bones pràctiques i tutorials]</li>
<li>Six Revision: <a href="http://sixrevisions.com/user-interface/best-practices-for-hints-and-validation-in-web-forms/" rel="external">Best Practices for Hints and Validation in Web Forms</a> [Bones pràctiques per a suggeriments i validació de formularis web]</li>
<li>A List Apart: <a href="http://www.alistapart.com/articles/inline-validation-in-web-forms/" rel="external">Inline Validation in Web Forms</a>[Validació en línia de formularis web]</li>
</ul>
<strong> </strong></dd>
</dl>
<h4 id="Un_exemple_que_no_utilitza_lAPI_de_validació_de_restriccions"><strong>Un exemple que no utilitza l'API de validació de restriccions</strong></h4>
<p>A continuació es mostra una versió simplificada de l'exemple anterior que funciona amb navegadors antics.</p>
<p>L’HTML és gairebé el mateix; només n’hem tret les funcions de validació HTML.</p>
<pre class="brush: html notranslate"><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></pre>
<p>De la mateixa manera, el CSS no ha de canviar gaire; acabem de convertir la pseudoclasse {{cssxref(":invalid")}} de CSS en una classe real i hem evitat utilitzar el selector d'atributs que no funciona en Internet Explorer 6.</p>
<pre class="brush: css notranslate">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;
}</pre>
<p>Els grans canvis es produeixen en el codi JavaScript, que ha de fer molta més feina feixuga.</p>
<pre class="brush: js notranslate">// 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";
}
});</pre>
<p>El resultat és el següent:</p>
<p>{{EmbedLiveSample("Un_exemple_que_no_utilitza_lAPI_de_validació_de_restriccions", "100%", 130)}}</p>
<p>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 <a href="http://rickharrison.github.com/validate.js/" rel="external">Validate.js</a>.</p>
<h2 id="Resum">Resum</h2>
<p>De vegades, la validació de formulari del costat del client necessita JavaScript si vols personalitzar els missatges d’estil i d’error, però <em>sempre</em> 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:</p>
<ul>
<li>Mostrar missatges d’error explícits.</li>
<li>Ser permissiu amb els formats d’entrada.</li>
<li>Assenyalar exactament on es produeix l’error, sobretot en els formularis grans.</li>
</ul>
<p>Un cop comprovat que el formulari s'ha emplenat correctament, pots procedir a enviar-lo. A continuació exposarem l’<a href="/en-US/docs/Learn/Forms/Sending_and_retrieving_form_data">enviament de les dades d’un formulari</a>.</p>
<p>{{PreviousMenuNext("Learn/Forms/UI_pseudo-classes", "Learn/Forms/Sending_and_retrieving_form_data", "Learn/HTML/Forms")}}</p>
<h2 id="En_aquest_mòdul"><strong>En aquest mòdul</strong></h2>
<ul>
<li><a href="/en-US/docs/Learn/Forms/Your_first_form">Els teu primer formulari</a></li>
<li><a href="/en-US/docs/Learn/Forms/How_to_structure_a_web_form">Com estructurar un formulari web</a></li>
<li><a href="/en-US/docs/Learn/Forms/Basic_native_form_controls">Els controls de formulari bàsics originaris</a></li>
<li><a href="/en-US/docs/Learn/Forms/HTML5_input_types">Els tipus d'entrada de l’HTML5</a></li>
<li><a href="/en-US/docs/Learn/Forms/Other_form_controls">Altres controls de formulari</a></li>
<li><a href="/en-US/docs/Learn/Forms/Styling_web_forms">Aplicar estil a formularis web</a></li>
<li><a href="/en-US/docs/Learn/Forms/Advanced_form_styling">Aplicació avançada d’estil a formularis</a></li>
<li><a href="/en-US/docs/Learn/Forms/UI_pseudo-classes">Pseudoclasses d’interfície d’usuari (UI)</a></li>
<li><a href="/en-US/docs/Learn/Forms/Form_validation">Validació del formulari de la banda del client</a></li>
<li><a href="/en-US/docs/Learn/Forms/Sending_and_retrieving_form_data">Enviar les dades d’un formulari</a></li>
</ul>
<h3 id="Temes_avançats">Temes avançats</h3>
<ul>
<li><a href="/en-US/docs/Learn/Forms/How_to_build_custom_form_controls">Com crear controls de formulari adaptats a client</a></li>
<li><a href="/en-US/docs/Learn/Forms/Sending_forms_through_JavaScript">Enviar formularis amb JavaScript</a></li>
<li><a href="/en-US/docs/Learn/Forms/Property_compatibility_table_for_form_widgets">Taula de compatibilitat de controls de formulari de codi propietari</a></li>
</ul>
|