Okej, tema za mart mesec na blogu je JavaScript. Dosta sam se bacio na taj scripting jezik u poslednjih 20-ak dana, te sam rešio da svoju preokupaciju podelim sa svima. Našao sam jednu sjajno napisanu skriptu u knjizi „JavaScript and Ajax for the Web“ (strana 167) čiji su autori Tom Negrino i Dori Smith, pa ću ovde, na srpskom, objasniti šta ona ustvari radi, tako da će svima koji ne znaju JavaScript ovo dobro doći da neke stvari shvate. Ukoliko dobro poznajete ovu materiju, preporučujem da ipak pogledate o čemu se radi s obzirom da vam ovo može poslužiti kao dobar framework za dalji rad, ili čak kao gotovo rešenje spremno za implementaciju.
S obzirom da su Web 2.0 aplikacije uveliko standard, samim tim je i veća interakcija između korisnika i i web sajta. Forme su klasičan primer za prethodno rečeno. Ono o čemu ću ja danas pisati je verifikacija forme, odnosno, pokazaću kako možete proveriti da li je korisnik popunio sva polja iz forme i da li je to učinio pravilno. Postoje dva načina na koje možemo uraditi ovo:
1) da prosledimo unete podatke do web servera, tu ih obradimo, proverimo i nakon toga, ukoliko postoji greška, obavestimo korisnika. To možemo uraditi u nekom server-side jeziku (na primer, PHP).
2) da proveru uradimo direktno u korisničkom brauzeru, bez ikakvog kontakta sa web server-om koristeći JavaScript. Uslov je, naravno, da korisnik ima uključen JavaScript u svom brauzeru, što 99% korisnika ima.
Drugi način je daleko bolji jer se sve dešava na korisničkoj mašini, pa je samim tim i brži – vreme se ne gubi u slanju podataka do servera i čekanju da se isti obrade. Iz ovoga sledi i to da je naš server oslobođen od tog posla, pa će brže reagovati na zahteve nekih drugih korisnika.
Gotovo rešenje pogledajte odmah, a onda ću komentarisati deo po deo.
HTML - ništa specijalno, ne bih zalazio u analizu jer je akcenat pre svega u JavaScript kodu.
<html> <head> <title>Car Picker</title> <script type="text/javascript" src="script.js"></script> <link rel="stylesheet" href="script.css" /> </head> <body> <h2 align="center">Car Picker</h2> <form action="#"> <p> <label for="emailAddr">Enter your email address: <input id="emailAddr" type="text" size="30" /> </label></br /> <label for="emailAddr2">Re-enter your email address:<input id="emailAddr2" type="text" size="30" /> </label> </p> <p><label for="color">Colors: <select id="color"> <option value="" selected="selected">Choose a color</option> <option value="Red">Red</option> <option value="Green">Green</option> <option value="Blue">Blue</option> </select> </label></p> <p>Options: <label for="sunroof"><input type="checkbox" id="sunroof" value="Yes" />Sunroof (Two door only)</label> <label for="pWindows"><input type="checkbox" id="pWindows" value="Yes" />Power Windows</label> </p> <p><label for="DoorCt">Doors: <input type="radio" id="twoDoor" name="DoorCt" value="twoDoor" />Two <input type="radio" id="fourDoor" name="DoorCt" value="fourDoor" />Four </label></p> <p><input type="submit" value="Submit" /> <input type="reset" /></p> </form> </body> </html>
JavaScript
window.onload = initForms;
function initForms() {
for (var i=0; i< document.forms.length; i++) {
document.forms[i].onsubmit = function() {return validForm();}
}
}
function validForm() {
var allGood = true;
var allTags = document.getElementsByTagName("*");
for (var i=0; i<allTags.length; i++) {
if (!validTag(allTags[i])) {
allGood = false;
}
}
return allGood;
function validTag(thisTag) {
var outClass = "";
var allClasses = thisTag.className.split(" ");
for (var j=0; j<allClasses.length; j++) {
outClass += validBasedOnClass(allClasses[j]) + " ";
}
thisTag.className = outClass;
function validBasedOnClass(thisClass) {
var classBack = "";
switch(thisClass) {
case "":
case "invalid":
break;
case "reqd":
if (allGood && thisTag.value == "") {
classBack = "invalid ";
}
classBack += thisClass;
break;
default:
classBack += thisClass;
}
return classBack;
}
}
}
KORAK 1: Analiza intForm() funkcije.
function initForms() {
for (var i=0; i< document.forms.length; i++) {
document.forms[i].onsubmit = function() {return validForm();}
}
}
Proveravamo sve forme koje imamo na strani koristeci for loop. Uvodimo promenljivu i, i dok je ona manja od broja formi na strani (document.forms se odnosi na sve form objekte na strani, dok je ovo .length ustvari njihov ukupan broj), pozivamo funkciju koja nema deklarisano ime, već samo vraća vrednost funkcije validForm() ukoliko je korisnik kliknuo na form submit. Drugim rečima: Zamislite da je korisnik kliknuo na neku našu formu Tada JavaScript preko onsubmit handler-era poziva funkciju koja vraća vrednost funkcije validForm(). Funkcija validForm() može imati samo dve vrednosti: true ili false! U sledecem bloku koda videćemo šta zapravo validForm() radi.
KORAK 2: Analiza validForm() i validTag() funkcija.
function validForm() {
var allGood = true;
var allTags = document.getElementsByTagName("*");
for (var i=0; i<allTags.length; i++) {
if (!validTag(allTags[i])) {
allGood = false;
}
}
return allGood;
Unutar funkcije validForm() imamo promenljive allGood koja je po default-u true, i allTags kojoj dodeljujemo vrednost svih html elemenata na strani. Da smo napisali document.getElementsByTagName(„p“), onda bi se allTags promenljiva odnosila iskljucivo na paragrafe. Mogli smo da stavimo kao parametar bilo koji element. U ovom slučaju, nas interesuju svi elementi, pa nam je zato parametar („*“), jer * = all!
Opet, for loop-om prolazimo kroz sve elemente na stranici i ubacujemo ih kao parametar u funkciju validTag(). validTag() će biti objašnjena u sledećim pasusima – za sada nam je bitno da njena vrednost moze biti samo true ili false. Ukoliko je njena vrednost false, tj, ukoliko (!validTag(allTags[i])), onda ce i nasa promenljiva allGods biti false, pa ce i sama funkcija validForm() biti false jer ta funkcija vraća vrednost promenljive allGood (return allGood;).
function validTag(thisTag) {
var outClass = "";
var allClasses = thisTag.className.split(" ");
for (var j=0; j<allClasses.length; j++) {
outClass += validBasedOnClass(allClasses[j]) + " ";
}
thisTag.className = outClass;
validTag() prima parametar allTags[i] iz prethodne funkcije validForm(). Vrednost tog parametra obeležavamo promenljivom thisTag. Da bih malo približio ovo onima koji ne shvataju ovo, pokušaću da kažem i ovako: Rekli smo da f-ja validForm() pretražuje sve elemente na strani. Zamislite da je došla do nekog p taga (dakle paragraf). Ona prosleđuje p tag do f-je validTag(), pa je u tom slučaju thisTag ustvari p. Onda ta funkcija dobije, na primer, tag a kao parametar. U tom slučaju, thisTag ce biti a. I tako dalje, sve do poslednjeg elementa na strani.
Prokomentarišimo sada šta se sve dešava unutar funkcije validTag(). Deklarišemo nove promenljive: outClass koja je po defaultu prazan string i drugu promenljivu – allClasses, koja iz taga koji je trenutno ubačen u funkciju (kao sto smo malopre rekli, to moze biti bilo koji tag) čita njegovu klasu, i ukoliko parametar ima više klasa, onda ih razdvaja (className.split(“ „);) i smesta u niz. Pokažimo to na praktičnom primeru:
<label for="emailAddr2">Re-enter your email address:<input id="emailAddr2" type="text" size="30" />
Vidite kako naša labela ima dve klase: reqd i emailAddr. U tom slučaju će className.split(“ „); uraditi sledeće: Napraviće niz i smestiti oba stringa (tj, imena obe klase, koja su u našem primeru reqd i emailAddr) u taj niz. Zatim, novim for loop-om „pretresti taj niz“, uzeti svaki njegov clan i ubacivati kao parametar u našu novu funkciju validBasedOnClass(allClasses[j]). Ta funkcija će uraditi proveru da li je clan tog niza (odnosno klasa) „invalid“. Više reči o tome će biti u narednim pasusima.
Za sada nam je bitno da će na kraju ovog našeg for loop-a vrednost promenljive outClass (za primer prethodne labele) biti „reqd emailAddr“.
KORAK 4: Provera da li imamo „invalid“ klasu:
if (outClass.indexOf("invalid") > -1) {
thisTag.focus();
if (thisTag.nodeName == "INPUT") {
thisTag.select();
}
return false;
}
return true;
Proveravamo dalje da li ta klasa ( u slučaju sa našom labelom „reqd emailAddr“) u sebi sadrži reč „invalid„, tj, da li string invalid deo (indexOf) outClass-e. Ukoliko jeste, onda cemo taj html tag (labelu), staviti u fokus, kako bismo ispitali da li je nodeName ustvari input tag. Drugim rečima – ukoliko nađemo bar jednu klasu invalid, funkciji vracamo vrednost false, a samim tim ona nece biti procesirana do web servera, vec ce korisniku odmah vratiti adekvatnu gresku. Ukoliko string „invalid“ nije pronađen, onda je sve u redu (korisnik je pravilno popunio formu), f-ja će vratiti vrednost true, pa će podaci iz forme biti prosleđeni Web serveru.
KORAK 3: Analiza funkcije validBasedOnClass(thisClass)
function validBasedOnClass(thisClass) {
var classBack = "";
switch(thisClass) {
case "":
case "invalid":
break;
case "reqd":
if (allGood && thisTag.value == "") {
classBack = "invalid ";
}
classBack += thisClass;
break;
default:
classBack += thisClass;
}
return classBack;
}
Prokomentarišimo sada funkciju validBasedOnClass(thisClass). Deklarisali smo promenljivu classBack.
Primecujemo da paramatar koji dolazi u funkciju može imati različite vrednosti. On može biti prazan, može biti „invalid“, „reqd“, itd. Za takve situacije je najbolje koristiti switch, koji je nalik if-u. Postoje, dakle, više različitih slučajeva (case). Za slučaj da je parametar koji je dospeo u funkciju prazan string ili „invalid“, odmah izlazimo iz switch-a komandom break. Break bukvalno kaže switch-u: „okej, gotovi smo sa ispitivanjem, to je taj slučaj koji tražim, ne proveravaj ostale mogućnosti.“
Ono sto nas najviše interesuje je slučaj ukoliko je parametar=“reqd“. To znači da je polje sa tom klasom obavezno (korisnik mora da ga popuni ukoliko želi da mu forma bude prosledjena do servera). Ukoliko on ipak nije uneo nista u required polje, tj, vrednost tog polja je prazan string (thisTag.value == „“), vrednost naše promenljive classBack ćemo PROMENITI POMOĆU JAVASCRIPT-a na INVALID. Ovo je ključna tačka jer se odmah zatim desavaju sledece stvari:
- Funkcija validBasedOnClass(thisClass) će vratiti vrednost invalid
- Onda ta vrednost odlazi do 4. KORAKA, gde u proveri tražimo upravo tu reč. Ukoliko je nađemo, naša forma neće biti procesirana jer će funkcija validTag() vratiti false, samim tim će i promenljiva allGood (deklarisana u validForm()) biti false, a što dalje implicira da naša forma NIJE VALIDNA!
To bi bilo sve za ovaj prvi deo. Drugi deo ću objaviti početkom aprila. Ostalo je još dosta posla koji treba da se završi kako bi ova skripta zaista bila dobra i sasvim funkcionalna.


