Övningar i JavaScript del 4 I dessa övningar ska du dels hantera ett frmulär ch dels arbeta med några textsträngar. 1. Dkument i övningsmappen Övningsmappen sm du laddar ner från labratinens webbsida innehåller exempel 4 från föreläsning F12. I denna labratin arbetar du vidare med det frmulär sm finns där. 2. Funktin för att beräkna kstnaden Du ska nu skriva funktinen för att beräkna kstnaden av de val sm användaren gör. Definiera funktinen ch anrpa den från knappen Skriv in följande funktin längst ner i script-filen: functin calculatecst() { Lägg in ett nclick-attribut i input-taggen för knappen "Beräkna kstnaden": <input type="buttn" value="beräkna kstnad" nclick="calculatecst()"> Tagg för resultat Resultatet av beräkningen ska skrivas i span-taggen med id="ttalcst", så skapa en referens till den i JavaScript-kden. Lägg till en glbal variabel högst upp i script-filen: var ttalcsttag; Initiera variabeln i funktinen init: functin init() { ttalcsttag = dcument.getelementbyid("ttalcst"); 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 1
Avläs menyn för antal nätter Menyn består av ett select-element med ett antal ptin-taggar. Man refererar till select-elementet ch avgör vilken ptin-tagg sm är vald. Sedan kan man avläsa value-attributet i den ptin-taggen. Lägg till följande rader i funktinen, för att avläsa antal nätter: functin calculatecst() { var nightoptin, nrofnights, rmprice, ttalcst, i, thevalue; nightoptin = frmtag.nights.selectedindex; nrofnights = Number(frmTag.nights.ptins[nightOptin].value); ttalcsttag.innerhtml = nrofnights; Ett antal lkala variabler införs. Just nu behövs endast de två första. Övriga behövs i kmmande övningar, men vi inför dem redan nu, så är det gjrt. Variabeln frmtag är initierad i funktinen init ch är en referens till frm-elementet i HTML-kden. I HTML-kden finns ett select-element med name="nights". Det innehåller ckså ett antal ptin-taggar. Med frmtag.nights får vi en referens till select-elementet. Observera att vi nu använder referens via namn istället för id. Egenskapen selectedindex är ett tal sm är index till det alternativ sm är valt i menyn. Index börjar på 0, för det första alternativet. Med frmtag.nights.ptins får vi en array bestående av alla ptin-taggar i menyn. Genm att indexera med det index sm tgs fram på föregående rad, får vi den ptintagg sm är vald. Där avläser vi value-attributet från HTML-kden. (Titta i HTMLdkumentet ch kntrllera att antal nätter är inlagda i alla ptin-taggars value-attribut.) Eftersm innehållet i value-attributet i första hand tlkas sm text, så knverterar vi till ett tal med Number. För att kntrllera att vi får fram rätt värde, så skriver vi ut antal nätter i taggen för ttal kstnad. Detta ska sedan ändras. Välj ett antal nätter i menyn ch klicka på knappen "Beräkna kstnad". Avläs radiknapparna för rumstyp Radiknapparna är ett antal input-taggar med type="radi". De hr ckså ett name-attribut med samma namn. Därmed grupperas de ch endast en av dem kan vara vald. Varje knapp har ckså en egenskap kallad checked, sm är true m knappen är vald, annars false. Utöka nu funktinen med följande rader: functin calculatecst() { var nightoptin, nrofnights, rmprice, ttalcst, i, thevalue; nightoptin = frmtag.nights.selectedindex; nrofnights = Number(frmTag.nights.ptins[nightOptin].value); fr (i=0; i<frmtag.rm.length; i++) { if (frmtag.rm[i].checked) { thevalue = frmtag.rm[i].value; rmprice = Number(theValue.split(",")[1]); break; ttalcsttag.innerhtml = rmprice; I HTML-kden har radiknapparna samma namn, rm. För att ta reda på vilken sm är vald, kan vi inte göra på samma sätt sm för menyn. I detta fall finns inget selectedindex. Istället får vi kntrllera knapp för knapp ch se m egenskapen checked är true. 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 2
Med frmtag.rm får vi en array med alla input-taggar med name="rm". Med egenskapen length får vi fram hur många det är. Därmed kan vi gå igenm dem i en frlp. I if-satsen kntrlleras aktuell knapp ch dess egenskap checked. Är den true, så har vi hittat den knapp sm är vald. Då avläser vi dess value-attribut från HTML-kden. Värdet är t.ex. "enkelrum,600" (se HTML-kden). Texten "enkelrum" finns med, eftersm vi vill ha med den, då frmulärets data skickas iväg för att göra beställningen. Men just nu vill vi endast ha priset, sm är tecknen efter kmmatecknet. Det får vi genm att dela upp strängen till en array med kmma sm skiljetecken. Det andra elementet (sm indexeras med 1) blir priset. Vi ser ckså till att det tlkas sm ett tal, genm att knvertera med Number. Då vi hittat den knapp sm är vald, behöver vi inte frtsätta i lpen, utan den avbryts med break. Utskriften i taggen för ttala kstnaden ändras nu till rmprice, så att vi kan kntrllera att vi får fram rätt värde. Avläs kryssknapparna för tilläggen Kryssknappar fungerar sm radiknappar, men man kan där välja flera alternativ eller inget, även m de har samma namn i name-attributet. Lägg till följande kd för att avläsa tilläggen: functin calculatecst() { fr (i=0; i<frmtag.extra.length; i++) { if (frmtag.extra[i].checked) { thevalue = frmtag.extra[i].value; rmprice += Number(theValue.split(",")[1]); ttalcst = nrofnights * rmprice; ttalcsttag.innerhtml = ttalcst + " kr"; Alla kryssknappar för tilläggen ha samma namn, extra. Därmed kan vi referera till dem sm en array ch gå igenm dem i en lp på samma sätt sm för radiknapparna. Men i detta fall kan flera knappar vara valda, så vi avbryter inte lpen, utan går igenm alla knappar. Även i detta fall består value-attributet av två delar, t.ex. "Internet,40", ch det är den andra delen sm är priset. Så vi tar ut det på samma sätt sm i föregående steg med rumspriset. För varje extra tillägg sm valts, ökar rumspriset, så det läggs till med +=. Kntrllera ckså m alternativet är aktivt eller ej Om du först valt enkelrum eller dubbelrum, går det välja sjöutsikt. Väljer du sedan familjerum, så gråmarkeras alternativet med sjöutsikt, men det är frtfarande valt ch kmmer därför med i priset. Vi måste alltså ckså testa egenskapen disabled för knapparna. 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 3
Lägg till ett test av disabled i if-satsen: functin calculatecst() { fr (i=0; i<frmtag.extra.length; i++) { if (frmtag.extra[i].checked &&!frmtag.extra[i].disabled) { thevalue = frmtag.extra[i].value; rmprice += Number(theValue.split(",")[1]); Observera utrpstecknet framför testet. Egenskapen disabled är true m knappen är inaktiv ch false m den är aktiv. Det är endast då den är aktiv, dvs disabled är false sm vi ska ta med den i beräkningen. Vi inverterar därför värdet med utrpstecknet, dvs det sm testas är att den inte är disabled. 3. Kntrll av frmuläret innan det skickas Då man klickar på submit-knappen inträffar händelsen nsubmit. Denna fångas upp i frm-taggen (se HTML-kden) ch funktinen checkfrm anrpas. I denna funktin finns redan en del kntrll av innehållet, men du ska nu fylla på med lite mer. Kntrllera att alla textfält är ifyllda Input-taggarna för textfälten har lika namn, så vi kan inte kmma åt dem sm en grupp på samma sätt sm menyn, radiknapparna ch kryssknapparna. Men vi kan mge dem med ett div-element ch via det kmma åt input-taggarna ch på så sätt referera till dem sm en array. Lägg till div-taggar, sm mger textfälten i HTML-kden: <div id="custmerdata"> <p><label>ankmstdatum:<br><input type="date" name="arrivaldate"></label></p> <p><label>namn:<br><input type="text" name="name"></label></p> <p><label>gatuadress:<br><input type="text" name="street"></label></p> <p><label>pstnummer:<br><input type="text" name="zipcde"></label></p> <p><label>ort:<br><input type="text" name="twn"></label></p> </div> Högst upp i script-filen lägger du till en glbal variabel: var custmertags; I init-funktinen lägger du till en initiering av variabeln: functin init() { custmertags = dcument.getelementbyid("custmerdata").getelementsbytagname("input"); Referensen görs först till div-taggen med id="custmerdata". Där refereras det sedan till alla input-taggar. Variabeln custmertags blir därmed en array med referenser till textfälten. 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 4
Kntrllera nu m textfälten är tmma. Lägg till följande kd i funktinen checkfrm: functin checkfrm() { fr (i=0; i<custmertags.length; i++) { if (custmertags[i].value == "") { alert("alla textfält måste vara ifyllda"); return false; return true; Om ett textfält är tmt (jämförs med en tm textsträng, två citatinstecken, utan någt mellan dem), ges ett felmeddelande ch funktinen avbryts med return false. Det returneras då false till nsubmit i frm-taggen ch frmuläret skickas ej. Om någt textfält är tmt, får du felmeddelandet. Om alla textfält är ifyllda, skickas frmuläret (i HTML-kden finns det inget i actin-attributet i frm-taggen, så det skickas ingenstans, men du ser att frmuläret töms). 4. Knvertera namn Du ska nu knvertera kundens namn, så att varje del i namnet skrivs med inledande versal ch resten med gemener. Vi gör detta i två steg. Dela upp namnet med blanktecken sm skiljetecken Knverteringen görs i en separat funktin, så skriv in följande funktin i script-filen: functin initialuppercase(wrd) { wrd = wrd.charat(0).tuppercase() + wrd.substring(1).tlwercase(); return wrd; Ordet sm ska knverteras kmmer in i parametern wrd. Det första tecknet tas ut med charat(0) ch det knverteras till en versal med tuppercase(). Tecknen från psitin 1 (dvs det andra tecknet) ch resten av strängen tas ut med substring(1). Denna sträng knverteras till gemener med tlwercase(). Skriv sedan in följande kd i funktinen checkfrm under den lp där dubbla blanktecken tas brt: functin checkfrm() { var name, twn, zipcde, dblspaceps, i, namearr, namearr2; namearr = name.split(" "); fr (i=0; i<namearr.length; i++) { namearr[i] = initialuppercase(namearr[i]); name = namearr.jin(" "); frmtag.name.value = name; Inför två nya lkala variabler. Variabeln namearr används här ch namarr2 kmmer att användas i nästa steg. 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 5
Kundens namn finns redan i variabeln name. Detta delas upp i en array, så att varje del sm åtskiljs av blanktecken blir varsitt element i arrayen. Denna array genmlöps i en lp. För varje del av namnet anrpas initialuppercase, för att knvertera till inledande versal. Efter lpen sätts arrayen samman till en sträng igen ch sm skiljetecken används ett blanktecken. Lämna fältet med pstnummer tmt, så skickas inte frmuläret iväg. Då blir innehållet kvar i frmuläret ch du kan se m knverteringen av namnet fungerar. Dubbelnamn med bindestreck Namnen kan ju ckså vara uppdelade med bindestreck, t.ex. Karl-Oskar. Med vanstående kd blir det Karl-skar. Så nu ska vi se till att även namnet efter bindestrecket får inledande versal. Lägg till en if-sats i lpen, så att fr-lpen blir: I if-satsen kntrlleras det m det finns ett bindestreck i namnet. Detta görs med indexof. Om bindestreck finns ger indexof psitinen för tecknet, annars -1. Vi är inte intresserade av vilken psitin det är, så vi kntrllerar bara m det är skilt från -1. Då finns det alltså ett bindestreck. Namnet i namearr[i] delas då upp i en array med bindestreck sm skiljetecken. Denna array sparas i namearr2. De båda delarna i namearr2 (dvs delarna indexerade med 0 ch 1) knverteras var för sig ch sätts samman med ett bindestreck till en ny sträng i namearr[i]. Om det inte finns någt bindestreck, så går vi in i else-delen ch utför knverteringen så sm tidigare. Slut I dessa övningar tg vi upp: functin checkfrm() { fr (i=0; i<namearr.length; i++) { if (namearr[i].indexof("-")!= -1) { namearr2 = namearr[i].split("-"); namearr[i] = initialuppercase(namearr2[0]) + "-" + initialuppercase(namearr2[1]); else namearr[i] = initialuppercase(namearr[i]); Referens till element i frmulär med hjälp av namnen i name-attributen. Referens till ptin-taggar i en meny. Referens till radiknappar. Referens till kryssknappar. Referens till flera input-taggar med hjälp av getelementsbytagname. Stränghantering med funktinerna: charat() substring() tlwercase() tuppercase() indexof() 2012-11-19 Rune Körnefrs (rune.krnefrs@lnu.se) 6