Permalänk

Behöver hjälp med JavaScript

Hej! Försöker göra att ett program med hjälp av Javascript + html som tar in data (nummer) från en HTML text box - nämligen Celsius - som sedan skall konvertera numret till motsvarande Fahrenheit och visa det i en Alert() box. Jag försöker och försöker men det blir ändå fel. Funktionen convertFahr() körs DIREKT när man browsern körs UTAN att man trycker på knappen. Och det händer ingenting när man fyller i ett tal i tal-boxen och trycker på knappen. (scripet är rätt kopplat till html-filen)

Vad är det jag har missat? Lägger upp html + Javascript

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <label>Mata in Celcius-grader</label> <input id="databox" type="number" /><br /><br /> <button id="celcius"> Farenheit</button> <script src="secondMet.js"></script> </body> </html>

var inData = document.getElementById("databox").value; var sendCel = document.getElementById("celcius"); sendCel.addEventListener('click', convertFahr(inData)); function convertFahr(value) { var conversion = value * (9/5) + 32; alert(conversion); }

Permalänk
Medlem

Du behöver en funktion som hämtar och returnerar inData, annars hämtas det så fort sidan scriptet körts. Personligen brukar jag använda onClick på knappar för jag tycker det ger en överskådligare blick över vad som körs när man läser HTML-koden. Men skulle, om du vill behålla eventlistener'n, testa ändra till:

sendCel.addEventListener("click", function(){getValue()});

där getValue har din första rad kod och sen bara kallar vidare på på convertFarh() med celsius som parameter.

Visa signatur

Neon
Citera mig om du vill ha svar!

Permalänk
Skrivet av Neonxz:

Du behöver en funktion som hämtar och returnerar inData, annars hämtas det så fort sidan scriptet körts. Personligen brukar jag använda onClick på knappar för jag tycker det ger en överskådligare blick över vad som körs när man läser HTML-koden. Men skulle, om du vill behålla eventlistener'n, testa ändra till:

sendCel.addEventListener("click", function(){getValue()});

där getValue har din första rad kod och sen bara kallar vidare på på convertFarh() med celsius som parameter.

Vår lärare gillar INTE alls att man kör onClick via HTML-koden "Man ska liksom hålla isär JavaScript och HTML"

Ska prova ditt förslag. Tack för hjälpen!

Permalänk

Du måste wrappa din funktion i en ytterligare, anonym funktion:
http://stackoverflow.com/questions/2373995/javascript-addeven...

Exempel: http://jsfiddle.net/mwg2ffw7/

Permalänk
Medlem
Skrivet av DiAMONDBACK:

Vår lärare gillar INTE alls att man kör onClick via HTML-koden "Man ska liksom hålla isär JavaScript och HTML"

Ska prova ditt förslag. Tack för hjälpen!

haha, smaken är som baken. Men utöver onClick håller jag med, inga script-taggar i HTML-koden

Visa signatur

Neon
Citera mig om du vill ha svar!

Permalänk
Medlem

1. Använd form element och lägg in din kod i det.
2. Använd sedan document.querySelector() för att "fånga" ditt form.
3. Lägg till en onsubmit på ditt form (glöm inte e.preventDefault i den funktionen) och skriv din kod i denna funktion.

Permalänk
Hedersmedlem

Sidonotiser:

Skrivet av DiAMONDBACK:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml">

Första raden bra, då den i praktiken säger att vi kör HTML5 vilket rent krasst är vad man gör idag. Andra raden dålig, då den samtidigt försöker säga att vi kör XHTML, vilket, tja, man inte längre gör . Till och med W3C har övergivit sina XHTML-planer. Du kan med gott samvete ersätta den raden med `<html>`, och faktum är att den faktiskt är helt valbar enligt specifikationen, men det är många som känner sig mer bekväma när den är på plats.

Om er lärare explicit har sagt att ni måste koda någon sorts utdaterad hybrid-XHTML så må det vara hänt, men… I nuläget är det i alla fall fel, då XHTML kräver en XHTML-doctype.

När du strippar specifikationen av XHTML-namnrymden så kan du även slänga konceptet med "självstängande" taggar, dvs de taggar som du avslutar med ` />` vilket ej heller längre behövs.

Mindre att skriva, mer korrekt och modernt: alla vinner!

Skrivet av DiAMONDBACK:

<label>Mata in Celcius-grader</label>

Celsius!

Skrivet av DiAMONDBACK:

<button id="celcius"> Farenheit</button>

Och Fahrenheit!

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Skrivet av phz:

Sidonotiser:

Första raden bra, då den i praktiken säger att vi kör HTML5 vilket rent krasst är vad man gör idag. Andra raden dålig, då den samtidigt försöker säga att vi kör XHTML, vilket, tja, man inte längre gör . Till och med W3C har övergivit sina XHTML-planer. Du kan med gott samvete ersätta den raden med `<html>`, och faktum är att den faktiskt är helt valbar enligt specifikationen, men det är många som känner sig mer bekväma när den är på plats.

