Introduktion till XmlHttp
Förord
Dagens webbapplikationer blir allt mer sofistikerade, och vi vill göra dem allt mer lika vanliga applikationer. Hittills har vi varit begränsade till att ladda om sidan när vi vill ändra datan, alternativt ladda allt genast från början. Att ladda allt från början är i vissa fall möjligt, i andra fall mer eller mindre omöjligt eller åtminstone väldigt ineffektivt. Fortfarande sätter html samt http en del begränsningar på vad man kan göra, men i och med XmlHttp har vi som webbutvecklare fått friare händer.XMLHTTP
XmlHttp :: vad är det?
XmlHttp är ett sätt att ladda och skicka xml data mellan klient och server, utan att behöva ladda om hela sidan. Detta främst via http kommandona GET och POST. Kommunikationen kan vara antingen synkron* eller asynkron* beroende på behov. Klienten får sedan denna data i form av ett DOM träd.
Tidigare då?
Att skapa dynamiska webbappliationer har tidigare varit svårare, alternativen har varit att antingen ladda om sidan allt eftersom (med medföljande blinkeffekt), ladda all data på förhand (kan vara tungrott) eller ladda data i en gömd iframe med hjälp av javascript (även här får vi blinkeffekter i statusfältet på vissa webbläsare). Så det har alltså inte varit helt omöjligt, men XmlHttp utgör en klar förbättring.
DOM :: Document Object Model
Eftersom XMLHTTP returnerar data i form av ett DOM träd, kan det vara på sin plats med en snabb genomgång av hur dokument objekt modellen fungerar. Vad är då DOM? Jo, DOM är en W3C (World Wide Web Consortium) standard för att hantera och manipulera xml baserade dokument. För att hantera (X)html dokument finns även HTML DOM som är ett superset av den generella DOM modellen.Alla objekt i modellen kallas Noder. Det finns ett antal olika nodtyper, men dom absolut vanligaste är Element (taggar i källkoden), Attribut samt Text noder.
Dokumentet representeras som ett träd av noder. Trädet returneras som ett Dokument objekt som har ett rotelement, (för ett xhtml dokument är denna rot nod elementet). I dokument objektet finns även funktionalitet för att skapa nya noder. Noderna är relaterade till varandra som en familj, en nod kan ha en förälder, syskon och/eller barn. Den kanske mest kända DOM funktionen är getElementById, som hämtar ett element baserat på dess id. Trädet kan manipuleras genom att sätta till, ta bort eller flytta element i trädet. Användbara funktioner för detta är appendChild, removeChild, getAttribute, setAttribute samt document.createElement och document.createTextNode.
Ett exempel kan kanske vara på sin plats:
baz
I detta simpla xml dokument har vi rotelementet foo, detta har barnelementet bar, och bar har också ett barn, ett text nod som innehåller texten baz. Om vi ser på det från andra hållet så är foo förälder till bar. Härav följer att för att få fram texten baz när vi har elementet bar (i variabeln barElem) barElem.firstChild.value. Texten finns alltså som innehåll i första barnet.
XmlHttp :: Kompatibilitet
I en perfekt värld så skulle ju alla tillverkare ha implementerat samma API på samma sätt, men alla som kommit i kontakt med webbutveckling är sorgligt medvetna om att så inte är fallet. Microsoft implementerar XmlHttp i form av ett ActiveX object, Microsoft.XMLHTTP eller MSXML2.XMLHTTP beroende på vilken version av MSXML som är installerat. Gecko däremot har XmlHttp funktionalitet direkt inbyggt som ett XMLHttpRequest objekt.Microsoft:
Gecko (Mozilla, Firefox, Netscape, ...) och Safari:
API:na är relativt lika, trots en del skillnader.
Ifall vi vill använda asynkron laddning så behöver vi skapa och registrera en callback som kallas varje gång statusen för vår begäran (request) ändras. Denna callback kan användas som sådan för både IE och Gecko.
function callback() {
if (req.readyState == 4) {
// färdig laddad
// DOM trädet finns i req.responseXML
}
}
Ladda ner xml dokumentet data.xml á la IE:
var req = new ActiveXObject("MSXML2.XMLHTTP");
req.onreadystatechange = callback;
req.open("GET", "data.xml", true);
req.send();
..och enligt Gecko familjen:
var req = new XMLHttpRequest();
req.onreadystatechange = callback;
req.open("GET", "data.xml", true);
req.send(null);
Exempel applikation :: bakgrund
För att visa hur detta fungerar i praktiken så har jag valt att som exempel visa en applikation för att rösta på favoritlåtar. Låtnamnen laddas in först efter att användaren har valt favoritartist. Datan för den här applikationen, dvs. artister och låtnamn, tog jag från ett antal skivor som jag råkade ha liggande på skrivbordet.Bakgrund: Vi vill inte skicka all data åt användaren direkt, i verkligheten kan detta vara onödigt mycket extra data. Däremot vill vi ladda datan som användaren behöver så transparent som möjligt, utan att sidan laddas om och blinkar till.
Vi vill göra sidan efter konstens alla regler och bara använda standard metoder. (Även om de facto standarder som .innerHTML ibland är trevligare att arbeta med.)
För att gömma bort skillnader i API:n så har jag använt Sarissa som är ett öppet cross-platform bibliotek för bland annat xmlhttp. Detta är naturligtvis inte nödvändigt, men man slipper lite enklare undan.
Exempel applikation :: implementation
För att välja artist väljer vi att använda radio knappar, och använder onclick händelsen för att ladda in information om låtarna.
I html koden ovan är alltså kansas-songs.xml namnet på den xml fil som innehåller låtnamnen för Kansas.
För att få det att fungera måste vi ännu skriva javascript funktionen loadSongs. Ifall vi använder sarissa kan vår loadSongs se ut ungefär som följande.
function loadSongs(elem) {
var oDomDoc = Sarissa.getDomDocument();
oDomDoc.async = true;
oDomDoc.onreadystatechange = ...
oDomDoc.load(elem.value);
}
Vi instantierar sarissa, meddelar att vi vill ladda asynkront. onreadystatechange är en callback som kallas när oDomDoc ändrar status, vi återkommer till den. Eftersom vi skickar med this till vår callback pekar alltså elem på elementet, och dess value attribut är ju filnamnet vi vill ladda.
Formatet på xml filen är valbart, jag har valt att göra det så här:
Kansas
the best of kansas
Carry on Wayward Son
Point of Know Return
...
Åter igen till vår callback,
0 Kommentarer