SERVIS<>
102007<><>

Mala škola AJAX-a (3)

Strana koju vole i ljudi i roboti

Kada je izgled stranice naše aplikacije u pitanju, pred nas se postavljaju zahtevi poput onoga da stranica treba da bude što jednostavnija za kreiranje i održavanje, kao i da roboti pretraživača mogu da izvuku iz naše stranice što više informacija koje će pomoći njenom dobrom rangiranju u rezultatima pretrage. Kada govorimo o tehnici prikaza stranica AJAX aplikacija, postoji više pristupa – od onih kod kojih se JavaScript koristi za ispisivanje celokupne stranice, do pristupa kod kojeg se što je više moguće elemenata definiše u čistom HTML-u. Koji je od ova dva načina bolji zavisi od konkretnog slučaja, ali svakako treba težiti ovom drugom kad god je to moguće.

Dakle, naš pristup će se sastojati u tome da stranicu koja će se prikazati kod inicijalnog učitavanja u potpunosti definišemo u HTML-u, dok će sva dinamika stranice biti definisana u JavaScript fajlovima koji će se učitavati zajedno sa stranicom. Ovim postižemo razdvajanje vizuelnog dela naše aplikacije od programskog dela, čime se olakšava održavanje i jednog i drugog dela – dizajn stranice može se menjati nezavisno od funkcionalnosti i obrnuto. Takođe, iako su pretraživači prilično napredovali u tumačenju stranica koje se dinamički generišu, ipak ćemo im za početak prikazati čist HTML za koji znamo da ga tumače više nego dobro, izbegavajući rizik da naša stranica bude nepravilno indeksirana ili čak da uopšte ne bude indeksirana. Po inicijalnom učitavanju startovaće se JavaScript kôd koji će popuniti preostale delove stranice i u pozadini izvršiti učitavanje delova koji nisu odmah vidljivi. Ukoliko roboti pretraživača uspeju da protumače i ovaj deo prikaza, tim bolje, a ukoliko ne, ipak će imati dovoljno materijala da pristojno indeksiraju stranicu.

Sledeći primer pokazaće kako se vrši asinhrono učitavanje teksta, HTML-a i XML-a a potom njihovo naknadno prikazivanje na stranici, kao i kako se parametri iz naše aplikacije prenose na server. Objasnimo najpre šta želimo da postignemo korišćenjem asinhronih zahteva.

Zamislimo AJAX aplikaciju koja za svoj rad zahteva veliki broj formi, a poseduje jednostavan help sistem baziran na čistom tekstu. Ukoliko bismo sve forme koje stranica koristi učitavali odmah, to bi moglo da poveća veličinu stranice i uspori učitavanje. Isto važi i za tekst. Ako bismo iscrtavanje formi radili pomoću JavaScripta, kôd koji ih iscrtava bio bi nepotrebno veliki, što opet vodi produženom vremenu učitavanja strane. Ono što želimo da postignemo jeste da se prvo učitavanje stranice, ono koje je za korisnika najvidljivije, odigra što brže – a to jednostavno zahteva što manje stranice. Pošto se naša inicijalna stranica učita za tren oka, korisnika smo namirili na neki trenutak, dok ne počne da bira opcije koje ona nudi. Zato odmah po učitavanju statičkog dela stranice nastavljamo sa radom i korišćenjem asinhronih zahteva učitavamo ostale delove stranice koje bi korisnik mogao da zahteva. Time smo uvek korak ispred korisnika i spremni smo da brzo odgovorimo na njegove zahteve, što našu stranicu čini prijatnom za rad.

Slika 3: Stranica iz primera, neposredno po učitavanju
U našem primeru operišemo jednostavnom stranicom koja je prikazana na slici 3. Vidi se da ta stranica, inicijalno, ima sve elemente koji kod korisnika ostavljaju utisak da je učitavanje kompletirano. Međutim, delovi stranice koji bi trebalo da se prikažu kada kliknemo na elemente za navigaciju s leve strane nisu učitani, već se njihovo učitavanje pokreće odmah po učitavanju inicijalne stranice. Pogledajmo prvo kôd stranice.

async-1.html

