AJAX Asynchronous JavaScript and XML, jméno AJAX vzniklo v roce 2005 směs již existujících technologií JavaScriptu na straně klienta umožňuje volat v pozadí server a podle potřeby tak získat potřebná data (aktualizace stránek bez nutnosti opětovného načítání celé stránky) klient zasílá http žádost (request) na server, uživatel může pracovat souběžně s rozhraním na klientovi, zatímco server zpracovává jeho požadavek problémy: nefunguje v prohlížečích bez JavaScriptu špatně se vkládají do oblíbených položek špatně spolupracují s vyhledávacími stroji vznik velkého množství nových knihoven vývoj AJAXu podporován Microsoftem v projektu Atlas 1 Prvky AJAXu HTML, XHTML, CSS JavaScript manipulující s částmi HTML stránky pomocí DOM DOM (Document Object Model) = model internetových stránek pro jejich dynamickou změnu objekt XMLHttpRequest (vyvinutý firmou Microsoft v roce 1999), dnes součástí moderních prohlížečů, snahy o standardizaci na straně serveru je zapotřebí něco na zpracování požadavků, např. PHP server posílá data ve formátu, který je pak parsován JavaScriptem v klientovi, doporučeným formátem je XML nabo JSON (JavaScript Object Notation) 2 DOM model na klientovi při interpretaci HTML stránky vzniká objektový model dokumentu DOM objekty vytváří strom dokumentu lze vytvářet dynamicky nové uzly nebo je rušit, mazat jejich obsah důležité vlastnosti objektů DOM: nodetype = typ uzlu (12 typů), nejčastěji ELEMENT_NODE nebo TEXT_NODE (listový) id = jedinečný identifikátor tagname = název HTML tagu vlastnosti pro pohyb ve stromu: childnodes = pole ukazatelů na nejbližší potomky parentnode = ukazatel na rodiče metody: getelementbyid(id) = vrátí ukazatel na prvek s daným id getelementbytagname(tagname) = vrátí pole ukazatelů na prvek s daným jménem směrem od uzlu, na kterém byla metoda volána createelement(tagname) = vrátí ukazatel na nově vytvořený element createtextnode(text) = vrátí ukazatel na nově vytvořený textový uyel appendchild(uzel) = připojí uzel do seznamu potomků removechild(uzel) = odstraní uzel ze seznamu potomků 3 Techniky založené na JavaScriptu JavaScript a DOM DOM má schopnost manipulovat s dokumenty založenými na XML (včetně HTML) na straně klienta: manipulace s HTML stránkou během práce s ní 16.2.2011 1/18 Ajax
čtení a parsování souborů XML získaných ze serveru tvorba nových dokumentů XML na straně serveru: vytváření nových dokumentů XML (a jejich následné zaslání klientovi) čtení XML dokumentů kód JavaScriptu se provádí před parsováním ostatního kódu HTML, jeho výstup se zobrazí nejdřív *** pozdrav.html *** <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="generator" content="pspad editor, www.pspad.com"> <title>ajax: JavaScript a DOM</title> <script type="text/javascript" src="pozdrav.js"></script> </head> <body> <body> <p>přeji krásný den!</p> </body> </html> *** pozdrav.js *** // JavaScript Document var date = new Date(); var hour = date.gethours(); if (hour>=22 hour<5) document.write("dobrou noc, už je ", hour, " hodin"); else document.write("dobrý den, je právě ", hour, " hodin"); *** výstup *** Dobrou noc, už je 23 hodin Přeji krásný den! nebo lze v JavaScriptu uložit to, co se má udělat, do nějaké funkce a její volání svázat s nějakou událostí v dalším příkladě je volána javascriptovská funkce při kliknutí na odesílací tlačítko formuláře funkce zmena() provede tyto změny stránky = DOM vytvoří element <ul> přidá do něj položky = vytvoří element <li> a vloží text smaže obsah textového vstupu jmeno zruší odesílací tlačítko *** adresar.html *** <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="generator" content="pspad editor, www.pspad.com"> <title>adresář</title> <script type="text/javascript" src="adresar.js"></script> </head> <body> <h1>adresář</h1> <div id="adresar"></div> <form> <label for="jmeno">jméno:</label> 16.2.2011 2/18 Ajax
<input type="text" id="jmeno" name="jmeno" value="karel Novák"> <input type="button" id="odesli" name="odesli" value="odešli" onclick="zmena();"> </form> </body> </html> *** adresar.js *** // JavaScript Document var zmena = function() { var adresar = document.getelementbyid("adresar"); var jmeno = document.getelementbyid("jmeno"); var seznam = document.createelement("ul"); pridejpolozku(seznam, jmeno.value); pridejpolozku(seznam, "Eva Bílá"); pridejpolozku(seznam, "Pepa Zdepa"); adresar.appendchild(seznam); jmeno.value = ""; var odesli = document.getelementbyid("odesli"); odesli.parentnode.removechild(odesli); var pridejpolozku = function(seznam, text) { var polozka = document.createelement("li"); seznam.appendchild(polozka); polozka.appendchild(document.createtextnode(text)); *** před stiskem Odešli *** *** po stisku Odešli *** 4. JavaScript, DOM a CSS pomocí DOM můžeme manipulovat i se styly JavaScript přiřadí elementům tabulky odpovídající styl <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/tr/xhtml11/dtd/xhtml.11.dtd" /> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="generator" content="pspad editor, www.pspad.com"> <title>ajax: JavaScript, DOM a CSS</title> <script type="text/javascript" src="jsdom5.js"></script> <noscript>vypnutý JavaScript</noscript> <link href="styl5.css" type="text/css" rel="stylesheet" /> </head> <body> 16.2.2011 3/18 Ajax
<table id="table"> <tr> <th id="tablehead">název výrobku</th> </tr> <tr> <td id="tablefirstline">letadlo</td> </tr> <tr> <td id="tablesecondline">náklaďák</td> </tr> </table> <br /> <input type="button" value="nastav styl 1" onclick="setstyle1();" /> <input type="button" value="nastav styl 2" onclick="setstyle2();" /> </body> </html> // JavaScript Document // nastavení stylů tabulky na styl č.1 function setstyle1() { // získání odkazů na elementy HTML otable = document.getelementbyid("table"); otablehead = document.getelementbyid("tablehead"); otablefirstline = document.getelementbyid("tablefirstline"); otablesecondline = document.getelementbyid("tablesecondline"); // nastavení stylů otable.classname = "Table1"; otablehead.classname = "TableHead1"; otablefirstline.classname = "TableContent1"; otablesecondline.classname = "TableContent1"; // nastavení stylů tabulky na styl č.1 function setstyle2() { // získání odkazů na elementy HTML otable = document.getelementbyid("table"); otablehead = document.getelementbyid("tablehead"); otablefirstline = document.getelementbyid("tablefirstline"); otablesecondline = document.getelementbyid("tablesecondline"); // nastavení stylů otable.classname = "Table2"; otablehead.classname = "TableHead2"; otablefirstline.classname = "TableContent2"; otablesecondline.classname = "TableContent2"; /* CSS Document */.Table1 { border: DarkGreen 1px solid; background-color: LightGreen;.TableHead1 { font-family: Verdana, Arial; font-weight: bold; font-size: 10pt;.TableContent1 { font-family: Verdana, Arial; font-size: 10pt;.Table2 { border: DarkBlue 1px solid; background-color: LightBlue; 16.2.2011 4/18 Ajax
.TableHead2 { font-family: Verdana, Arial; font-weight: bold; font-size: 10pt;.TableContent2 { font-family: Verdana, Arial; font-size: 10pt; 5 Objekt XMLHttpRequest objekt umožňující JavaScriptu vytvářet asynchronní požadavky na server vytvořen firmou Microsoft v roce 1999 objekt je ve všech novějších webových prohlížečích, ale není standardem W3C objekt se vytváří v různých prohlížečích různě ale pak už se používá stejně, instance ve všech prohlížečích budou stejné posloupnost operací při práci s XMLHttpRequest: vytvoření instance XMLHttpRequest použití objektu k vytvoření asynchronního volání stránky na serveru + definice funkce zpětného volání (automaticky se provede při odpovědi od serveru) práce s odpovědí serveru ve funkci zpětného volání další použití objektu XMLHttpRequest... 5.1. Vytvoření objektu XMLHttpRequest pro nové prohlížeče: xmlhttp = new XMLHttpRequest(); pro Internet Explorer 6 a staší: xmlhttp = new ActiveXObject("Microsoft.XMLHttp"); před vytvářením objektu mohu nejdříve zkotrolovat, zda je XMLHttpRequest podporován daným prohlížečem: if (typeof XMLHttpRequest!= "undefined")... vlastnosti a metody objektu XMLHttpRequest: abort() = ukončí aktuální požadavek getallresponseheaders() = vrátí hlavičky odpovědi jako řetězec getallresponseheaders("headerlabel") = vrátí jednu hlavičku odpovědi jako řetězec open("method", "URL" [, asyncflag [, "username" [, "password"]]]) = konfiguruje požadavek a nastavuje jeho parametry send(content) = provede požadavek HTTP setrequestheader("label", "value") = nastaví dvojici label/value požadavku onreadystatechange = používá se pro funkci zpětného volání, která ovládá změny stavu požadavku readystate = vrátí stav požadavku responsetext = vrátí odpověď serveru jako řetězec responsexml = vrátí odpověď serveru jako dokument XML status = vrátí stavový kód požadavku (bez chyby = 200) statustext = vrátí zprávu stavu požadavku *** vytvorenixmlhttprequest.js *** var xmlhttp = vytvorxmlhttprequestobject(); //uchovava instanci /* vytvoření instance XMLHttpRequest */ function vytvorxmlhttprequestobject() { var xmlhttp; try { 16.2.2011 5/18 Ajax
xmlhttp = new XMLHttpRequest(); // pro všechny prohlížeče mimo IE6 a starší catch(e) { // pro prohlížeče IE6 a starší var verze = new Array("MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"); for (var i=0; i<verze.length &&!xmlhttp; i++) { try { xmlhttp = new ActiveXObject(xmlHttpVersions[i]); catch(e) { alert("chyba při vytváření objektu XMLHttpRequest"); if (!xmlhttp) alert("objekt XMLHttpRequest se nepodařilo vytvořit"); else return xmlhttp; 5.2. Inicializace požadavků na server pomocí XMLHttpRequest před tím, než pošleme požadavek na server, musíme provést jeho inicializaci a nastavit mu patřičné hlavičky pro inicializaci HTTP požadavku slouží metoda open() objekt XMLHttpRequest vytváří standardní požadavek http, rozdíl je jen v tom, že je asynchronní open()= pouze nastavuje volby serveru, nevyvolává spojení se serverem, má argumenty: method: GET, POST, PUT (= atribut method formuláře) url: (= atribut action formuláře), kam se má požadavek poslat, adresa relativní nebo absolutní (pokud není URL pomocí http, je první argument ignorován) async: true = zpracovávání skriptu pokračuje po ukončení metody send() bez čekání na odpověď false = před pokračováním se čeká na odpověď username, password = nepovinné, používá se při přihlašování na server, který vyžaduje autentizaci když se provádí požadavek asynchronně, je před voláním send() potřeba nastavit událost onreadystatechange na metodu zpětného volání, která se provede při změně stavu požadavku = základní mechanismus AJAXu při inicializaci požadavku jsou automaticky nastaveny patřičné hlavičky, můžeme hlavičky také přidat, např. hlavičku XML: XMLHttpRequest.setRequestHeader("Content-type", "text/xml"); 5.3. Odeslání požadavku na server k odeslání dat slouží metoda send() parametr metody = tělo požadavku tělo požadavku může být ve formátu: textový řetězec zaslaný metodou GET textový řetězec zaslaný metodou POST XML dokument zaslaný metodou POST *** volání stránky serveru *** function process() { if (xmlhttp) { // volání stránky serveru pro spuštění serverové operace pro metodu GET try { xmlhttp.open("get", "async.txt", true); xmlhttp.onreadystatechange = handlerequeststatechange; //metoda zpětného volání xmlhttp.send(null); 16.2.2011 6/18 Ajax
catch(e) { alert("chyba při připojování na server" + e.tostring()); /* pro metodu POST xmlhttp.open("post", "http://localhost/ajax/test.php", true); xmlhttp.onreadystatechange = handlerequeststatechange; xmlhttp.send("param1=x¶m2=y"); */ DOM model můžeme uplatnit i na XML dokument na rozdíl od HTML musíme nejdříve vytvořit kořen dokumentu, vytvoření závisí opět na typu prohlížeče použijeme metodu createdocument(jmenný prostor, kořenový element, typ dokumentu) *** vytvorenixml.js *** var vytvorxml = function() { var xml; if (document.implementation && document.implementation.createdocument) { xml = document.implementation.createdocument("","",null); else if (ActiveXObject) { xml = new ActiveXObject("Microsoft.XMLDOM"); return xml; 5.4. Stavy požadavku a zpracování odpovědi serveru můžeme získat informaci o stavu zpracování požadavku readystate = vrátí stav požadavku: 0 = neinicializovaný... uninitialized 1 = zavádí se... loading 2 = je zaveden... loaded 3 = přechodný... intermediate (část. přijata) 4 = kompletní... complete některé prohlížeče nepodporují všechny stavy sledujeme jen stav 4, ten je podporován vždy musíme ještě ověřit, že během zpracování nedošlo k chybě: vlastnost status je rovna hodnotě 200 popis stavu je uložen v proměnné statustext, můžeme použít při vypsání chyby *** stav zpracování požadavku *** XMLHttpRequest.onreadystatechange = function() { if (xmlhttp.readystate == 4 && xmlhttp.status == 200) { try { // zpracování odpovědi catch(e) { alert("chyba čtení odpovědi" + e.tostring()); else { alert("při zpracování na serveru došlo k chybě: "+ XMLHttpRequest.statusText); 16.2.2011 7/18 Ajax
při vytváření asynchronního požadavku nezpůsobí vykonání xmlhttp.send() zamrznutí prohlížeče nastavíme metodu zmenapozadavku tak, aby ošetřila změnu stavu požadavku /* funkce ošetřuje odpověď HTTP response */ function zmenapozadavku() { // získání reference na element <div> na stránce mydiv = document.getelementbyid("mujdivelement"); // zobrazování stavu požadavku if (xmlhttp.readystate == 1) mydiv.innerhtml += "Request status: 1 (loading) <br />"; else if (xmlhttp.readystate == 2) mydiv.innerhtml += "Request status: 2 (loaded) <br />"; else if (xmlhttp.readystate == 3) mydiv.innerhtml += "Request status: 3 (interactive) <br />"; // pokračuj, je-li proces kompletní else if (xmlhttp.readystate == 4) { // pokračuj pouze, je-li status HTTP "OK" if (xmlhttp.status == 200) { try { // čti zprávu ze serveru response = xmlhttp.responsetext; // zobraz zprávu mydiv.innerhtml += "Request status: 4 (complete). Server odpovídá:<br />"; mydiv.innerhtml += response; catch(e) { alert("chyba čtení odpovědi" + e.tostring()); else { // zobraz zprávu o stavu alert("problém s daty: " + xmlhttp.statustext); Celý příklad vytvoříme soubor async.txt s textem např: Pozdrav ze serveru!!! vytvoříme soubor async.html: <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/tr/xhtml11/dtd/xhtml.11.dtd"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <meta name="generator" content="pspad editor, www.pspad.com"> <title>ajax: JavaScript a XMLHttpRequest</title> <script type="text/javascript" src="async.js"></script> </head> <body onload="vytvorpozadavek()"> <p> Servere, řekni mi, jaké jsou tvoje oblíbené knihy? <br /> <div id="mujdivelement"> </p> </body> </html> vytvoříme soubor async.js: 16.2.2011 8/18 Ajax
var xmlhttp = createxmlhttprequestobject(); // uchovává instanci XMLHttpRequest function vytvorxmlhttprequestobject() {... // vytvoří instanci XMLHttpRequest function vytvorpozadavek() {... // vytváří požadavek na server function zmenapozadavku() {... // volá se při změně stavu HTTP požadavku zadáme adresu http://localhost/.../async.html v prohlížeči se nám pak zobrazí: Ahoj, servere! Request status: 1 (loading) Request status: 2 (loaded) Request status: 3 (interactive) Request status: 4 (complete). Server odpovídá: Pozdrav ze serveru!!! 6. Práce se strukturami XML ze serveru nebudeme číst řetězec, ale soubor XML soubor XML: <?xml version="1.0" encoding="windows-1250" standalone="yes"?> <knihy> <kniha> <autor>rastislav Škultéry</autor> <titul>javascript</titul> </kniha> <kniha> <autor>cristian Darie</autor> <titul>ajax a PHP</titul> </kniha> <kniha> <autor>rudolf Pecinovský</autor> <titul>návrhové vzory</titul> </kniha> </knihy> v souboru HTML změníme v rámci logiky příkladu pouze obsah těla: <body onload="vytvorpozadavek()"> <p> Servere, jaké jsou tvoje oblíbené knihy? <br /> <div id="mujdivelement"> </p> </body> v souboru s JavaScriptem změníme v metodě vytvorpozadavek(): xmlhttp.open("get", "knihy.xml", true); // čte soubor xml v souboru s JavaScriptem změníme metodu zmenapozadavku(), budeme v ní volat metodu zpracujodpovedserveru(), do ní přesuneme veškerou funkčnost: /* funkce se volá při změně stavu HTTP požadavku */ function zmenapozadavku() { // pokračuj, je-li proces kompletní if (xmlhttp.readystate == 4) { 16.2.2011 9/18 Ajax
if (xmlhttp.status == 200) { try { // zpracování odpovědi ze serveru zpracujodpovedserveru(); catch(e) { alert("chyba čtení odpovědi" + e.tostring()); else { // zobraz zprávu o stavu alert("problém s daty: " + xmlhttp.statustext); metoda zpracujodpovedserveru() přečte zprávu ze serveru a generuje odpověď HTML: přečte zprávu ze serveru: var xmlzprava = xmlhttp.responsexml zabalí přijatou odpověď jako dokument DOM (případně zobrazí chybu) získáme odkaz na kořen dokumentu: korenxml = xmlresponse.documentelement pak už můžeme procházets tromem dokumentu a získávat potřebná data funkce getelementsbytagname() parsuje celý dokument a vrací elementy se zadaným jménem (nebo můžeme použít jazyk XPath) vytvoříme výstupní pole z těchto polí vytvoříme strukturu HTML dokumentu ošetření dalších chyb a generování výjimek: pokud je chyba v XML souboru, žádný prohlížeč kromě Internet Exploreru ji nezachytí, přidáme kontrolu: v metodě zpracujodpovedserveru() přidáme zachycení možných chyb u různých prohlížečů /* zpracování odpovědi serveru */ function zpracujodpovedserveru() { // přečte zprávu ze serveru var xmlresponse = xmlhttp.responsexml; // zachycení možných chyb u IE a Opery if (!xmlresponse!xmlresponse.documentelement) throw("špatná XML struktura:\n" + xmlhttp.tesponsetext); // zachycení možných chyb u Firefoxu var rootnodename = xmlresponse.documentelement.nodename; if (rootnodename == "parsererror") throw("špatná XML struktura:\n"); // nastaví nový obsah HTML novyobsahhtml(xmlresponse); /* získání nového obsahu html ze souboru xml zaslaného serverem */ function novyobsahhtml(xmlresponse) { // získá element dokumnentu XML xmlroot = xmlresponse.documentelement; // získá pole autorů a titulů autorarray = xmlroot.getelementsbytagname("autor"); titularray = xmlroot.getelementsbytagname("titul"); // generuje výstup HTML var html = ""; for (var i=0; i<titularray.length; i++) 16.2.2011 10/18 Ajax
html += autorarray.item(i).firstchild.data + ": " + titularray.item(i).firstchild.data + "<br />"; // získání reference na element <div> na stránce a změní obsah html mydiv = document.getelementbyid("mujdivelement"); mydiv.innerhtml = "Server odpovídá: <br />" + html; 7. Techniky na straně serveru s PHP a MySQL XML může být generováno také dynamicky napíšeme PHP skript, který bude generovat XML dynamicky HTML se nezmění v JavaScriptu se změní v process(): xmlhttp.open("get", "phpxml.php", true); soubor phpxml.php (pozor, implicitně vyžaduje kódování utf-8): <?php header('content-type: text/xml'); // nový dokument XML $dom = new DOMDocument(); $knihy = $dom->createelement("knihy"); $dom->appendchild($knihy); $kniha = $dom->createelement("kniha"); $knihy->appendchild($kniha); $autor = $dom->createelement("autor"); $kniha->appendchild($autor); $autortext = $dom->createtextnode("rastislav Škultéry"); $autor->appendchild($autortext); $titul = $dom->createelement("titul"); $kniha->appendchild($titul); $titultext = $dom->createtextnode("javascript"); $titul->appendchild($titultext); $kniha = $dom->createelement("kniha"); $knihy->appendchild($kniha); $autor = $dom->createelement("autor"); $kniha->appendchild($autor); $autortext = $dom->createtextnode("cristian Darie"); $autor->appendchild($autortext); $titul = $dom->createelement("titul"); $kniha->appendchild($titul); $titultext = $dom->createtextnode("ajax a PHP"); $titul->appendchild($titultext); $kniha = $dom->createelement("kniha"); $knihy->appendchild($kniha); $autor = $dom->createelement("autor"); $kniha->appendchild($autor); $autortext = $dom->createtextnode("rudolf Pecinovský"); $autor->appendchild($autortext); $titul = $dom->createelement("titul"); $kniha->appendchild($titul); $titultext = $dom->createtextnode("návrhové vzory"); $titul->appendchild($titultext); $xmlstring = $dom->savexml(); // výstup řetězce echo $xmlstring; 16.2.2011 11/18 Ajax
?> 8. Práce s MySQL definice dat potřebných pro připojení k databázi připojení k databázi načtení dat z databáze vytvoření souboru xml pomocí php a DOM z dat získaných z databáze 9. Ověřování formulářových dat pomocí AJAXu dříve ověřování na straně serveru po odeslání formuláře pomocí php nebo na straně klienta pomocí JavaScriptu pomocí AJAXu lze reagovat na událost, kdy libovolné pole formuláře ztratí fokus (onblur) hodnota pole pak bude odeslána na server, který ověří data a vrátí výsledek pokud má klient zkázáno používat JavaScript, kontrola pomocí AJAXu se neprovede vždy je proto nezbytné provedení finální kontroly na straně serveru Princip kontroly dat pomocí AJAXu Zdroj obrázku (autor Petr Láslo ): http://programujte.com/?akce=clanek&cl=2008081900-ajax-7-lekce Bezpečnost vůči vláknům asynchronní požadavek na server se vykoná pokaždé, když uživatel opustí nějaké pole pokud se uživatel rychle přesune přes několik vstupníchpolí nebo je-li spijení se serverem pomalé, může se stát, že objekt XMLHttpRequest je ještě zaměstnán čekáním na odpověď předchozího požadavku výsledkem může být chyba vedoucí k ukončení aplikace 16.2.2011 12/18 Ajax
tento problém můžeme řešit několika způsoby: vytvoříme pokaždé novou instanci XMLHttpRequest (může snížit výkon serveru) uložíme zprávu do fronty a odešleme ji později (zachovává se pořadí zpráv) naplánujeme po uplynutí nějaké doby automatický pokus o vytvoření nového požadavku (nezachovává pořadí zpráv) zprávu ignorovat Příklad 1 validace formuláře: vytvoříme formulář s těmito položkami: přezdívka jméno příjmení e-mail. prohlížeči musíme zakázat ukládání dat do cache: <meta http-equiv="pragma" content="no-cache" /> <meta http-equiv="cache-control" content="no-cache, must-revalidate" /> <meta http-equiv="expires" content="0" /> ukazatel nastavíme na první položku formuláře: <body onload="document.getelementbyid('nick').focus()"> k odpálení požadavku použijeme událost onblur <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="cs"> <head> <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" /> <meta http-equiv="content-language" content="cs" /> <meta http-equiv="pragma" content="no-cache" /> <meta http-equiv="cache-control" content="no-cache, must-revalidate" /> <meta http-equiv="expires" content="0" /> <meta name="generator" content="pspad editor, www.pspad.com" /> <meta name="author" content="all: Petr 'plasmo' Láslo; mailto: plasmo@plasmo.cz; web: http://plasmo.cz" /> <script src="js.js" type="text/javascript"></script> <title>registrace uživatele</title> </head> <body onload="document.getelementbyid('nick').focus()"> <fieldset> <legend>registrace uživatele</legend> <form action="#" method="post"> <table border="0"> <tr> <td><label for="nick">nick:</label></td> <td><input type="text" name="nick" id="nick" value="" onblur="vytvorpozadavek(this.id,this.value)" /></td> <td><div id="nickzprava"></div></td> </tr> <tr> <td><label for="jmeno">jméno:</label></td> <td><input type="text" name="jmeno" id="jmeno" onblur="vytvorpozadavek(this.id, this.value)" /></td> <td><div id="jmenozprava"></div></td> </tr> <tr> <td><label for="prijmeni">přijmení:</label></td> <td><input type="text" name="prijmeni" id="prijmeni" onblur="vytvorpozadavek(this.id, this.value)" /></td> <td><div id="prijmenizprava"></div></td> </tr> <tr> 16.2.2011 13/18 Ajax
<td><label for="email">e-mail:</label></td> <td><input type="text" name="email" id="email" onblur="vytvorpozadavek(this.id, this.value)" /></td> <td><div id="emailzprava"></div></td> </tr> </table> </form> </fieldset> </body> </html> soubor async.js bude obsahovat opět tyto funkce a proměnné: var xmlhttp = createxmlhttprequestobject(); // uchovává instanci XMLHttpRequest var cache = new Array(); // třída Array JavaScriptu může sloužit jako fronta, pomocí metod push() a shift() do ní přidáváme a z ní odebíráme. V případě, že bude objekt xmlhttp zaneprázdněný, uložíme požadavek do fronty a počkáme, až bude mít xmlhttp na tyto požadavky čas function vytvorxmlhttprequestobject() {... // vytvoří instanci XMLHttpRequest function vytvorpozadavek() {... // vytváří požadavek na server function zmenapozadavku() {... // volá se při změně stavu HTTP požadavku, pomocí XML zajistí komunikaci se scriptem na straně serveru funkce vytvorpozadavek() bude přebírat dva parametry: id prvku a hodnotu prvku funkce bude kontrolovat existenci prvku id, pokud se kontrola vyhodnotí jako pravda, přidá požadavek do fronty přidání podmínky do části try, díky které vytvoříme požadavek jen v případě, že xmlhttp nemá zrovna nic na práci a zároveň jen tehdy, když fronta není prázdná další změnou je použití metody xmlhttp.setrequestheader("content-type","application/x-www-form-urlencoded"); objektu XHR pro nastavení MIME typů poslední malou změnou je předání cache jako parametru metody xhr.send(cachevstup);. Funkce bude vypadat následovně: /* vytváří požadavek na server */ function vytvorpozadavek(id,hodnota){ if(xmlhttp) { if(id){ //zakoduji hodnoty id = encodeuricomponent(id); hodnota = encodeuricomponent(hodnota); //vložím hodnoty do fronty cache.push("id="+id+"&hodnota="+hodnota); try{ //pokračovat budu jen v případě že cache není prázdná a objekt XHR nemá co na práci if((xmlhttp.readystate == 4 xmlhttp.readystate == 0) && cache.length > 0){ //z cache načtu další hodnotu var cachevstup = cache.shift(); xmlhttp.open("post","./validace.php",true); xmlhttp.setrequestheader("content-type","application/x-www-form-urlencoded"); xmlhttp.onreadystatechange = zmenapozadavku; xmlhttp.send(cachevstup); catch(e){ alert("nelze se připojik k serveru:\n" + e.tostring()); else alert("funkce \"precitsoubor()\": chybí objekt XMLHttpRequest"); 16.2.2011 14/18 Ajax
funkce zmenapozadavku() opět přečte dokument XML a zobrazí jej na webové stránce obsah funkce se změní jen přidáním: settimeout("vytvorpozadavek();", 500); /* funkce se volá při změně stavu HTTP požadavku */ function zmenapozadavku() { // pokračuj, je-li proces kompletní if (xmlhttp.readystate == 4) { // pokračuj pouze, je-li status HTTP "OK" if (xmlhttp.status == 200) { try { // zpracování odpovědi ze serveru zpracujodpovedserveru(); settimeout("vytvorpozadavek();", 500); catch(e) { alert("chyba čtení odpovědi: " + e.tostring()); else { // zobraz zprávu o stavu alert("problém s daty: " + xmlhttp.statustext); nezmění se ani funkce zpracujodpovedserveru() změní se funkce novyobsahhtml(xmlresponse) /* získání nového obsahu html ze souboru xml zaslaného serverem */ function novyobsahhtml(xmlresponse) { // získá element dokumnentu XML xmlroot = xmlresponse.documentelement; odpoved = xmlroot.getelementsbytagname("odpoved")[0].firstchild.data; stav = xmlroot.getelementsbytagname("stav")[0].firstchild.data; id = xmlroot.getelementsbytagname("id")[0].firstchild.data; zprava = document.getelementbyid(id+"zprava"); //alert(odpoved+" "+id+" "+zprava); zprava.innerhtml = stav; soubor validace.php nahradí soubor phpxml.php přibudou: hlavičky, které zamezí ukládání dat do cache logika pro ověření zadaných údajů, kontrola probíhá nejdřív dle id prvku rozhodneme, který prvek budeme kontrolovat (zda nick, jméno,...), pak přiřadíme hodnoty proměnným $hodnota a $zprava <?php header("expires: Wed, 23 Dec 1980 00:30:00 GMT"); header("last-modified:".gmdate("d, d M Y H:i:s")." GMT"); header("cache-control: no-cache, must-revalidate"); header("pragma: no-cache"); switch ($_REQUEST['id']) { case "nick": 16.2.2011 15/18 Ajax
//pokud nick obsahuje hodnotu vracím 1 == true jinak 0 == false if($_request['hodnota']){ $hodnota = 1; $zprava = "OK"; else{ $hodnota = 0; $zprava = "Musíte zadat nick!"; break; case "jmeno": if(empty($_request['hodnota'])){ $hodnota = 0; $zprava = "Musíte zadat jméno!"; else{ $hodnota = 1; $zprava = "OK"; break; case "prijmeni": if(empty($_request['hodnota'])){ $hodnota = 0; $zprava = "Musíte zadat přijmení!"; else{ $hodnota = 1; $zprava = "OK"; break; case "email": if(!eregi("^[a-z0-9_.-]+@([a-z0-9_-]+\.)+[a-z]{2,4$",$_request['hodnota'])){ $hodnota = 0; $zprava = "E-mailová adresa musí být v platném tvaru!<br />"; else{ $hodnota = 1; $zprava = "OK"; break; //výstup je XML dokument, proto odešlu správný mime-type header("content-type: text/xml"); //tvořím nový XML $xml = new DOMDocument("1.0","utf-8"); //vytvočím kořenový element validace $validace = $xml->createelement("validace"); $xml->appendchild($validace); $vysledek = $xml->createelement("vysledek"); //vytvorim element odpoved a vložím do něj data $odpoved = $xml->createelement("odpoved"); $odpoveddata = $xml->createtextnode($hodnota); $odpoved->appendchild($odpoveddata); //vytvorim element zprava a vložím do něj data $stav = $xml->createelement("stav"); $stavdata = $xml->createtextnode($zprava); $stav->appendchild($stavdata); //vytvorim element id a vložím do něj data $id = $xml->createelement("id"); $iddata = $xml->createtextnode($_request['id']); $id->appendchild($iddata); $vysledek->appendchild($odpoved); $vysledek->appendchild($stav); 16.2.2011 16/18 Ajax
$vysledek->appendchild($id); $validace->appendchild($vysledek); //uložím XML výstup $vystup= $xml->savexml(); //zobrazím echo $vystup;?> 16.2.2011 17/18 Ajax
Příklad 2: napíšeme formulář pro vstup dat: uživatelské jméno jméno a příjmení pohlaví datum narození, zvlášť měsíc - den - rok (select) e-mail zaškrtávací políčko, že klient souhlasí odesílací tlačítko budeme implementovat frontu zpráv FIFO tabulka uživatelé user_id user_name v pomocném souboru si nastavíme hodnoty některých pomocných polí pohlaví měsíce pole $_SESSION V příkladu 2 budeme pomocí PHP i AJAXu ověřovat: uživatelské jméno nesmí být už v databázi pole pro jméno nesmí být prázdné musí být vyplněno pohlaví musí být vybrán měsíc narození kotrola platného dne narození (1 až 31) kontrola platného roku narození (1900 až 2005) kontrola dnů podle měsíců kontrola e-mailové adresy telefonní číslo odpovídá tvaru xxx xxx xxx musí být zatrženo. že se klient seznámil s podmínkami použití 16.2.2011 18/18 Ajax