Ajax - IFrame
Keď už vieme prenášať požiadavky prostredníctvom objektu XMLHttpRequest, nezaškodí poznať aj iné alternatívy komunikácie medzi klientom a serverom. V dnešnom článku sa podrobne pozrieme na prenos údajov cez dynamicky vytvorený skrytý rámec.
Minule sme sa oboznámili s použitím objektu XMLHttpRequest
, ktorý je určený na komunikáciu klienta so serverom. Dnešný článok bude o alternatívnom spôsobe komunikácie, ktorého použitie je v niektorých aspektoch oveľa výhodnejšie. Ak potrebujeme odosielať iba požiadavky typu GET a POST (čo je drvivá väčšina prípadov), je v súčasnosti komunikácia prostredníctvom skrytého rámca väčšinou tou lepšou možnosťou, ako samotný objekt XMLHttpRequest
.
Prostredníctvom elementu iframe
dokážeme prenášať údaje v HTML alebo v textovom formáte. Navyše od objektu XMLHttpRequest
môžeme prenášať aj súbory z klientského počítača. Cestu k súboru však musí najskôr návštevník stránky vybrať, až potom môžeme prepísaním atribútu target
formulára presmerovať požiadavku do skrytého rámca a súbor pomocou JavaScriptu odoslať na server.
V súčasnosti najväčšou výhodou prenosu dát prostredníctvom skrytého rámca je to, že v prehliadači Internet Explorer 6 a jeho predchádzajúcich verziách nepotrebujme používať ActiveX objekt. Pri vyššom stupni zabezpečenia tak nebude vyskakovať na používateľa otravná hláška. Okrem toho je element iframe
podporovaný vo viacerých prehliadačoch, než objekt XMLHttpRequest
. Vývoj však nezastavíme a v budúcnosti zrejme nebudú tieto dve výhody skrytého rámca až také podstatné.
Podobne ako to bolo pri použití objektu XMLHttpRequest
, ani prostredníctvom rámca nemôžeme plne komunikovať so serverom z inej domény. Odosielanie požiadaviek je síce možné, avšak prečítanie odpovede už také jednoduché nie je. V JavaScripte sa totiž nedostaneme k dokumentu v elemente iframe
, ktorý obsahuje stránku servera z inej domény. Napriek tomu môžeme v obmedzenej forme dostať odpoveď aj z takéhoto servera. Odpoveď môže byť obsiahnutá v adrese stránky, na ktorú server požiadavku skriptu presmeruje. Prečítaním adresy rámca z atribútu src
sa túto odpoveď dozvieme.
Vytvorenie skrytého rámca
Najjednoduchším spôsobom, ako vytvoriť na stránke skrytý element iframe
, je vložiť ho priamo do HTML kódu stránky. To však vôbec nie je elegantné. Keďže chceme oddeliť správanie od obsahu stránky, budeme skrytý rámec vytvárať prostredníctvom JavaScriptu. Rámec vytvoríme pomocou štandardnej metódy createElement
pre vytváranie elementov. Aby bol neviditeľný, nastavíme mu nulovú šírku, výšku a nulové okraje. Posledným krokom je nastavenie obslužnej funkcie, ktorá sa zavolá vždy po dokončení nahrávania obsahu rámca.
function createIFrame ()
{
var iframe = null;
if (document.createElement)
{
var iframe = document.createElement ("iframe");
iframe.style.position = "absolute";
iframe.style.border = "0";
iframe.style.width = "0";
iframe.style.height = "0";
iframe.load = function () {receiveResponse (iframe)};
document.body.appendChild (iframe);
if (iframe.addEventListener) // Gecko / W3C
iframe.addEventListener ("load", iframe.load, false);
else if (iframe.attachEvent) // IE
iframe.attachEvent ("onload", iframe.load);
else
iframe.onload = iframe.load;
}
return iframe;
}
Pre nastavenie obslužnej funkcie použijeme štandardnú metódu addEventListener
. V prehliadačoch, ktoré túto metódu nepodporujú, skúsime použiť neštandardnú metódu attachEvent
, prípadne priradiť obslužnú funkciu priamo. Podobne ako v predchádzajúcom článku musíme aj tu myslieť na uvoľňovanie pamäte. Keďže sme elementu iframe
nastavili obslužnú funkciu, ktorá používa odkaz na iframe
, vytvorili sme kruhovú referenciu medzi elementom dokumentu a objektom JavaScriptu. Aby sme dokázali neskôr tento začarovaný kruh rozťať, odložíme si dočasne odkaz na obslužnú funkciu do vlastnosti load
elementu iframe
.
Odoslanie požiadavky
Požiadavku na server odošle prehliadač automaticky po nastavení adresy skrytého rámca alebo po zavolaní metódy submit
formulára, ktorého odpoveď smeruje do skrytého rámca. Po spracovaní požiadavky sa odpoveď servera v tomto rámci objaví.
Odoslanie požiadavky metódou POST
Odoslanie údajov z formulára, ktorý je už na stránke, je jednoduché. Rámcu, ktorý sme vytvorili, priradíme nejaké meno v atribúte name
a to isté meno nastavíme formuláru do atribútu target
. Väčšinou však takýto formulár na stránke nemáme a odoslanie bude zložitejšie.
Pri odosielaní údajov metódou POST vytvoríme v skrytom rámci formulár, ktorý naplníme požadovanými údajmi. Nakoniec ho odošleme metódou submit
. Odoslanú požiadavku zakóduje samotný prehliadač, takže nemáme priamu kontrolu nad odoslanými údajmi.
function sendRequest (data, url)
{
var iframe = createIFrame ();
if (iframe)
{
var iframeDoc = (iframe.contentWindow?
iframe.contentWindow.document:
iframe.contentDocument);
if (iframeDoc)
{
var pairs = data.split ("&");
var inputs = [];
var encode = function (text)
{
return decodeURIComponent (text).
replace (/&/g, "&").
replace (/</g, "<").
replace (/>/g, ">").
replace (/"/g, """);
};
for (var i = 0; i < pairs.length; ++i)
{
var pair = pairs [i].split ("=");
inputs [i] =
'<input type="text" name="' + encode (pair [0]) + '"' +
' value="' + encode (pair [1]) + '" />';
}
iframeDoc.open ();
iframeDoc.write (
'<form action="' + url + '" method="POST">' +
inputs.join ("") +
"</form>");
iframeDoc.getElementsByTagName ("form") [0].submit ();
}
return iframeDoc;
}
return false;
}
Uvedená funkcia dynamicky vytvorí skrytý rámec. Aby bolo možné zapísať do dokumentu rámca formulár, musí sa najprv dostať k dokumentu rámca, ktorý si uloží do premennej iframeDoc
. V nasledujúcom kroku vygeneruje formulár na základe údajov, ktoré chceme odoslať. Tieto údaje sú uložené v reťazci data
. Namiesto reťazca by sme mohli použiť napríklad asociatívne pole. Reťazec používame preto, aby bolo rozhranie funkcie pre odoslanie požiadavky rovnaké, ako v minulom článku.
Premenná data
teda obsahuje zakódovaný formulár. Formulár je zakódovaný rovako, ako by to spravil pri odosielaní prehliadač. Reťazec pozostáva z dvojíc meno=hodnota
, ktoré sú zreťazené znakom &
. Meno aj hodnota sú URL-zakódované. Funkcia pre odoslanie požiadavky metódou POST tento reťazec dekóduje a vytvorí z neho formulár. Každá dvojica meno=hodnota
zodpovedá jednému elementu input type=text
, ktorého atribút name
obsahuje meno a atribút value
obsahuje hodnotu. Vygenerovaný formulár odošle údaje na zadanú adresu, čo dosiahneme nastavením atribútu action
. Nakoniec volaním metódy submit
formulár odošleme.
Odoslanie požiadavky metódou GET
Odoslanie požiadavky metódou GET je oveľa jednoduchšie. Stačí nastaviť zdroj rámca prostredníctvom atribútu src
na požadovanú URL.
function sendRequest (data, url)
{
var iframe = createIFrame ();
if (iframe)
iframe.location.replace (url);
}
Táto funkcia ani nepotrebuje komentár. Nasledujúcim krokom bude prijatie a spracovanie odpovede nastavenou funkciou receiveResponse
.
Prijatie odpovede
Pri vytváraní rámca sme mu nastavili obslužnú funkciu, ktorá sa zavolá po nahraní jeho obsahu. Táto funkcia spracuje odpoveď nastavenú v jeho dokumente:
function receiveResponse (iframe)
{
var iframeDoc = (iframe.contentWindow?
iframe.contentWindow.document:
iframe.contentDocument);
var text = iframeDoc.body.innerHTML.
replace (/&/g, "&").
replace (/</g, "<").
replace (/>/g, ">").
replace (/"/g, '"');
alert (text);
if (iframe.removeEventListener)
iframe.removeEventListener ("load", iframe.load, false);
else if (iframe.detachEvent)
iframe.detachEvent ("onload", iframe.load);
else
iframe.onload = null;
iframe.load = null;
setTimeout (function () {document.body.removeChild (iframe)}, 0);
}
Pri prijatí odpovede sa najprv dostaneme k dokumentu rámca. Potom dekódujeme jeho obsah. Ten je zakódovaný do HTML, takže musíme nahradiť špeciálne entity za znaky, ktoré reprezentujú.
Po spracovaní odpovede nesmieme zabudnúť na odregistrovanie obslužnej funkcie a odstránenie skrytého rámca zo stránky. Odstránením obslužnej funkcie, na ktorú sme si odložili referenciu do vlastnosti load
, prerušíme kruhovú referenciu, čím umožníme prehliadaču Internet Explorer uvoľniť pamäť. Odstránenie skrytého rámca zo stránky o niečo oneskoríme, pretože odstraňujeme element, ktorého udalosť práve obsluhujeme. V opačnom prípade by prehliadač Firefox neukončil korektne načítavanie obsahu rámca.
Záver
V tejto časti seriálu sme si ukázali spôsob odosielania údajov metódou GET aj POST prostredníctvom skrytého rámca. Uvedené funkcie by mali stačiť na vytvorenie jednoduchej aplikácie, kde komunikuje klient so serverom.
Podobne ako v predchádzajúcom článku sme sa aj tu zaoberali uvoľňovaním pamäte. Pri písaní funkcií v JavaScripte, ktoré plánujeme využívať mnohokrát za sebou, by sme sa mali vždy zamyslieť aj nad problémom neuvoľňovania pamäte v niektorých prehliadačoch.