Iz primera se vidi da naša osnovna stranica ima jednostavnu strukturu – na njoj je prikazana tabela koja definiše raspored osnovnih elemenata stranice: dela sa uvodnim tekstom, dela za navigaciju sa opcijama koje su kreirane korišćenjem paragrafa (HTML tag P) i na kraju glavnog dela koji će se menjati zavisno od izabrane opcije a koji inicijalno sadrži opisni tekst. Treba primetiti da su za sve elemente stranice kojima ćemo na neki način pristupati definisani jedinstveni ID-jevi. Takođe, u head tagu stranice koristili smo dva metataga: prvi definiše jezik na kojem je stranica i koriste ga pretraživači a drugi definiše način kodiranja stranice – korišćen je UTF-8 kako bi naša slova bila pravilno prikazana. Napomenimo da editor u kojem kreirate fajlove (mi smo koristili Eclipse) mora biti u stanju da fajlove snimi u UTF-8 formatu.

Prethodno smo već govorili o tome da je poželjno razdvojiti izgled stranice od njene funkcionalnosti – izdvajanje CSS definicija u poseban fajl jedan je korak u tom pravcu. CSS je skraćenica od Cascading Style Sheets, što je poseban jezik koji definiše pravila koja opisuju na koji način browser prikazuje pojedine elemente stranice. CSS definicije pravila mogu biti uključene direktno u stranicu, u okviru taga head, na sličan način kao kod JavaScript koda, ali mogu biti izdvojene i u posebne fajlove sa ekstenzijom css kao što je to slučaj u našem primeru. Ukoliko se ubacuju direktno u stranicu, css definicije se smeštaju između otvarajućeg taga </style type=”text/css”> i zatvarajućeg </style>. Opšti oblik CSS pravila je sledeći:

ime_stila selektor {

osobina_1:vrednost_1;

...

osobina_n:vrednost_n;

}

Pomoću selektora se izdvaja element na koji se pravilo odnosi i on se sastoji iz dva dela – selektora tipa i selektora klase, u formatu selektorTipa.selektorKlase. Ako kao selektor stavimo td, to je selektor tipa i pravilo se odnosi samo na ćelije tabele, ali može se staviti i nešto kao td.novaKlasa, gde će se ovo pravilo primeniti samo na ćelijama za koje je eksplicitno definisano da su date klase. Deo unutar vitičastih zagrada zove se deklaracija i ima format dat u gornjem primeru. U deklaraciji se definišu sve pojedinosti izgleda elemenata kao što su na primer boja, veličina, font, margine, padding, borderi i još mnogo toga. CSS fajl u kome su definisani naši stilovi naveden je u sekciji head stranice korišćenjem taga link. Na samoj stranici, stilovi su ubacivani u definicije elemenata koji se prikazuju na stranici korišćenjem osobine class (eng. property) kao u sledećem primeru:

<p class=”navigation” id=”id_text”>

Ono što može dati izuzetne efekte jeste dinamičko menjanje pojedinih CSS karakteristika elemenata na stranici. Prva stvar koju možemo da primenimo jeste da pomoću skripta promenimo klasu nekog elementa na stranici, što trenutno proizvodi vizuelni efekat. Za tag iz prethodnog primera to bi izgledalo ovako:

document.getElementById(”id_text”).className=”neka_druga_klasa”;

Ukoliko pak želimo da menjamo samo pojedinačne osobine elementa, to u opštem slučaju radimo na sledeći način:

document.getElementById("id_text").style.imeOsobine="nova_vrednost";

U ovom slučaju imeOsobine se odnosi na polje koje definiše određenu CSS osobinu elementa: color, border, margin, padding, fontSize i slično.

Pogledajmo sada sadržaj našeg CSS fajla:

async-1.css

Vidimo da su u CSS fajlu definisane samo dve klase – navigation i ourtable. Činjenica da ispred selektora klasa nisu definisani selektori tipa omogućava nam da klase primenimo na proizvoljne elemente na stranici. Pošto CSS nije tema ovog dodatka, napomenućemo samo jedan koristan trik koji smo upotrebili u klasi navigation: osobinu cursor koju smo postavili na vrednost pointer. Efekat koji se ovim postiže je da se pokazivač miša pretvori u pointer (oblik kursora koji se inače pojavljuje iznad linkova) kada je iznad opcija za navigaciju, čime opcije za navigaciju stavljaju korisniku do znanja da se na njih može kliknuti.

