AJAX bevezető
A webre fejlesztők közös nyelve a HTML, ennek segítségével tudják megfogalmazni
gondolataikat. Sajnos a HTML nagyon korlátozott lehetőséget nyújt a felhasználói interakcióra,
konkrétan hivatkozások, gombok és űrlapok formájában. Sok fajta technológiai megoldás született
ennek kiküszöbölésére, a felhasználói élmény fokozására a böngészőn belül. Ilyenek a Java Applet-ek,
a Flash mozik, és az ActiveX kontrollok is.
Mindegyiknek megvan a saját előnye és hátránya. Itt most két legfontosabb
hátrányt a platform függőséget és a "lejátszó" plug-in telepítésének szükségességét emelhetjük ki.
Nemrégiben elindult egy új, izgalmas irányvonal, ami ezen hátrányokat jól
kiküszöböli. Ezt az új technológiát AJAX-nak keresztelték el. A betűszó az "Asynchronous
JavaScript and XML" rövidítése, azaz aszinkron JavaScript és XML. Nézzük meg pontosan, hogy mit is
jelent ez. Az aszinkron egy olyan dolog, amivel eddig a web programozóknak nem kellett törődnie,
azaz, hogy kérés a háttérben fut. A JavaScript mindenkinek ismerős kell, hogy legyen, ebben a
kontextusban azt jelenti, hogy az Ajax "programozási nyelve" a JavaScript. A szemfüles programozó
arra is rájön belőle, hogy ez egy böngésző oldali technológia. Az XML pedig az "eXtended Markup Language",
egy mostanában futótűzként terjedő technológia, amivel egyszerűen, több rendszer között is
viszonylag könnyen értelmezhető, szabványos módú kommunikációs üzenet forma valósítható meg.
Szóval mi is az az AJAX, ezt még mindig nem értjük! Az AJAX egyszerűen egy új
funkció a böngészőkben, amely segítségével a háttérben kérés küldhető a szerver felé. Mindezt
anélkül, hogy frissítenénk az oldalt vagy elnavigálnánk onnan. A kérésre kapott választ
JavaScript-ből feldolgozhatjuk és az oldal egyes részeit frissíthetjük.
A webes világ az AJAX-ot mégis egy kicsit szélesebben értelmezi, többnyire
beleértik a hozzá szorosan és néha kevésbé szorosan kapcsolódó egyéb JavaScript megoldásokat is.
Ennek a fejezetnek rövid bevezetőt nyújt, hogyan valósítható meg a szigorúbb
értelemben vett AJAX a modern böngészőkben. Először bemutatunk néhány frame-ekre épülő megoldást,
majd egy egyszerűbb utat világítunk meg az XMLHttp segítségével.
A fejezetben elkészített példákat letöltheti külön-külön az alfejezetek elején
található hivatkozásra kattintva, vagy egy csomagolt fájlban.
[ Demo oldal ]
AJAX-hoz vezető megoldások. Miért jobb az AJAX?
Gyakran előfordul, hogy a fejlesztés során a kliens oldali
és a szerver oldali feladatok külön válnak, és más személy, vagy csapat kezébe
kerül a két terület. Az is megfigyelhető azonban, hogy a szerver oldali
programozóknak gyakran részben, vagy egészében a kliens oldali technológiákat
is el kell sajátítaniuk, míg egy nagyszerű kliens oldali programozó nem
feltétlenül ismeri mélységeiben a szerver oldali lehetőségeket.
Az Ajax megjelenésével ez szükségszerűen megváltozik, és
azoknak a kliens oldali fejlesztőknek, akik használni szeretnék az új
technológiát, meg kell ismerniük a másik oldalt.
Ajax kommunikációs technikák
Azt tudjuk, hogy a böngésző és a kiszolgáló közötti
párbeszéd a HTTP segítségével valósul meg, melynek során kérések és válaszok tömkelege
vándorol a weben. Alapesetben egy kérés csak akkor generálódik, amikor a
felhasználó valamely módon ezt kiváltja. Az Ajax használatával nem kell várni a
felhasználóra, a szerverrel bármikor kezdeményezhetünk párbeszédet.
A rejtett (hidden) Frame technika
Az alapötlet az, hogy egy olyan frameset-et készítünk, amelynek
egyik tagjának szélessége és magassága is egyaránt 0 pixel, ebből
következően nem látszik, és kizárólag a szerverrel történő
kommunikációra használjuk.
A kommunikáció minden esetben a 2.1 ábrán látható 4 lépéses minta
alapján zajlik. Az első lépés a látható keretben történik, ahol a
felhasználó, mit sem sejtve arról, hogy létezik a másik frame, a szokásos módon
használja az oldalt, és olyan műveletet kezdeményez, aminek a
kiszolgálásához további adatokra van szükség a szerverről.
Ebben a pillanatban egy JavaScript hívás történik a rejtett
frame-re. Ez a hívás lehet egy egyszerű átirányítás, de akár egy
űrlap adatainak elküldése is, a lényeg, hogy bekövetkezik a folyamat második
lépése, egy HTTP kérés.
A harmadik lépés a szervertől kapott válasz fogadása.
Mivel frame szerkezetben dolgozunk, a válasz nyilván egy újabb weboldal lesz,
ami tartalmazza a szervertől kért adatokat, és azt a JavaScript kódot, ami
átadja azokat a látható frame-nek.
Végül, a negyedik lépésben az előbb említett
JavaScript kód lefut. Tipikusan ez úgy történik, hogy a visszaküldött oldal onload
eseménykezelőjében hívunk meg egy
függvényt a látható frame-ben, és átpasszoljuk a megkapott adatokat, amelyek
sorsáról már a látható frame feladata lesz gondoskodni.
A rejtett frame technika alapelve
Rejtett frame GET típusú kéréssel
Kipróbálom
Letöltöm
A legjobb módszer a példán keresztüli tanulás, ezért most is ezt
alkalmazzuk. Mivel ez az első példa, nagyon egyszerű lesz. A feladat
az, hogy egy ügyfél adatbázisból az ügyfél azonosító (ID) megadása után
visszakapjuk a hozzá tartozó adatokat. Feltételezzük, hogy az adatok SQL
adatbázisban vannak, ezért szükségünk lesz szerver oladli programozásra is.
Ehhez a példában PHP-MySQL-t használunk.
A példa használatához létre kell hozni egy tetszőleges
adatbázist, és abban egy táblát. A következő SQL paranccsal hozhatjuk
létre a táblát.
create table customer (
customer_id int(11) not null auto_increment,
name varchar (255) not null default '',
address varchar (255) not null default '',
city varchar (255) not null default '',
zip varchar (255) not null default '',
phone varchar (255) not null default '',
email varchar (255) not null default '',
primary key (customer_id)
) type=myisam comment='ugyfel adatok';
Az adatbázist és a táblát létrehozó, és adatokkal feltöltő
script benne van a fejezethez tartozó letölthető források között.
Miután az adatbázis és a tábla elkészült, és ellenőriztük,
jöhet a HTML rész. Mivel ugye a "hidden frame" technikát használjuk, a létrehozandó
frameset valahogy így fog kinézni:
index.html
<frameset rows="100%, 0" frameborder="0">
<frame name="displayFrame" src="display.htm" noresize="noresize" />
<frame name="hiddenFrame" src="about:blank" noresize="noresize" />
</frameset>
Ebből azonnal látszik, hogy olyan frameset-et hozunk létre,
amelynek második sora 0 magasságú, azaz nem látszik, de nevet természetesen
kell neki adni, hiszen itt zajlanak majd a háttér események, tehát hivatkoznunk
kell majd rá. Ennél a technikánál a frame-ek méretezését célszerű
letiltani.
Következzék a felhasználó által használt oldal, ahol elkérjük a
felhasználó azonosítóját, és a többi adatot is itt fogjuk majd megjeleníteni:
display.html
function requestCustomerInfo() {
var sId = document.getElementById("txtCustomerId").value;
top.frames["hiddenFrame"].location = "getcustomerdata.php?id=" + sId;
}
<p>Add meg a keresett ügyfél azonosítóját:</p>
<p>Azonosító: <input type="text" id="txtCustomerId" value="" /></p>
<p><input type="button" value="Ügyfél adatai"
onclick="requestCustomerInfo()" /></p>
<div id="divCustomerInfo"></div>
Ez egy elég egyszerű oldal, amin csak egy input box van,
amibe bekérjükmajd az azonosítót, ennek elküldésére egy gomb, és egy <div/> elem,
ahová a visszakapott adatokat majd
elhelyezzük. A gomb megnyomásakor a vezérlés a requestCustomerInfo()
nevű JavaScript függvényre ugrik, ami a rejtett frame-et átirányítja a getcustomerdata.php
oldalra, és a query sztringben átadja neki a beírt ügyfél azonostót.
Ahogy átadtuk a beírt azonosítót a rejtett frame-nek , úgy a
megkapott további adatokat vissza is kell juttatni a felhasználó által látott
frame-be. Ehhez nyilván egy újabb JavaScript függvényre lesz szükség, amit a
rejtett frame hív meg, miután a PHP visszaadta a kért adatokat. A függvény
paramétere, az ügyfél megjelenítendő adatait tartalmazó sztring lesz.
function displayCustomerInfo(sText) {
var divCustomerInfo = document.getElementById("divCustomerInfo");
divCustomerInfo.innerHTML = stext;
}
Ezt a függvényt még adjuk hozzá az előző, display.html oldalhoz, és ezzel
ennek kódolása be is fejeződött. Ideje megnézni a szerver oldali feladatokat.
A getcustomerdata.php egy alap
HTML oldal, két PHP blokkal. Az első blokk a query stringben átvett
azonosító alapján lekérdezi az adatbázisból az ügyfél többi adatát, és
elhelyezi azt egy változóban. Ezt a blokkot később külön tárgyaljuk. A
második blokk az említett változó tartalmát egy<div/>
elembe helyezi.
getcustomerdata.php
<html>
<head>
<title>Ügyfél adatainak lekérése</title>
<?php
// PHP kód, ami lekéri az ügyfél adatait az adatbázisból
?>
</head>
<body>
<div id="divInfoToReturn"><?php echo $sInfo ?></div>
</body>
</html>
Tehát ez az oldal töltődik a rejtett frame-be, magába
foglalva a szervertől kapott választ. Ezután nincs más hátra, mint az
oldal betöltődése után egy JavaScript függvénnyel a</div> tartalmát át kell küldeni a
megjelenítő frame-be:
window.onload = function () {
var = document.getElementById("divInfoToReturn");
top.frames["displayFrame"].displayCustomerInfo(divInfoToReturn.innerHTML);
};
Az első sorban lekérjük a</div>
hivatkozását, a második sorban a megjelenítő frame-ben korábban definiált
displayCustomerInfo() függvényt hívjuk, átadva neki a </div>
innerHTML tulajdonságát, azaz a tartalmát.
Ideje
rátérni az első PHP blokk részleteire, amelyben kiderül, hogy az ügyfél
azonosítójából hogyan is áll elő a $sInfo változó tartalma. Először
szükségünk lesz az adatbázis elérési adataira, majd ha sikeresen csatlakoztunk,
lefuttatjuk a szükséges lekérdezést.
Idézzük
fel, hogyan is hívtuk meg ezt az oldalt? A rejtett frame-et átirányítottuk a
következő URL-re: getcustomerdata.php?id=" + sId. A PHP
blokk elején az url-ben kapott változót hozzuk étre a szokásos $_GET tömb
segítségével, majd a $sInfo szrtingváltozót is inicilizáljuk, üres tartalommal.
A példa kipróbálásához, az adatbázis eléréséhez szükséges
változókba a saját fejlesztőkörnyezetben használt adatokat adjuk meg!
<?php
$sID = mysql_escape_string($_GET['id']);
$sInfo = '';
$sDBServer = 'your.database.server';
$sDBName = 'your_db_name';
$sDBUsername = 'your_db_username';
$sDBPassword = 'your_db_password';
$sQuery = '
select *
from customer
where customer_id=' . $sID;
$oLink = mysql_connect($sDBServer, $sDBUsername,$sDBPassword);
@mysql_select_db($sDBName) or $sInfo = 'Unable to open database';
if($oResult = mysql_query($sQuery) and mysql_num_rows($oResult) > 0) {
$aValues = mysql_fetch_array($oResult,MYSQL_ASSOC);
$sInfo =
$aValues['name'] . '<br/>' .
$aValues['address'] . '<br/>' .
$aValues['city'] . '<br/>' .
$aValues['state'] . '<br /><br/>Telefonszám: ' .
$aValues['phone'] . '<br/>' .
'<a href=\'mailto:' . $aValues['email'].'\'>' .
$aValues['email'] . '</a>'
;
} else {
$sInfo = 'Nem létező ügyfél azonosító:' . $sID;
}
mysql_close($oLink);
?>
Ha találtunk a megadott azonosítóhoz tartozó rekordot, akkor a
$sInfo változóba HTML formátumban, sortörésekkel
elválasztva összefűzzük a mezők tartalmát. Sikertelen kapcsolódás,
vagy nem megfelelő azonosító esetén pedig hibaüzenetet küldünk vissza.
Rejtett frame POST típusú kéréssel
Kipróbálom
Letöltöm
Általánosságban elmondható, hogy a GET-et inkább adatok
lekérésére, míg a POST-ot inkább adatok küldésére használjuk. Ennek több oka is
lehet, de tekintsük a legegyértelműbbet, mégpedig azt, hogy a query
sztringgel küldött adatok mennyisége (512 KB) sokkal kisebb lehet, mint a
POST-olt adatoké (2 GB)
Ugye emlékszünk még arra, amikor a hőskorban a POST
kéréseket csak az űrlapok elküldéséhez használtuk amethod tulajdonság post-ra
állításával? Ezzel most az a probléma, hogy az űrlap elküldésekor a
böngésző az action tulajdonságban megadott
oldalra navigál, azaz egy új, teljes oldalt tölt le, ami teljesen ellentétes az
Ajax céljaival.
Szerencsénkre azonban létezik az űrlapoknak egy kevésbé
ismert, target nevű attribútuma. Ha ezt
beállítjuk, akkor a kitöltött űrlapot tartalmazó oldal megmarad, és az
action által meghatározott cél oldal a target szerint egy új ablakba, vagy egy frame-be
töltődik. Miért ne lehetne ez akár egy rejtett frame?
Készítsünk egy új oldalt az előző példa szerinti
frameset-tel. A különbség csak az, hogy a látható frame-be másik HTML fájlt
töltünk. (entry.html)
<frameset rows="100%,0" frameborder="0">
<frame name="displayFrame" src="entry.html" noresize="noresize" />
<frame name="hiddenFrame" src="about:blank" noresize="noresize" />
</frameset>
A feladatunk az lesz, hogy új ügyfelet tudjunk felvenni az
adatbázisba.. Ehhez készítünk egy űrlapot, ahol az adatokat lehet majd
felvinni. Az ügyfél azonosító nem lesz itt, mert azt az adattáblában
automatikusként definiáltuk. Az űrlap után hozzuk létre azt a divStatus nevű <div/>
elemet, amit a szerverről érkező üzenetek megjelenítéséhez
használunk.
entry.html
<form method="post" action="savecustomer.php" target="hiddenFrame">
<p>Ajda meg az elmentendő ügyfél adatokat:</p>
<p>
Ügyfél neve: <input type="text" name="txtName" value="" /><br />
Cím: <input type="text" name="txtAddress" value="" /><br />
Város: <input type="text" name="txtCity" value="" /> <br />
Irányítószám: <input type="text" name="txtZipCode" value="" /><br />
Telefonszám: <input type="text" name="txtPhone" value="" /> <br />
E-mail: <input type="text" name="txtEmail" value="" />
</p>
<p><input type="submit" value="Ügyfél adatok mentése" /> </p>
</form>
<div id="divStatus"></div>
Az első sorban látható, hogy a <form/>
elem target tulajdonságát beállítottuk, ezért ha
a felhasználó elküldi az űrlapot, a kérés a rejtett frame-be kerül.
A megjelenítő oldalra már csak egy JavaScript függvény
szükséges, amit akkor hívunk meg, amikor a rejtett frame visszaadja a szerver
válaszát.
function saveResult(sMessage) {
var divStatus = document.getElementById("divStatus");
divStatus.innerHTML = "Kérés végrehajtva: " + sMessage;
}
Most akkor nézzük meg a szerveroldali teendőket. Az
előző, példához hasonlóan most is egy egyszerű HTML oldalról van
szó, egy kevés PHP és JavaScript kóddal fűszerezve.
<?php
$sName = mysql_escape_string($_POST['txtName']);
$sAddress = mysql_escape_string($_POST['txtAddress']);
$sCity = mysql_escape_string($_POST['txtCity']);
$sZipCode = mysql_escape_string($_POST['txtZipCode']);
$sPhone = mysql_escape_string($_POST['txtPhone']);
$sEmail = mysql_escape_string($_POST['txtEmail']);
$sStatus = '';
$sDBServer = 'your.database.server';
$sDBName = 'your_db_name';
$sDBUsername = 'your_db_username';
$sDBPassword = 'your_db_password';
$sSQL = "
insert
into customers
(name, address, city, state, zip, phone, email)
values (
'$sName', '$sAddress', '$sCity', '$sState',
'$sZipCode', '$sPhone', '$sEmail'
)
";
$oLink = mysql_connect($sDBServer,$sDBUsername, $sDBPassword);
@mysql_select_db($sDBName) or $sStatus = 'Unable to open database';
if($oResult = mysql_query($sSQL)) {
$sStatus =
'Ügyfél sikeresen rögzítve; Ügyfél azonosító ' .
mysql_insert_id();
} else {
$sStatus = 'Hiba történt az ügyfél rögzítése közben. ' .
'Adatok mentése sikertelen!';
}
mysql_close($oLink);
?>
A PHP a POST metódussal küldött adatokat a $_POST tömb
segítségével begyűjti, és tárolja az adatbázisban. A megjelenítő
oldal számára pedig, a $sStatus valtozó tartalmát kell valahogy visszajuttatni.
Ehhez ismét azonload eseményt használjuk fel.
window.onload = function () {
top.frames["displayFrame"].saveResult("<?php echo $sStatus ?>");
}
A PHP oldal teljes betöltődésekor tehát a megjelenítő
frame-ben definiált Saveresult függvényt hívjuk,
és a PHP által korábban már kitöltött$Status
változót adjuk át paraméterként. Mivel ez egy sztringváltozó, a PHP echo parancsát
idézőjelek közé kellett tenni.
Kész is vagyunk. Kipróbáláskor látható az Ajax előnye: az
oldal újratöltése nélkül, ugyanazzal az űrlappal, egymás után több
ügyfelet is felvehetek az adatbázisba.
Rejtett iFrame
A HTML 4.0-val érkező iframe-mel új lehetőség nyílt a
háttérben történő kliens-szerver kommunikációra. Egy iframe
tulajdonképpen ugyanaz, mint egy hagyományos frame, azzal a különbséggel, hogy
az oldal bármely területén elhelyezhető, nincs szükség frameset
definiálására. Ebből következően JavaScript segítségével akár
futásidőben, dinamikusan is elő lehet állítani. Mindez Ajax
funkciókkal kibővítve, kiváló lehetőségekkel kecsegtette a
fejlesztőket.
Get kérés beágyazott iFrame elemmel
Kipróbálom
Letöltöm
Ebben az esetben viszonylag egyszerű dolgunk lesz. Csak
beágyazunk egy rejtett <iframe/> elemet az
oldalba, majd ezután az első példában látott módon tudunk kéréseket
indítani a szerver felé. Ehhez a megjelenítő oldal kódját át kell
alakítani:
<p>Add meg a keresett ügyfél azonosítóját:</p>
<p>Azonosító: <input type="text" id="txtCustomerId" value="" /></p>
<p><input type="button" value="Ügyfél adatai"
onclick="requestCustomerInfo()" /></p>
<div id="divCustomerInfo"></div>
<iframe
src="about:blank" name="hiddenFrame" width="0"
height="0" frameborder="0"></iframe>
Az iframe width, height és frameborder
tulajdonságai egyaránt 0 értékre vannak állítva, emiatt marad rejtve. Mivel a
neve továbbra is hiddenFrame, minden JavaScript
kód továbbra is működni fog.
Viszont a getcustomerdata.php
oldal JavaScript kódját kis mértékben változtatni kell. Az eredeti verzió
a displayframe nevű frame-ben keresett egy displayCustomerInfo() fügvényt. Mivel
most nincs ilyen
nevű frame-ünk, a parent hivatkozást kell
használnunk.
window.onload = function () {
var divInfoToReturn = document.getElementById("divInfoToReturn");
parent.displayCustomerInfo(divInfoToReturn.innerHTML);
};
Get kérés dinamikus iFrame elemmel
Kipróbálom
Letöltöm
Amikor dinamikusan hozunk létre egy iframe-et, kicsit trükközni
kell, mert a különböző böngészők eltérő módokon valósítják meg
az iframe-eket.
var oIFrame = null;
function createIFrame() {
var oIFrameElement = document.createElement("iframe");
oIFrameElement.width=0;
oIFrameElement.height=0;
oIFrameElement.frameBorder=0;
oIFrameElement.name = "hiddenFrame";
oIFrameElement.id = "hiddenFrame";
document.body.appendChild(oIFrameElement);
oIFrame = frames["hiddenFrame"];
}
Az iframe-et a document.createElement()
metódussal hozzuk létre, és ezután hozzárendeljük a szükséges attribútumokat. A
name és az id egyaránt
meg van adva, mert némely böngészők az iframe-eket name, mások pedig id alapján
azonosítják. Nagyon fontos az a sor, ahol az appendChild()
metódussal az új iframe-et hozzáadjuk a dokumentum struktúrához. E nélkül
nem tudna a szerver felé kéréseket indítani. Az oIFrame
globális változóban tároljuk az iframe objektum hivakozását.
Végül módosítjuk a requestCustomerInfo()
függvényt is.
function requestCustomerInfo() {
if (!oIFrame) {
createIFrame();
setTimeout(requestCustomerInfo, 10);
return;
}
var sId = document.getElementById("txtCustomerId").value;
oIFrame.location = "GetCustomerData.php?id=" + sId;
}
A függvény megvizsgálja, hogy létezik-e már az iframe. ha az
oIFrame globális változónk még nincs értéke, akkor
meghívja a createIFrame() függvényt, majd 10
msec. múlva újrahívja saját magát. erre azért van szükség, mert az IE az
egyedüli böngésző, amely azonnal érzékeli az új iframe-eket, a többi
böngészőnek ez egy kis időbe telik. Miután másodszorra is lefut, az
új iframe már biztosan látható, és a kód többi része is végrehajtódik.
POST kérés dinamikus iFrame elemmel
A GET típusú kérések esetén, ahogy láttuk, viszonylag
egyszerű dolgunk van. A POST története azonban teljesen más, ugyanis kevés
böngésző engedi meg azt, hogy egy űrlap target
tulajdonságát egy dinamikusan előállított iframe elemre állítsuk. Többek
között az IE sem enged ilyesmit, úgyhogy megint jöhet a trükközés. A megoldás
az lesz, hogy a kitöltött űrlap adatait az elküldés után valahogy átirányítjuk
a rejtett iframe-be, és onnan POST-oljuk tovább a szervernek.
Összegzés
Az itt leírt technikák évek óta ismertek és használatban vannak
sok Ajax alkalmazásban. Létezik még néhány szempont, amit érdemes figyelembe
venni, mielőtt kiválasztjuk a megfelelő technikát.
Böngésző History kezelése
Ha rejtett frame-eket használunk, a history működése
zavartalan marad, a felhasználó továbbra is tudja használni a "Vissza" és
"Előre" gombokat. Ennek az az oka, hogy a böngésző nem tudja,
hogy egy frame valójában rejtett, és egyformán kezeli a látható párjával, azaz
továbbra is tárolja azokat a kéréseket, amelyek rajta keresztül indultak.
A rejtett iFrame esetén már más a helyzet, a böngészők
jelenleg ezt eltérően kezelik. Az IE minden iframe esetén tárolja a
history-t, a FireFox csak a statikus iframe-ek esetén, és pl. a Safari egyik
esetben sem.
Árnyoldal
A rejtett frame-ekkel kapcsolatban az lehet a probléma, hogy elég
kevés információnk van arról, ami a háttérben történik. Valójában csak bízni
tudunk abban, hogy a kért adat visszaérkezik a szervertől. Mi van, ha
bármi miatt nem sikerül a szerverrel kommunikálni? A fő oldal továbbra is
működik, semmi jele, hogy probléma lenne, csak várunk a megfelelő
JavaScript függvény hívására. A fejezetben bemutatott példák mindegyike szenved
ebben a betegségben. Be lehetne esetleg állítani egy timeout-ot, aminek
letelése után adunk némi információt, de ez a megoldás nem az igazi.
Szerencsénkre van még egy lehetőségünk: az XMLHttp
XMLHttp
Kipróbálom
Letöltöm
Az XMLHTTP egy Microsoft találmány, amelyet később,
többé-kevésbé hasonlóan, a többi böngészőbe is megvalósítottak. Sajnos a
web világában már megszokhattuk, hogy nem elég egyszer megírni a kódot és azt
egyszer letesztelni, hanem ezeket a lépéseket több különböző
böngészőn is el kell végeznünk. Sőt, gyakori az is, hogy ugyan azt a
kódot többféleképpen kell megírnunk függően attól, hogy milyen
böngészőt detektálunk. Ugyan ez a helyzet az XMLHTTP objektummal is.
Első lépésként hozzunk létre egy ilyen objektumot Internet Explorerben. A
Microsoft ezt a lehetőséget egy ActiveX komponensen keresztül biztosítja,
aminek neve Microsoft.XMLHttp. Létrehozása viszonylag egyszerű:
var request = new ActiveXObject(´Microsoft.XMLHTTP´);
Ez a kód sajnos kizárólag Internet Explorerben működik. A
Mozilla fejlesztői úgy gondolták, hogy a Microsoft egy jól használható
objektumot hozott létre, ezért megalkották saját osztályukat erre a feladatra,
amit XMLHttpRequest névre kereszteltek. Ennek létrehozása még egyszerűbb,
mint az előző esetben:
var request = new XMLHttpRequest();
Vegyítsük a kettő megoldást egy "böngésző független"
megoldássá. Ehhez meg kell vizsgálni, hogy létezik-e XMLHttpRequest osztály,
illetve, hogy létezik-e ActiveXObject. Ha valamelyik létezik, akkor az annak
megfelelő objektumot hozzuk létre:
function createXmlHttp() {
var request = null;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
}
else if (typeof ActiveXObject != undefined) {
request =
new ActiveXObject('Microsoft.XMLHTTP');
}
return request;
}
Figyeljünk a kis és nagy betűk közötti különbségre, mivel a javascript
érzékenyen reagál erre. Ha készen van az objektum, akkor küldjünk el vele egy
kérést a szervernek. Ehhez először elkészítünk egy XMLHTTP objektumot, ha
ez sikerült, akkor az open() metódussal megnyitunk egy GET típusú kérést,
majd elküldjük a megfelelő paraméterekkel a szervernek.
function requestCustomerInfo() {
var sId =
document.getElementById("txtCustomerId").value;
var ajaxRequest = createXmlHttp();
if (ajaxRequest) {
ajaxRequest.open(
'get',
'getcustomerdata.php?id=' + sId, true);
ajaxRequest.send();
}
}
Egy lényeges dolog hiányzik: a szerver által visszaadott adatok
feldolgozása. Ehhez írnunk kell egy esemény feldolgozó függvényt, vagy más
néven "callback" függvényt, amely akkor hívódik meg, ha a kérés állapotában
változás áll be. Minket jelenleg csak egy változás érdekel, amikor visszakapjuk
a kérés eredményét, tehát az egész folyamat lezárult. A függvénynek szüksége van
a kérésre, hogy eldönthesse: megvan-e a válasz a szervertől. Erre
készítsünk egy globális változót, amiben a kérésünket tárolni fogjuk.
var ajaxRequest = null;
function requestCustomerInfo() {
var sId =
document.getElementById("txtCustomerId").value;
ajaxRequest = createXmlHttp();
if (ajaxRequest) {
ajaxRequest.open(
'get', 'getcustomerdata.php?id=' + sId, true);
ajaxRequest.send();
}
}
A függvényünkben, amelyik a változáskor hívódik meg, le kell
kezelni a különböző állapotokat. Azt hogy éppen milyen fázisban van a
kérés azt az objektum readyState tulajdonságában találjuk meg.
Ennek értéke 4, ha a kérés befejeződött és az adatokat visszakaptuk a szervertől. Tehát először
ellenőrizzük le, hogy megfelelő-e a státusz. Ha nem, akkor ne is
haladjunk tovább:
function ajaxCustomerInfo() {
if (ajaxRequest.readyState != 4) {
return;
}
}
A kérés végén az objektum responseText tulajdonságában érhetjük
el a szerver válaszát. Ezt helyezzük el a megfelelő <div/> elembe:
var divCustomerInfo =
document.getElementById('divCustomerInfo')
divCustomerInfo.innerHTML =
ajaxRequest.responseText;
Már csak egy feladatunk maradt, be kell állítani, hogy a mi
függvényünk hívódjon meg, amikor változás áll be a kérés állapotában.
Mielőtt a send() metódussal elküldjük a kérést, állítsuk az
onreadystatechange tulajdonságot a saját függvényünkre:
ajaxRequest.onreadystatechange =
ajaxCustomerInfo;
Ahhoz, hogy működjön a getcustomerdata.php átírása nem
feltétlenül szükséges, de érdemes. Ugyanis eddig szükség volt arra, hogy
szerver teljes HTML kódot adjon vissza, mivel azt egy frame-be töltöttük be.
XMLHTTP kérés esetén ezek csak fölösleges szövegek, elég a ténylegesen kiírandó
információ tartalmat visszaadni:
<?php
$sID = mysql_escape_string($_GET['id']);
//itt minden ugyan az mint az előző esetben ...
mysql_close($oLink);
echo $sInfo;
?>
A gyakorlott programozó már nem lepődik meg, amikor
kipróbálja az eddig összeállított példát, és kérdőjeleket lát a visszakapott
szöveg ékezeteinek helyén. Ennek oka, hogy a böngésző rosszul értelmezi a
visszakapott választ. Egyszerűen javíthatjuk a hibát, ha megmondjuk, hogy
milyen kódlappal kell értelmezni a választ:
<?php
header('Content-Type: text/html; charset=iso-8859-2');
...
Amennyiben az adatbázis létrehozásánál már kódlappal dolgoztunk,
akkor konvertálás helyett érdemes azt megadni.
Összegzés
Reméljük sikerült mindenkit meggyőzni, hogy az XMLHTTP kezelése
pofon egyszerű feladat. Milyen előnyök járnak az előzőekben
leírt hidden frame-s technikával szemben? Egyrészt sokkal áttekinthetőbb javascript
kódot eredményez, mivel minden függvény egy fájlban maradhat. A szerver oldalon
pedig nem kell a megjelenítéssel foglalkozni, csak az adatok
összegyűjtésével, így ez a kód is átláthatóbb marad.
Hasznos linkek