Inputkontroll
En fornuftig bruk av JavaScript er kontroll eller validering av det brukeren skriver inn i inputfelter (text, textarea) før det sendes til tjeneren. Typiske kontroller kan være:
- Kontroll av om et felt er utfylt. Dette er som regel greitt å finne ut av.
- Kontroll av om et felt har riktig syntaks. Bare siffere, bare bokstaver, riktig antall siffere eller bokstaver. Dette skaper heller ikke store problemer.
- Riktig format i henhold til en mer presis syntaksbeskrivelse, f.eks. en dato. Dette kan være mer komplisert men bruk av regulære utttrykk kan hjelpe oss langt på vei. Javascript støtter dette.(mer om dette nedenfor)
- At feltene er fornuftige i forhold til hverande. Dette kan være enkelt, men det kan også bli kanske komplisert og tungvindt å løse i JavaScript.
- At dataene er lovlige gitt en bestemt situasjon. Dette avhenger helt av situasjonen. "lovlig" i denne sammenheng kan bety så mangt. F.eks. Kan det være greitt å teste om en dato har rett format, men det kan hende vi må konsultere en database eller en annen datakilde for å sjekke om den angitte datoen i f.eks. en bestillingssituasjon er ledig eller effektiv.
Det er trolig en god leveregel å finne en fornuftig balanse mellom det som med rimelighet kan skrives i JavaScript på klienten og det som med fordel kan løses på tjeneren. Vi kan kanskje si at det er rinmelig å foreta syntakskontroller på klienten og logiske kontroller på tjeneren.
Vi må også tenke gjennom hvordan og når vi skal gi tilbakemelding til brukeren om at noe er galt eller mangelfullt. Begivenhetsstyrt DOM-programmering er nøkkelen til dette.
.Et enkelt eksempel
Vi begynner med et enkelt eksempel som ikke stiller store krav til selve kontrollen, valideringen. Hensikten er å se litt på organisering og rekkefølge. Vi tar for oss en situasjon der brukeren inviteres til å angi en 4-siffret tallkode og en tekst med 3 bokstaver.
Strategien er at vi skriver og kaller tre funksjoner slik:
- controlnumber(). Denne kalles når sifferfeltet mister fokus, begivenheten onblur. Denne setter opp en feilmelding og returnerer false dersom noe er galt i sifferfeltet, ellers true.
- controlalfa(). Denne kalles når bokstavfeltet mister fokus, begivenheten onblur. Denne setter opp en feilmelding og returnerer false dersom noe er galt i bokstavfeltet, ellers true.
- controlboth(). Denne kalles når vi trykker på Registrer-knappen, begivenheten onsubmit, og kaller de to andre funksjonene. Denne returnerer false dersom en av de to andre returnerer false, ellers true.
function controlnumber() { inputelt=document.getElementById('number'); errorelt=document.getElementById('numbererror'); if ((inputelt.value==null) || (inputelt.value.length!=4)) { errorelt.innerHTML='4 siffere'; return false; } var legals = "0123456789"; var T=inputelt.value; for (i = 0; i != T.length; i++) if (legals.indexOf(T.charAt(i)) == -1) { errorelt.innerHTML='bare siffere'; return false; } errorelt.innerHTML=''; return true; } function controlalfa() { inputelt=document.getElementById('alfa'); errorelt=document.getElementById('alfaerror'); if ((inputelt.value==null) || (inputelt.value.length!=3)) { errorelt.innerHTML='3 bokstaver'; return false; } var legals = "abcdefghijklmopqrstuvwxyzæøå"; var T=inputelt.value; T=T.toLowerCase() for (i = 0; i != T.length; i++) if (legals.indexOf(T.charAt(i)) == -1) { errorelt.innerHTML='bare bokstaver'; return false; } errorelt.innerHTML=''; return true; } function controlboth(){ if (!controlalfa()) return false; if (!controlnumber()) return false; return true; }
Den aktuelle HTML-koden er som nedenfor. Det kan virke litt overdrevet med table, men hensikten er å ordne de tre komponentene inledningstekst, selve inputfeltet og feilmeldingen.
<fieldset>
<legend>Registrer dine data</legend>
<form onsubmit="javascript:return controlboth();"
action="http://www.ia.hiof.no/~borres/cgi-bin/forms/scriptvalidate1.py"
method="post">
<table cellpadding="5px" cellspacing="0px" border="0px">
<tr>
<td>Tall:(4 siffer)</td>
<td><input id="number" name="siffere" onblur="controlnumber()"
type="text" value="" maxlength="4" size="10"/></td>
<td id="numbererror" style="color:red"></td>
</tr>
<tr>
<td>Tekst:(3 bokstaver)</td>
<td><input id="alfa" name="bokstaver" onblur="controlalfa()"
type="text" value="" maxlength="3" size="10"/></td>
<td id="alfaerror" style="color:red"></td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="Registrer"/></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
Merk onsubmit i form-elementet. Dersom controlboth() returnerer false dreper vi submitforsøket.
.Et eksempel til
Vi lager et eksempel til der vi bruker regulæruttrykk for å validere input.
Den aktuelle JavaScript-funksjonen ser slik ut:
function controldato() { inputelt=document.getElementById('dato'); errorelt=document.getElementById('datoerror'); if ((inputelt.value==null) || (inputelt.value.length!=10)) { errorelt.innerHTML='galt format'; return false; } var T=inputelt.value; var regex=/(19|20)\d\d[:](0[1-9]|1[012])[:](0[1-9]|[12][0-9]|3[01])/; if (regex.test(T)) { errorelt.innerHTML=''; return true; } errorelt.innerHTML='galt format'; return false; }
Vi ser at vi har brukt regulære uttrykk, regex-objektet, til å teste formatet. Vi kunne gjort dette med ren string-programmering (split, lengde kontroll osv), men den løsningen som er valgt er vesentlig smidigere.
Den aktuelle HTML-koden er etter mønster av forrige eksempel slik:
<fieldset>
<legend>Registrer dato</legend>
<form onsubmit="javascript:return controldato();"
action="http://www.ia.hiof.no/~borres/cgi-bin/forms/scriptvalidate2.py"
method="post">
<table cellpadding="5px" cellspacing="0px" border="0px">
<tr>
<td>Dato:(åååå:mm:dd)</td>
<td><input id="dato" name="dato" onblur="controldato()"
type="text" value="" maxlength="10" size="11"/></td>
<td id="datoerror" style="color:red"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Registrer"/></td>
<td></td>
</tr>
</table>
</form>
</fieldset>
Nå har vi laget en ren syntakskontroll av datoformatet.
var regex=/(19|20)\d\d[:](0[1-9]|1[012])[:](0[1-9]|[12][0-9]|3[01])/;
Løsningen har noen svakheter. F.eks. vil 2006:02:31 passere syntakskontrollen selv om det er en dato som ikke finnes. På den annen side vil 1889:02:01 feile siden regulæruttrykket vårt bare aksepterer datoer på 1900 og 2000 tallet.
La oss anta at vi bare er intresserte i datoer på 1900 og 2000 tallet.
Det andre problemet, altså å fange opp problemer av typen 2001:02:31, kan vi løse på flere måter. Vi kan utvide regex-uttrykket og fange det opp der eller vi kan skrive string-kode. Vi prøver det siste, og lage følgende funksjoner:
function controldatox() { inputelt=document.getElementById('datox'); errorelt=document.getElementById('datoerrorx'); if ((inputelt.value==null) || (inputelt.value.length!=10)) { errorelt.innerHTML='galt format'; return false; } var T=inputelt.value; var regex=/(19|20)\d\d[:]\d\d[:]\d\d/; if (regex.test(T)) { if(checkdato(T)) { errorelt.innerHTML=''; return true; } else { errorelt.innerHTML='datoen eksisterer ikke'; return false; } } errorelt.innerHTML='galt format eller galt årstall'; return false; } function checkdato(s){ var strArray=s.split(":"); y=parseInt(strArray[0]); m=parseInt(strArray[1]); d=parseInt(strArray[2]); if ((m==1)||(m==3)||(m==5)||(m==7)||(m==8)||(m==10)||(m== 12)) { return (d <= 31); } else if ((m==4)||(m==6)||(m==9)||(m==11)) { return (d <= 30); } else if (m == 2) { if (d <= 28) return true; if (d > 29) return false; // d==29 if ((y % 4 == 0) && (y % 100 != 0)) return true; return false; } else return false }
Test denne: