Just curious:
My code works if I compare a number string (e.g. '10') to an integer (10), using the comparison operator ==
.
But if I convert the string to an integer with parseInt()
and compare to integers with the strict comparison operator ===
it fails – not immediately – once you start messing with the parameters (select menus).
The same code will work as expected without parseInt() and with comparison operators as in (time == 5)
.
Code that fails:
const productSelect = document.querySelector('#product')
let productValue = document.querySelector('#product').value
const prodTimeSelect = document.querySelector('#prodTime')
let prodTime = parseInt(document.querySelector('#prodTime').value)
const text = document.querySelector('.textoutput')
// Find start cost
let findStartCost = function(time) {
if (time === 5) {
return startCost = 2000
} else if (time === 10) {
return startCost = 1500
} else if (time === 20) {
return startCost = 1000
}
}
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
// Update text if product changes
productSelect.addEventListener('change', function(e) {
productValue = e.target.value
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
})
// Update text if production time changes
prodTimeSelect.addEventListener('change', function(e) {
prodTime = e.target.value
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
})
<h3>Select Product</h3>
<select id="product">
<option value="1">Product 1</option>
<option value="2">Product 2</option>
<option value="3">Product 3</option>
<option value="4">Product 4</option>
<option value="5">Product 5</option>
</select>
<h3>Select production time</h3>
<select id="prodTime">
<option value="5" selected="selected">5 days</option>
<option value="10">10 days</option>
<option value="20">20 days</option>
</select>
<p class="textoutput"></p>
Code that works:
const productSelect = document.querySelector('#product')
let productValue = document.querySelector('#product').value
const prodTimeSelect = document.querySelector('#prodTime')
let prodTime = document.querySelector('#prodTime').value
const text = document.querySelector('.textoutput')
// Find start cost
let findStartCost = function(time) {
if (time == 5) {
return startCost = 2000
} else if (time == 10) {
return startCost = 1500
} else if (time == 20) {
return startCost = 1000
}
}
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
// Update text if product changes
productSelect.addEventListener('change', function(e) {
productValue = e.target.value
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
})
// Update text if production time changes
prodTimeSelect.addEventListener('change', function(e) {
prodTime = e.target.value
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`
})
<h3>Select Product</h3>
<select id="product">
<option value="1">Product 1</option>
<option value="2">Product 2</option>
<option value="3">Product 3</option>
<option value="4">Product 4</option>
<option value="5">Product 5</option>
</select>
<h3>Select production time</h3>
<select id="prodTime">
<option value="5" selected="selected">5 days</option>
<option value="10">10 days</option>
<option value="20">20 days</option>
</select>
<p class="textoutput"></p>
Inside the listener, when you do
prodTime = e.target.value
This retrieves the changed value, but the .value
of an HTMLElement will always be a string. So when you pass that string to findStartCost
with findStartCost(prodTime)
, your conditions:
if (time === 5) {
return startCost = 2000
} else if (time === 10) {
return startCost = 1500
} else if (time === 20) {
return startCost = 1000
}
always fail because the parameter time
is always a string, not a number, so it'll never be ===
to a number.
==
, in contrast, implicitly casts its operands when comparing, but it's unpredictable if you haven't memorized all the different possibilities, so it shouldn't be used.
Use ===
and explicitly cast the values yourself:
prodTimeSelect.addEventListener('change', function(e) {
prodTime = Number(e.target.value);
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`;
})
Also, better not to implicitly create global variables - there's no need for a startCost
variable, you can just return the plain value in findStartCost
.
You may also make the code less repetitive by having just a single function that retrieves the values from the selects and populates the text.
const productSelect = document.querySelector('#product');
const prodTimeSelect = document.querySelector('#prodTime');
const text = document.querySelector('.textoutput');
// Find start cost
let findStartCost = function(time) {
if (time === 5) {
return 2000;
} else if (time === 10) {
return 1500;
} else if (time === 20) {
return 1000;
}
}
const updateText = () => {
const productValue = productSelect.value;
const prodTime = Number(prodTimeSelect.value);
text.textContent = `The product number is #${productValue} and the production time is ${prodTime} days. Includes a start cost of ${findStartCost(prodTime)}.`;
};
updateText();
productSelect.addEventListener('change', updateText);
prodTimeSelect.addEventListener('change', updateText);
<h3>Select Product</h3>
<select id="product">
<option value="1">Product 1</option>
<option value="2">Product 2</option>
<option value="3">Product 3</option>
<option value="4">Product 4</option>
<option value="5">Product 5</option>
</select>
<h3>Select production time</h3>
<select id="prodTime">
<option value="5" selected="selected">5 days</option>
<option value="10">10 days</option>
<option value="20">20 days</option>
</select>
<p class="textoutput"></p>