Vratimo se sada našoj glavnoj stranici. Vidimo da su u definiciji taga body definisani događaj onLoad i funkcija koja je zadužena za njegovu obradu – initPage. Ova funkcija se nalazi, kao i ostatak kôda koji pokreće naš primer, u fajlu AsyncExample.js. Pored ovog JavaScript fajla, koriste se i funkcije iz fajlova utility.js i Async.js koje smo prethodno definisali.

AsyncExample.js

Funkcija initPage, koja se poziva po učitavanju stranice, krajnje je jednostavna – ona pravi tri instance klase AsyncClass. Klase se u JavaScriptu mogu definisati na različite načine, a prikazani način je samo jedan od njih. Ideja koja stoji iza klase AsyncClass je da se enkapsuliraju sve funkcije i promenljive potrebne za funkcionisanje opcija iz našeg primera. Pogledajmo šta je to zajedničko za opcije iz našeg menija zbog čega se svaka od njih može predstaviti istom klasom. Kao prvo, sadržaj koji treba prikazati kada se izabere neka od opcija se asinhrono učitava, dakle nije prisutan na strani niti definisan u skriptu, pa treba obezbediti njegovo učitavanje i prikaz. Dalje, početna stranica je definisana tako da su opcije ništa drugo do tekst u paragrafu – dakle, treba im definisati ponašanje na akcije korisnika – konkretno na klik. Na kraju, u slučaju da korisnik izabere opciju dok sadržaj još nije učitan, poželjno je prikazati prigodnu poruku o tome da je učitavanje u toku.

Konstruktor klase prima tri parametra: ime stranice koju treba učitati, tip sadržaja koji od stranice dobijamo i identifikator opcije u meniju kojoj se sadržaj pridružuje. Iz definicije klase može se videti da se prilikom kreiranja objekta poziva funkcija init koja asinhrono učitava zadatu stranicu, kreira poruku o tome da je učitavanje u toku i dodeljuje funkciju za obradu klika zadatom paragrafu. Dakle, u funkciji init prvi put vidimo primenu funkcije startAsync koju smo ranije definisali – parametar koji nam je trenutno važan je call-back funkcija loadingComplete koja se poziva kada je učitavanje (ili tačnije neka od njegovih faza) gotovo. Kao parametar funkciji loadingComplete prosleđuje se objekat XMLHTTPRequest na osnovu kojeg se korišćenjem funkcije asyncComplete određuje da li je asinhroni zahtev kompletiran ili je u međufazi. U trenutku kada je zahtev kompletiran, izvršava se deo kôda funkcije loadingComplete koji na osnovu tipa očekivanog sadržaja sa servera priprema učitani sadržaj za ubacivanje u stranicu. Klasa AsyncClass sadrži promenljivu content u kojoj se čuva sadržaj koji treba prikazati na stranici. U našem primeru, kada od servera dobijemo tekst, promenljiva content je običan text nod, a u slučaju HTML-a, content je DIV tag u koji je kao innerHTML ubačen odgovor servera. U slučaju XML-a situacija je malo složenija pošto je za izdvajanje korisnog sadržaja iz XML-a potrebno izvršiti parsiranje dobijenog sadržaja, pa za ovu svrhu koristimo funkciju parseXML. Da bismo bili u stanju da bolje razumememo način parsiranja XML-a, pogledajmo najpre jednostavnu PHP funkciju koja je zadužena za njegovo generisanje.

async-xml.php

Prvo što treba zapaziti u našem PHP kôdu jeste funkcija header koja browseru kojem je strana poslata opisuje tip sadržaja stranice. Ukoliko bismo ovu liniju izostavili, browser ne bi shvatio dobijeni sadržaj kao XML, pa onda ne bismo bili u stanju da ga parsiramo pomoću našeg JavaScripta. Takođe, bitna stvar za funkciju header jeste da bude pozvana pre bilo kakvog drugug ispisa na stranicu. Zaključak: postarajte se da ispred otvarajućeg PHP taga nemate ni jedan jedini razmak!