Om er lärare explicit har sagt att ni måste koda någon sorts utdaterad hybrid-XHTML så må det vara hänt, men… I nuläget är det i alla fall fel, då XHTML kräver en XHTML-doctype.

När du strippar specifikationen av XHTML-namnrymden så kan du även slänga konceptet med "självstängande" taggar, dvs de taggar som du avslutar med ` />` vilket ej heller längre behövs.

Mindre att skriva, mer korrekt och modernt: alla vinner!

Celsius!

Och Fahrenheit!

Fick raden med XHTML från VS, och den var inte ens beställd Och tack för stavningskontroll hehe

Permalänk

En sak som jag inte förstår: Varför avfyras eventet (funktionen "convertFahr()") trots att man man via ...

sendCel.addEventListener('click', convertFahr(inData));

... har en 'click'? Ska inte funktionen endast avfyras när man trycker på knappen?

var sendCel = document.getElementById("celcius");

Permalänk
Medlem
Skrivet av DiAMONDBACK:

En sak som jag inte förstår: Varför avfyras eventet (funktionen "convertFahr()") trots att man man via ...

sendCel.addEventListener('click', convertFahr(inData));

... har en 'click'? Ska inte funktionen endast avfyras när man trycker på knappen?

var sendCel = document.getElementById("celcius");

Funktionen körs eftersom du anropar den. Metoden addEventListener tar en funktion som parameter, men du har gett den resultatet av att köra convertFahr. Full Strike har redan gett dig lösningen på detta.

Permalänk
Hedersmedlem
Skrivet av DiAMONDBACK:

En sak som jag inte förstår: Varför avfyras eventet (funktionen "convertFahr()") trots att man man via ...

sendCel.addEventListener('click', convertFahr(inData));

... har en 'click'? Ska inte funktionen endast avfyras när man trycker på knappen?

var sendCel = document.getElementById("celcius");

`addEventListener` fungerar helt enkelt så. Andra argumentet är inte vad som ska utföras när aktionen triggar, utan en "lyssnare" som kommer kallas med ett enda speciellt argument (som beskriver händelsen i sig) när aktionen triggar. Att den triggar direkt när sidan laddas är för att `addEventListener` utvärderar det andra argumentet för att kunna binda till det objektet: om man skriver ett fullständigt funktionsanrop så kommer den utföra just detta fullständiga funktionsanrop och sedan binda till det om funktionen returnerar, vilket i detta fallet är, tja, inget av värde.

Om din funktion inte hade behövt ta ett specifikt invärde så hade den kunnat anges som ett funktionshandtag utan att kallas. Hade du modifierat ditt JavaScript en smula och i stället skrivit:

var sendCel = document.getElementById("celcius"); sendCel.addEventListener('click', convertFahr); function convertFahr() { var inData = document.getElementById("databox").value; var conversion = inData * (9/5) + 32; alert(conversion); }

så hade det fungerat. Notera hur `convertFahr` nu inte tar formulärvärdet som argument (nu har jag inte explicit angett något argument trots att `addEventListener` kommer skicka med ett, men Javascript är minst sagt generöst i hur man får kalla funktioner) och hur avläsningen av indata sker i funktionen, och inte utanför. Avläsningen måste på något sätt upprepas varje gång funktionen kallas; annars kommer dess värde ständigt vara värdet när sidan laddades, vilket inte vore speciellt intressant här. Jag anger även funktionsnamnet `convertFahr` utan paranteser som argument till `addEventListener` — med paranteser säger vi att vi vill kalla på funktionen, men vi vill här bara ge den som ett funktionsobjekt.

Om anonyma funktioner, funktionshandtag, objekt, etc., känns som alltför mycket magi så är det kanske främst att acceptera till en början och lära sig proceduren som ett "idiom", för att med tiden lära sig mer.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Skrivet av cfj:

Funktionen körs eftersom du anropar den. Metoden addEventListener tar en funktion som parameter, men du har gett den resultatet av att köra convertFahr. Full Strike har redan gett dig lösningen på detta.

Men vad är då syftet med att fylla i 'click" i detta fall?

addEventListener(String type, argument)

String type säger mig inte mycket.

EDIT: Hann skriva och posta innan jag läste phz114's inlägg

Permalänk
Skrivet av phz:

`addEventListener` fungerar helt enkelt så
Om din funktion inte hade behövt ta ett specifikt invärde så hade den kunnat anges som ett funktionshandtag utan att kallas. Hade du modifierat ditt JavaScript en smula och i stället skrivit:

var sendCel = document.getElementById("celcius"); sendCel.addEventListener('click', convertFahr); function convertFahr() { var inData = document.getElementById("databox").value; var conversion = inData * (9/5) + 32; alert(conversion); }

Japp, gjorde detta istället. Logiken blev mycket tydligare för mig.

Men jag ska anstränga mig för att lära mig mer om anonyma funktioner

Permalänk
Hedersmedlem
Skrivet av DiAMONDBACK:

Japp, gjorde detta istället. Logiken blev mycket tydligare för mig.

Men jag ska anstränga mig för att lära mig mer om anonyma funktioner

När vi ändå är här så skulle jag vilja ytterligare faktorera om koden en smula:

// Elementväljare var getCel = document.getElementById("databox"); var sendCel = document.getElementById("celcius"); // Metoder function convertFahr() { var inData = getCel.value; var conversion = inData * (9/5) + 32; alert(conversion); } // Händelser sendCel.addEventListener('click', convertFahr);

Jag har inte gjort mycket, men jag har flyttat ut elementväljarkoden `document.getElementById("databox")` utanför funktionen. När denna kod körs så går webbläsaren igenom sidans struktur ("DOM-träd") och letar upp detta element. Eftersom elementet är samma oavsett hur många gånger du kallar på funktionen så är det onödigt att inuti funktionen varje gång leta reda på fältet i DOM-trädet. Genom att lägga det utanför så görs detta en enda gång, och kanske framför allt så strukturerar vi upp koden i tre tydliga delar (som jag också markerat med kommentarer i koden för övertydlighets skull ):

  • elementväljare

  • metoder

  • händelser

där jag också ändrat ordning på de sista två i koden för att få saker mer logiskt följande.

"Tricket" med att använda en anonym funktion som callback till `addEventListener` är faktiskt lite av en styggelse, skulle jag säga. Det uppmanar till dålig separation av distinkta områden i koden. Dessutom gör det ju saker som återanvändning av kod problematisk, och det frestar lätt en programmerare till att kopiera och klistra från den icke-återanvändningsbara koden i den anonyma funktionen snarare än att skriva funktioner på en centraliserad plats där man kanske även kan abstrahera gemensamma delar ytterligare ett steg. Som ett ytterligare argument så kan det vara hjälpsamt (åtminstone inte sämre) för debuggning att separara kod bättre.

Det kan nämnas att på grund av hur `addEventListener` är uppbyggd så kan man ibland vara tvungen att använda en intermediär anonym funktion för att skicka med argument till en lyssnare, men ofta (alltid?) går det att faktorera på andra sätt, och dessutom går det alltid att låta denna intermediära funktion vara ett minimalt anrop så att man i vilket fall sköter logiken i en separat sektion.

Ytterligare mindre notiser:

  • När `addEventListener` kallar på en lyssnare (dvs när händelsen triggats) så skickas det automatiskt med ett "händelse"-argument. Vi kan förtydliga och fånga detta genom att lägga till ett inargument till `convertFahr()`. Vi använder det inte här, men det är ett bra idiom att ta med sig.

  • `convertFahr()` låter som en funktion som konverterar till Fahrenheit — men den överraskar lite eftersom den även tar data från ett visst fält och slänger upp en `alert`-ruta. Jag skulle konceptuellt vilja separera dessa steg, så att `convertFahr()` verkligen bara tar ett Celsiusgradantal som inargument och ger tillbaka ett Fahrenheitgradantal. Funktionen som presenterar saker kan heta något annat.

  • Funktionsnamn — det finns ofta väldigt liten anledning att förkorta och göra saker mindre direkt läsbara. Varför `convertFahr` och inte `convertFahrenheit`? Eller `convertToFahrenheit`? Eller `convertCelsiusToFahrenheit` (för funktionen konverterar ju inte exempelvis Kelvin)? Eller kanske bara `celsiusToFahrenheit`, för "verbet" känns rätt inbakat då.

Med dessa ändringar får vi:

// Elementväljare var celsius = document.getElementById('databox'); // "databox" är inte ett så beskrivande namn; tänk ut något bättre. var convert = document.getElementById('celcius'); // Ändra stavningen på objekt-ID ;-) . // Metoder function celsiusToFahrenheit(degreeCelsius) { return degreeCelsius * 9/5 + 32; } function presentFahrenheit(event) { var degreeCelsius = celsius.value; var degreeFahrenheit = celsiusToFahrenheit(degreeCelsius); alert(degreeFahrenheit); } // Händelser convert.addEventListener('click', presentFahrenheit);

Variabelnamnen är inte "perfekta", men det kan vara en poäng i att lämna lite frågor att fundera på själv. Är `celsius` och `convert` bra namn på elementen? Är det logiskt att knappen som konverterar till Fahrenheit heter "celcius" (sic)? Varför/varför inte? Varför blandade originalkoden 'strängar' och "strängar" — är det någon skillnad på apostrofer och citationstecken när strängar definieras? Spelar det någon roll här? Etc.

En annan sak att ta med sig är att det "i verkligheten" oftast inte är en dygd att skriva kod så kompakt som möjligt, utan snarare att skriva så läsbart som möjligt för någon som är van vid fältet. Det innebär att använda idiom och vanliga strukturer för att överraska en läsare (vilket inkluderar dig själv, kanske någon månad senare) så lite som möjligt, vilket även innefattar att inte exempelvis låta en funktion som heter `convertFahr` göra en massa andra saker som man inte skulle förvänta sig. För den som oroar sig för filstorlek och liknande så använder man i stället externa program som exempelvis Closure Compiler som fixar detta automatiskt.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Skrivet av phz:

Massa text

Tack snälla för din tid och engagemang!