I have 2 lists (conversion from kilometers to miles etc.). When I'm trying to use input value to calculate (so "X * 1.609" for kilometers to miles) I have an error NaN.
const inputPlace = parseInt(document.getElementById("inputPlace").value);
const config = {
"kilometers": {
"miles": inputPlace * 1.609,
"yards": "Convert km to yd",
"feet": "Convert km to ft",
"inches": "Convert km to in"
},
"meters": {
"miles": "Convert m to mi",
"yards": "Convert m to yd",
"feet": "Convert m to ft",
"inches": "Convert m to in"
},
"centimeters": {
"miles": "Convert cm to mi",
"yards": "Convert cm to yd",
"feet": "Convert cm to ft",
"inches": "Convert cm to in"
},
"milimeters": {
"miles": "Convert mm to mi",
"yards": "Convert mm to yd",
"feet": "Convert mm to ft",
"inches": "Convert mm to in"
}
}
document.getElementById("btn").addEventListener("click", function(){
const metricValue = document.getElementById("metric").value;
const impValue = document.getElementById("imperial").value;
document.getElementById("aaa1").innerHTML = config[metricValue][impValue].toFixed(2);
});
<input type="number" id="inputPlace">
<select name="metric" id="metric">
<option value="kilometers">km</option>
<option value="meters">m</option>
<option value="centimeters">cm</option>
<option value="milimeters">mm</option>
</select>
<select name="imperial" id="imperial">
<option value="miles">mi</option>
<option value="yards">yd</option>
<option value="feet">ft</option>
<option value="inches">in</option>
</select>
<button id="btn">Click</button>
<p id="aaa1">Placeholder</p>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
(Please only look at first example - km to mi) How to fix it?
CodePudding user response:
Well, this one is simple. In the first line of your code, you are getting the value of the input, which is a blank string (the user hasn't entered anything yet! You're executing that line once the page loads), which when you try to convert to an int
results in "Not a Number". Instead, you should get the value of the number when you press the click
button, not once the page loads (you also have to create a function to dynamically calculate the value):
function calc(value) {
// creating a function to re-calculate the value
const config = {
"kilometers": {
"miles": value * 1.609,
"yards": "Convert km to yd",
"feet": "Convert km to ft",
"inches": "Convert km to in"
},
"meters": {
"miles": "Convert m to mi",
"yards": "Convert m to yd",
"feet": "Convert m to ft",
"inches": "Convert m to in"
},
"centimeters": {
"miles": "Convert cm to mi",
"yards": "Convert cm to yd",
"feet": "Convert cm to ft",
"inches": "Convert cm to in"
},
"milimeters": {
"miles": "Convert mm to mi",
"yards": "Convert mm to yd",
"feet": "Convert mm to ft",
"inches": "Convert mm to in"
}
}
return config;
}
document.getElementById("btn").addEventListener("click", function() {
const metricValue = document.getElementById("metric").value;
const impValue = document.getElementById("imperial").value;
const inputPlace = parseInt(document.getElementById("inputPlace").value.replaceAll(",", "").replaceAll(" ", ""));
document.getElementById("aaa1").innerHTML = calc(inputPlace)[metricValue][impValue].toFixed(2); // calling a function that returns an object instead of just using the object
});
<input type="number" id="inputPlace">
<select name="metric" id="metric">
<option value="kilometers">km</option>
<option value="meters">m</option>
<option value="centimeters">cm</option>
<option value="milimeters">mm</option>
</select>
<select name="imperial" id="imperial">
<option value="miles">mi</option>
<option value="yards">yd</option>
<option value="feet">ft</option>
<option value="inches">in</option>
</select>
<button id="btn">Click</button>
<p id="aaa1">Placeholder</p>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
I think you've misunderstood my last answer a little bit. There are 4 main problems with the code:
- The values stored in
config
were supposed to be methods - You're calling
toFixed
on what is essentially a method without every actually executing the method to get a result - You're reading the value of the input before the user had a chance to enter anything.
- If you want to support the user entering decimals use
parseFloat
notparseInt
const config = {
"kilometers": {
"miles": v => v * 1.609,
"yards": "Convert km to yd",
"feet": "Convert km to ft",
"inches": "Convert km to in"
},
"meters": {
"miles": "Convert m to mi",
"yards": "Convert m to yd",
"feet": "Convert m to ft",
"inches": "Convert m to in"
},
"centimeters": {
"miles": "Convert cm to mi",
"yards": "Convert cm to yd",
"feet": "Convert cm to ft",
"inches": "Convert cm to in"
},
"milimeters": {
"miles": "Convert mm to mi",
"yards": "Convert mm to yd",
"feet": "Convert mm to ft",
"inches": "Convert mm to in"
}
}
document.getElementById("btn").addEventListener("click", function() {
const metricValue = document.getElementById("metric").value;
const impValue = document.getElementById("imperial").value;
const inputPlace = parseFloat(document.getElementById("inputPlace").value);
const fn = config[metricValue][impValue];
document.getElementById("aaa1").innerHTML = fn(inputPlace).toFixed(2);
});
<input type="number" id="inputPlace">
<select name="metric" id="metric">
<option value="kilometers">km</option>
<option value="meters">m</option>
<option value="centimeters">cm</option>
<option value="milimeters">mm</option>
</select>
<select name="imperial" id="imperial">
<option value="miles">mi</option>
<option value="yards">yd</option>
<option value="feet">ft</option>
<option value="inches">in</option>
</select>
<button id="btn">Click</button>
<p id="aaa1">Placeholder</p>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
NOTE: The above will only work with kilometers-miles selected as thats the only one with a valid function as the value!