Slika 4: Obrađeni i neobrađeni XML sadržaj 
Što se samog XML sadržaja tiče, definicija verzije XML-a i korišćenog kodnog rasporeda data je u prvoj liniji. Ostatak XML sadržaja nalazi se u tagu primer. Naš PHP kôd simulira slanje podataka o četvorici zaposlenih neke firme gde se za svakog šalju ime i prezime (tag ime), godine staža (tag staz) i broj iskorišćenih dana odmora (tag odmor). PHP kôd je jednostavan, podatke koje šalje u XML formatu čita iz niza konstanti i nema potrebe dodatno ga objašnjavati. Na slici 4 može se videti kako naša AJAX aplikacija prikazuje obrađeni XML sadržaj, a odmah ispod i kako izgleda neobrađeni XML gledan u Firebug JavaScript debuggeru. Firebug je izuzetno koristan za praćenje asinhronog saobraćaja AJAX aplikacija; pomoću njega možete videti sadržaje svih upita i odgovora, proučiti sadržaje headera i proučavati vremena potrebna da se pojedini asinhroni zahtevi kompletiraju. Pored XML zahteva koji se u potpunosti vidi na slici, primetite da su u Firebugu prisutna i druga dva zahteva koje naša aplikacija upućuje.

Vratimo se sada parsiranju XML sadržaja. XML sadržaj se iz objekta XMLHTTPRequest dobija iz polja responseXML, za razliku od HTML i tekstualnog sadržaja koji se dobijaju iz polja responseText. Polje responseXML je DOM dokument, što znači da se kod njega mogu koristiti DOM funkcije. Stablo našeg XML dokumenta lako je razumeti ako se pogleda prethodna slika. Vidimo da koren stabla čini čvor primer, koji ima četvoro dece-čvorova osoba, od kojih opet svaki ima po tri čvora-deteta: ime, staz i odmor. Korišćenjem funkcije getElementsByTagName(”osoba”) dobijamo niz čvorova osoba iz kojih u petlji izdvajamo podatke o svakoj pojedinačno. Za izdvajanje podataka o svakoj osobi napravili smo posebnu funkciju getXMLTagValue koja vraća sadržaj zadatog taga iz zadatog čvora. Kao što se na pomenutoj slici može videti, podaci izdvojeni iz XML-a se prikazuju u listi – dakle u ovom slučaju objekat content sadrži tag LI.

Dosad smo videli kako teče konstruisanje objekata klase AsyncClass, kao i kako se obrađuju stranice dobijene od servera na osnovu HTTP zahteva koji su upućeni prilikom konstruisanja objekata. Kada je i poslednji odgovor servera obrađen, naša stranica je u potpunosti spremna da odgovori na klikove korisnika aplikacije, naravno na linkove za navigaciju sa leve strane. Još u funkciji init naše klase videli smo da je za obradu klikova na navigacione linkove zadužena funkcija handleClick. Ova funkcija ima jednostavnu ulogu da obriše prethodni sadržaj našeg centralnog panela i da potom u njega smesti objekat content koji sadrži asinhrono učitani sadržaj za izabranu opciju. Funkcija radi i još jednu operaciju koja je neophodna za naš HTML primer – dodeljuje odgovarajuću call-back funkciju dugmetu koje se pojavljuje na asinhrono učitanom HTML-u prikazanom na sledećoj slici.

Slika 5: Prikaz asinhrono učitanog XML-a
Naime, do sada smo pokazali samo kako se zahtevaju podaci od servera, ali ne i kako se podaci šalju serveru. Stoga smo u HTML deo uključili i jednostavan primer sabiranja dva broja u kojem se sabirci unose na našoj stranici, potom se asinhrono šalju serveru na sabiranje da bi ih on sabrao i poslao kao odgovor našoj stranici. Za to nam je bilo potrebno da dugmetu saberi dodelimo call-back funkciju koja će inicirati komunikaciju sa serverom, što smo učinili u prethodno opisanoj funkciji handleClick. Funkcija koja šalje sabirke serveru je submitNumbers. U funkciji se u prve dve linije čita sadržaj tekst polja koja sadrže sabirke, potom se formira URL u koji se smeštaju pročitane vrednosti (dakle, koristi se metod prenosa podataka GET) i na kraju se startuje asinhroni zahtev koji poziva serversku stranu za sabiranje datu u listingu ispod. U nastavku je takođe dat i izvorni kôd HTML stranice koja se asinhrono učitava.

