Övningar i JavaScript del 6 I dessa övningar tar vi upp två saker: Öppna ett nytt fönster ch hämta data från glbala variabler i dkumentet i föregående fönster. Läsa in data ifrån XML-filer med tekniken Ajax. Dessa båda delar behandlar vi i övningarna var för sig, men kan naturligtvis ckså kmbineras. 1. Dkument i övningsmappen På labratinens webbsida kan du ladda ner en zip-fil med övningsmaterial. Då du packar upp den får du en mapp med ett antal filer. kurser.htm, script_kurser.js, style.css Dessa filer är en webbsida sm visar ett frmulär med ett antal kryssknappar (checkbx) för några kurser. I frmuläret ska man välja kurser ch sedan klicka på knappen för att visa valda kurser. Då öppnas ett nytt fönster med ett dkument sm visar vilka kurser sm valts. Prgramkden för att sammanställa valda kurser ch sedan öppna det nya fönstret ska ligga i filen script_kurser.js ch ska skrivas i övningarna. kurslista.htm, script_kurslista.js, style.css Detta är sidan sm öppnas i det nya fönstret. I filen script_kurslista.js ska du i övningarna skriva kden för att hämta data från det föregående fönstret ch presentera valda kurser. Filen style.css är ganska enkel ch är densamma för alla webbsidr. litteratur.htm, script_litteratur.js, style.css Denna webbsida läser in XML-filer från mappen curses. En fil läses in för att få en lista på de kurser sm finns ch utifrån denna ska det skapas en lista med länkar (nclick) sm anrpar en funktin för att läsa in en annan XML-fil med en litteraturlista för vald kurs. curses Denna mapp innehåller en XML-fil (curselist.xml) med kurskder ch kursnamn för ett antal kurser. Dessutm finns det en fil för varje kurs med en litteraturlista i XMLfrmat. I de första övningarna kmmer du att använda de två första grupperna van, dvs sidrna kurser.htm ch kurslista.htm, så börja med att titta igenm dessa HTML-dkument ch tillhörande js-filer. 2. Sidan med kurserna Här finns ett frmulär med ett antal kryssknappar, där man markerar kurser. Då man klickar på knappen "Visa valda kurser" ska en funktin anrpas, för att gå igenm alla knappar ch se vilka sm är valda. Texten för de valda knapparna (kurserna) ska sparas i en array ch sedan ska filen kurslista.htm öppnas i ett nytt fönster. Öppna filerna ch gå igenm dem Öppna filen kurser.htm ch script_kurser.js i din editr. Öppna ckså kurser.htm i webbläsaren I kurser.htm finns ett frmulär med en input-tagg för varje kurs. Kursernas kd ch namn finns i span-taggar, så att de sedan kan hämtas ut. Det finns ckså en knapp med id="shwbtn". 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 1
I script_kurser.js finns en init-funktin sm anrpas på händelsen nlad. I denna tas det fram en referens till frm-taggen. Till knappen "shwbtn" kpplas en händelsehanterare för nclick, sm anrpar funktinen shwselectedcurses. Denna funktin finns ckså i filen, men är ännu så länge endast ett skal. Det finns ckså en funktin kallad newwindw ch tillhörande glbala variabel windvar. Detta är exakt samma knstruktin sm i föreläsning F14, så se beskrivning där. Funktinen shwselectedcurses Du ska nu påbörja denna funktin, för att gå igenm alla input-taggar. Skriv in följande kd i funktinen: functin shwselectedcurses() { var inputtags, spantag, i; inputtags = frmtag.getelementsbytagname("input"); fr (i=0; i<inputtags.length; i++) { if (inputtags[i].checked) { alert("kurs " + i + " vald"); Variabeln inputtags är en array med referenser till alla input-taggar. Dessa input-taggar genmlöps i en lp. I lpen finns en if-sats sm kntrllerar egenskapen checked, för att se m knappen är vald. I så fall skrivs det ut ett meddelande med alert. Denna alert ska sedan ersättas med annan kd, men tas nu med, för att du ska kunna kntrllera att du genmlöper knapparna krrekt ch hittar de sm är valda. Välj några kurser ch klicka sedan på knappen "Visa valda kurser". Ersätt alert-satsen i if-satsen med följande kd: if (inputtags[i].checked) { spantag = inputtags[i].parentnde.getelementsbytagname("span")[0]; alert(spantag.innerhtml); Utifrån input-taggen går vi upp ett steg i strukturen med parentnde ch kmmer då till label-taggen (se HTML-kden). Där söker vi span-taggen med geteelementsbytagname ch får en array sm vi indexerar med 0, för att få referensen till den första ch enda span-taggen. I alert-satsen skriver vi nu ut innehållet i span-taggen, dvs kursens kd ch namn. Spara kurserna i en array För att samla ihp kurserna ch sedan få över dem till det fönster sm ska öppnas, så ska kurserna (dvs span-taggens innehåll) sparas i en array i en glbal variabel. Inför en glbal variabel för kurserna högst upp i js-filen, under de andra glbala variablerna: var curselist; Initiera variabeln, genm att skapa en ny tm array i init-funktinen: functin init() { curselist = []; 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 2
I if-satsen i funktinen shwselectedcurses byter du ut alert-satsen mt följande: if (inputtags[i].checked) { spantag = inputtags[i].parentnde.getelementsbytagname("span")[0]; curselist.push(spantag.innerhtml); Innehållet i span-taggen sparas sist i arrayen i variabeln curselist. Sist i funktinen, dvs efter lpen, lägger du till en alert-sats, för att kunna testa: functin shwselectedcurses() { alert(curselist); De kurser du väljer ska visas i meddelandet med alert. Öppna ett nytt fönster Ersätt den sista alert-satsen med ett anrp till funktinen newwindw: functin shwselectedcurses() { newwindw(600,600,"kurslista.htm"); Filen kurslista.htm öppnas i det nya fönstret, men kurserna visas ännu inte. Du ska nu skriva kden för det. 3. Sidan med valda kurser I dkumentet sm öppnas i det nya fönstret ska variabeln curselist hämtas från det gamla dkumentet, så att valda kurser kan skrivas ut. Öppna filerna ch gå igenm kden Öppna filerna kurslista.htm ch script_kurslista.js i din editr. I kurslista.htm finns en ul-tagg med id="curses", där valda kurser ska läggas in sm litaggar. I script_kurslista.js finns en init-funktin sm tar fram en referens till taggen med id="curses" samt ett anrp till funktinen createcurselist. Det är denna sistnämnda funktin sm du nu ska skriva, men först ska du se till att få över data från det gamla dkumentet. Den glbala variabeln curselist Glbala variabler kan hämtas från det gamla dkumentet, eftersm det frtfarande är öppet i huvudfönstret. Skriv in följande kd högst upp i script_kurslista.js, bland de glbala variablerna: var curselist = windw.pener.curselist; Med windw.pener refererar man tillbaks till det gamla fönstret. Där hämtas variabeln curselist. Vi sparar den här i en ny glbal variabel med samma namn i det nya dkumentet. Det är inte nödvändigt att ha samma namn på variabeln, men det är lättare att se sambanden mellan dem, m vi väljer samma namn. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 3
Funktinen createcurselist I denna funktin går vi igenm curselist (sm är en array) ch lägger till en li-tagg för varje element. Lägg in följande kd i funktinen: functin createcurselist() { var i; fr (i=0; i<curselist.length; i++) { cursestag.innerhtml += "<li>" + curselist[i] + "</li>"; Vi går igenm curselist i en lp. För varje varv i lpen lägger vi till taggar för li ch texten från curselist i taggen sm refereras av cursestag, dvs ul-taggen i HTML-filen. Gå tillbaks till fönstret med kurserna (kurser.htm) i webbläsaren. Välj några kurser ch klicka på knappen "Visa valda kurser". Det nya fönstret öppnas då ch de kurser du valt visas i en lista. 4. Välj andra kurser Om du stänger det nya fönstret, sedan väljer andra kurser ch klickar på knappen igen, så öppnas fönstret med kurslistan. Men nu visas både de kurser du tidigare valt ch de nya kurserna. Det berr på att variabeln curselist inte tömts. Lägg till en rad för att tömma curselist i början av filen shwselectedcurse i filen script_kurser.js: functin shwselectedcurses() { var inputtags, spantag, i; curselist.length = 0; Denna rad tömmer variabeln curselist, så att den sedan endast innehåller de kurser sm läggs till i lpen i funktinen. Välj några kurser ch klicka på knappen för att öppna det nya fönstret. Stäng sedan fönstret ch välj några andra kurser ch klicka på knappen igen. Det ska då endast vara de nya kurserna sm visas i listan. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 4
5. Läsa in XML-kd med Ajax Medieteknik Vi ska nu övergå till att titta på Ajax. Så stäng alla filer både i din editr ch i webbläsaren ch öppna sedan de nya filerna. Studera XML- filerna Börja med att studera XML-filerna. Öppna filen curselist.xml i din editr. Denna fil innehåller en kurslista med en curse-tagg för varje kurs. Denna fil ska sedan läsas in till webbsidan ch utifrån den ska det skapas ett antal HTML-taggar med kurserna. Öppna någn av filerna med litteraturlista, t.ex. filen literature1me101.xml Alla litteraturlistr är strukturerade på samma sätt sm i labratin L7. De innehåller kursnamn ch reference-taggar för alla böcker eller annan litteratur i kursen. Då man väljer en kurs i listan över kurser på webbsidan, ska mtsvarande litteraturlista läsas in. Vi tar alltså inte in alla listr på en gång, utan endast de sm väljs ch en i taget. Ajax körs över http- prtkllet För att kunna testa prgrammet med Ajax, så måste filerna ligga på en server, antingen en lkal server på din datr eller på en server på Internet (t.ex. FirstClass). Använder du datrerna i labbsalen, så måste du använda det sistnämnda alternativet. Det innebär att du måste ladda upp filerna i ditt webbutrymme på servern, varje gång du vill testa. Öppna filerna för webbsidan ch gå igenm kden Öppna filerna litteratur.htm ch script_litteratur.js i din editr. Filen litteratur.htm innehåller en ul-tagg med id="curses", där kurslistan från curselist.xml ska läggas sm li-taggar. Det finns ckså en div-tagg med id="selectedcurse", där vald litteraturlista ska läggas in. I filen script_litteratur.js finns en init-funktin sm initierar två glbala variabler med referenser till de båda HTML-taggarna. 6. Kurslistan Du ska nu göra ett Ajax-anrp, för att läsa in kurslistan. Vi använder här kd på samma frm sm i exemplen i föreläsning F14. Begär filen curselist.xml Skriv in följande funktin i filen script_litteratur.js: functin requestcurses() { var request; if (XMLHttpRequest) { request = new XMLHttpRequest(); else if (ActiveXObject) { request = new ActiveXObject("Micrsft.XMLHTTP"); else {return false; request.pen("get","curses/curselist.xml",true); request.send(null); request.nreadystatechange = functin () { if ( (request.readystate == 4) && (request.status == 200) ) getcurses(request.respnsexml); ; Denna funktin skapar ett request-bjekt ch öppnar filen curselist.xml. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 5
Till request-bjektet kpplas händelsen nreadystatechange ch en namnlös funktin sm kntrllerar readystate. Då readystate är 4 är begäran klar ch filen (m den fanns) har överförts till webbläsaren. För att veta m filen fanns, kntrllerar vi ckså status. Är det 200 (OK), fanns filen. Då anrpas funktinen getcurses. Lägg ckså in ett anrp av requestcurses i init-funktinen: functin init() { requestcurses(); Testa Ajax- anrpet Lägg över filerna (HTML-filen, js-filen ch mappen curses med XML-filerna) i ditt webbutrymme på servern ch öppna HTML-filen i webbläsaren. Kör du istället en lkal server på din datr, så kan du öppna den via den. Öppna Firebug i undre halvan av fönstret i webbläsaren. Kntrllera i menyn Knsl att "Visa XMLHttpRequests" är förbckat, välj annars det alternativet. Ladda m sidan i webbläsaren. I knslen bör du då se att det skett ett GET-anrp av curselist.xml ch att kden är 200 OK. Om du inte får fram det, så får du kntrllera din kd ch att alla filer ligger på rätt plats. Du får ckså ett felmeddelande då funktinen getcurses anrpas, eftersm du ännu inte skrivit den. Funktinen getcurses I funktinen getcurses ska du läsa av den XML-kd sm kmmit in med Ajax. Den finns här i parametern XMLcde. För att kmma åt de lika taggarna används getelementsbytagname, på samma sätt sm vi gjrt tidigare i HTML-kden, fast nu söker vi efter XML-taggar i XML-kden. Lägg in följande funktin i filen script_litteratur.htm: functin getcurses(xmlcde) { var cdes, titles, HTMLcde, i; cdes = XMLcde.getElementsByTagName("cde"); titles = XMLcde.getElementsByTagName("title"); HTMLcde = ""; // Add tags fr the curses fr (i=0; i<cdes.length; i++) { HTMLcde += "<li id='" + cdes[i].firstchild.data + "'>" + cdes[i].firstchild.data + " " + titles[i].firstchild.data + "</p>"; cursestag.innerhtml = HTMLcde; // Add event handlers curses = cursestag.getelementsbytagname("li"); fr (i=0; i<curses.length; i++) { curses[i].nclick = shwliteraturelist; Vi tar hela funktinen på en gång, så att du inte ska behöva ladda upp filerna så många gånger på servern. Men då du själv skriver en sådan här funktin, så gör du det kanske stegvis ch lägger in alert-satser, för att testa att du får fram rätt referenser ch data. Du bör öppna filen curses.xml ch jämföra med kden där, så att du ser vilken struktur vi går igenm ch vad taggarna heter. Vi tar först fram referenser till alla taggar med namnen cde ch title. Dessa ligger i en tagg kallad curse. Så vi hade istället kunnat ta fram referenser till curse-taggarna, gå 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 6
igenm curse i lpen ch i varje varv i lpen ta fram referenser till de underliggande cde ch title. Men i detta fall innehåller varje curse en exakt en cde ch exakt en title ch då kan vi ta fram referenser direkt till dem, så blir kden lite effektivare. I variablerna cdes ch titles får vi alltså arrayer med referenser till alla cde-taggar respektive titletaggar. I lpen ska vi sätta samman den HTML-kd sm ska läggas in i listan ch det gör vi i variabeln HTMLcde, så före lpen lägger vi in en tm sträng i den variabeln. Då kan vi sedan i varje varv i lpen lägga till ny kd. I varje varv i lpen skapas en li-tagg på frmen <li id="1me101">1me101 Webbdesign</li> Vi lägger alltså in kurskden både i ett id-attribut ch sm innehåll i taggen. Anledningen till att vi lägger in den i ett id-attribut är att vi sedan ska använda det då man klickar på taggen, men det kmmer i övning 7. Här ser vi ckså en sak sm skiljer, då man går igenm en XML-fil istället för en HTMLfil. Då vi tagit fram innehåll i en HTML-tagg har vi använt innerhtml, men i XML-filen fungerar inte det. Istället måste vi skriva firstchild.data. Med firstchild refererar man till textnden ch med data innehållet i den. Efter lpen refererar vi till cursestag sm är ul-taggen i HTML-filen ch då kan vi använda innerhtml ch där lägga in HTML-kden. Därefter går vi igenm alla li-taggar sm skapats ch lägger på en händelsehanterare för nclick. Ladda först upp de nya filerna på servern eller ladda m dem i din lkala server. XML-filen läses in ch listan med kurser visas. I Firebug blir det sedan fel, då händelsehanterarna ska läggas till, eftersm funktinen shwliteraturelist ännu inte finns. 7. Visa litteraturlista Då användaren klickar på en kurs, ska litteraturlistan för kursen läses in med Ajax från vald XML-fil. Funktinen shwliteraturelist Lägg till följande funktin: functin shwliteraturelist() { requestlist(this.id); Med this kmmer vi åt den li-tagg sm användaren klickade på. Där avläser vi idattributet, där vi sparade kurskden. Kurskden kmmer att behövas för att kunna referera till önskad XML-fil, så denna skickas sm parameter till funktinen requestlist. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 7
Funktinen requestlist Lägg till följande funktin: functin requestlist(cursecde) { var request; if (XMLHttpRequest) { request = new XMLHttpRequest(); else if (ActiveXObject) { request = new ActiveXObject("Micrsft.XMLHTTP"); else {return false; request.pen("get", "curses/literature" + cursecde + ".xml",true); request.send(null); request.nreadystatechange = functin () { if ( (request.readystate == 4) && (request.status == 200) ) getlist(request.respnsexml); ; Denna funktin är nästan likadan sm requestcurses, men här har vi en parameter, för att avgöra vilken fil sm ska läsas. Parametern används i pen-kmmandt, där url:en till filen sätts samman. Då XML-filen kmmit in, anrpas funktinen getlist. Kntrllera i Firebug att det görs ett Ajax-anrp till filen för den kurs du klickar på i listan. Sedan blir det fel, då getlist anrpas, eftersm funktinen ännu inte finns. Funktinen getlist Denna funktin läser in en XML-fil med en litteraturlista, så öppna en sådan XML-fil ch jämför med strukturen ch taggarna där. I detta exempel lägger vi inte in allt innehåll på webbsidan, utan nöjer ss med en del av det. Lägg in följande funktin i js-filen: functin getlist(xmlcde) { var cde, title, references, i, a, firstname, lastname, initial; cde = XMLcde.getElementsByTagName("cde")[0]; title = XMLcde.getElementsByTagName("title")[0]; selectedcursetag.innerhtml = "<h3>" + cde.firstchild.data + " " + title.firstchild.data + "</h3>"; references = XMLcde.getElementsByTagName("reference"); fr (i=0; i<references.length; i++) { selectedcursetag.innerhtml += "<p>"; authrs = references[i].getelementsbytagname("authr"); fr (a=0; a<authrs.length; a++) { firstname = authrs[a].getelementsbytagname("firstname")[0]; lastname = authrs[a].getelementsbytagname("lastname")[0]; initial = firstname.getattribute("initial"); selectedcursetag.innerhtml += lastname.firstchild.data + ", " + initial + "; "; title = references[i].getelementsbytagname("title")[0]; selectedcursetag.innerhtml += title.firstchild.data + "</p>"; I detta fall finns det endast en cde-tagg ch en title-tagg, så då referenserna tas fram till dem, indexerar vi med 0 med en gång, för att få första elementet i arrayerna sm ges av getelementsbytagname. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 8
Kurskden ch titeln skrivs sedan ut i en h3-tagg på webbsidan. Därefter tar vi fram en array med referenser till alla reference-taggar. Dessa går vi igenm i en lp. För varje varv i lpen, skapas en p-tagg med referensen. Det kan finnas flera författare ch därmed flera authr-taggar. Så dessa genmlöps ckså i en lp. I författarnas förnamn ska vi använda initialerna sm finns i attributet initial i taggen firstname. Attributets värde får vi fram genm att först referera till taggen ch sedan använda funktinen getattribute. Klicka på lika kurser, så ser du att vald litteraturlista visas. Slut I dessa övningar tg vi upp två saker: Öppna ett nytt fönster ch hämta data. Ett fönster öppnas med windw.pen() Vi refererar tillbaks till det gamla fönstret med windw.pener ch kan då hämta glbala variabler därifrån. Använd Ajax för att läsa in XML-filer. Ett request-bjekt skapas för att öppna önskad fil. I en funktin kntrllerar vi readystate, för att se när filen kmmit in. Vi avläser XML-kden med getelementsbytagname, på samma sätt sm vi tidigare använt funktinen för HTML-kd. För att avläsa innehållet i en XML-tagg använder vi firstchild.data. För att avläsa ett attribut använder vi funktinen getattribute. 2012-12-03 Rune Körnefrs (rune.krnefrs@lnu.se) 9