adder.php

async-html.html

Kada nam serverska strana pošalje odgovor sa zbirom, poziva se call-back funkcija addingComplete koja u dijalogu prikazuje tekst poslat sa servera.

Kod slanja podataka na server metodom GET opšti format je jednostavan i uvek isti:

ime_stranice?parametar1=vrednost1¶metar2=vrednost2... parametarN=vrednostN

Slanje podataka metodom POST nešto je složenije, ali zato nije ograničena količina podataka koji se mogu preneti. Nažalost, obim ovog dodatka ne dozvoljava nam da se detaljnije pozabavimo ovom metodom, ali na Internetu ćete veoma lako naći sve o njoj.

Ovde smo završili detaljno objašnjavanje našeg primera, što je možda izgledalo pomalo zastrašujuće. Stoga ćemo rezimirati ovo objašnjenje da bismo videli koliko je osnovna ideja jednostavna – sve ostalo je samo tehnička realizacija. Dakle, događaj onLoad inicira pokretanje skripta koji pravi tri objekta klase koju smo definisali. Svaki od objekata poziva određenu stranicu sa servera i registruje svoju funkciju za obradu klikova za zadatu opciju menija. Objekti koriste sadržaj koji dobiju sa servera za kreiranje elementa koji se ubacuje u glavni panel stranice kada korisnik klikne na opciju. Dok se ne dobije odgovor sa servera, ovaj element sadrži tekst koji kaže da se stranica učitava.

NAPOMENA: Za funkcionisanje primera potrebno je napraviti i tekstualni fajl async-text.txt u kojem može biti bilo kakav tekstualni sadržaj.

Naš pogled na AJAX

Cilj našeg malog priručnika za AJAX bio je da napravimo sažet pregled tehnologija koje čine AJAX, kao i da kroz jednostavne primere dotaknemo sve ono što čini njegovu suštinu. Pokazali smo kako spojiti klasičan HTML i JavaScript, kako rukovati događajima, kako inicirati asinhrone HTTP zahteve i obraditi njihove rezultate. Naučili smo kako se sadržaj stranice može dinamički menjati, kako se novi elementi stranice mogu kreirati i menjati na razne načine. Takođe, videli smo da treba voditi računa o tome kako pretraživači vide našu stranicu, kao i o načinu na koji se aplikacije čine lakim za održavanje. Kôd koji smo naveli u primerima nije imao za cilj da bude najefikasniji i najlepši, već da bude dovoljno ilustrativan, tako da na njega ne treba gledati na nešto što je bogomdano već ga treba prilagođavati svojim potrebama i unapređivati. Isto se može reći i za sam AJAX. Ovo što ste videli u našem dodatku samo je jedan pristup pravljenju AJAX aplikacija – vaš pristup može biti podjednako dobar, ili možda još bolji...

Dejan STEFANOVIĆ

 
 AKCIJE
SK Case Chase: Kućište „Samurai Champloo”

 AKTUELNOSTI
Prvo srpsko sajber-tužilaštvo

 NA LICU MESTA
AirLive sertifikacija distributera, Dubrovnik
ArtTech 2007 (najava)
Lexmark karting kup
Otvaranje novog HP Demo centra
Telsey-Telephant konferencija
World Summit Award 2007
Web Fest 2007 (najava)

 KOMPJUTERI I FILM
„Agi i Ema”

 SITNA CREVCA
Miševi

 SERVIS
Overklokovanje procesora i memorije
Mala škola AJAX-a
Mala škola AJAX-a (2)
Mala škola AJAX-a (3)
Šta mislite o ovom tekstu?
Home / Novi brojArhiva • Opšte temeInternetTest driveTest runPD kutakCeDetekaWWW vodič • Svet igara
Svet kompjutera Copyright © 1984-2018. Politika a.d. • RedakcijaKontaktSaradnjaOglasiPretplata • Help • English
SKWeb 3.22
Opšte teme
Internet
Test Drive
Test Run
PD kutak
CeDeteka
WWW vodič
Svet igara



Naslovna stranaPrethodni brojeviOpšte informacijeKontaktOglašavanjePomoćInfo in English

Svet kompjutera