I'm told stackoverflow is the place to ask, so I'm hoping someone can guide me here. Long story short, I'm trying to learn Javascript. I learn things better in a probably odd way, for me to better get my head around something, I need to just create a problem and try and tackle it and learn what I need to do in order to achieve it.
However, what i've learned, clearly isn't right and i'm lost to what i'm doing wrong.
I'm trying to make a small form, with just 2 dropdown options. Depending on the two options selected, it will equate to a specific package. This will return and display the price of the package and provide the ID number of the package, which is displayed when the button is pressed.
I've added event handlers to run the function when changes are made, because if I don't, nothing updates.
But the function doesn't correctly change the variables, and whatever I did before, it actually did change the variables, but always the last ones in the 'else' statement, regardless of the chosen values.
If anyone can kindly show me where i'm going wrong, it would be greatly appreciated. I've tried following courses online and reading books about javascript, but I can't take it in, unless i'm trying to make something.
My HTML and javascript are as follows:
//Variables
var articles = document.getElementById("articles").value;
var wordCount = document.getElementById("wordCount").value;
var packPrice = "Choose a Package";
var packageID = "";
//Update the price when either input changes
articles.addEventListener("input", function (e) {
getPrice();
});
wordCount.addEventListener("input", function (e) {
getPrice();
});
//Sets the Price to Display & assigns the packageID
function getPrice() {
if(articles === "1" && wordCount === "500"){
packPrice = "£100";
packageID = "39";
}
else if (articles === "2" && wordCount === "500") {
packPrice = "£200";
packageID = "49";
}
else if(articles === "3" && wordCount === "500"){
packPrice = "£300";
packageID = "59";
}
else if(articles === "4" && wordCount === "500"){
packPrice = "£400";
packageID = "69";
}
else (articles === "1" && wordCount === "1000");{
packPrice = "£200";
packageId = "79";
}
};
//Displays Price of chosen Product
document.getElementById("packagePrice").innerHTML = packPrice;
//Submit button displays ID number
function selectPackage() {
alert(packageID);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="">
</head>
<body>
<div id="package">
<form target="_self">
<label for="articles">Number of Articles:</label>
<select id="articles" name="articles">
<option value="0">Select</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
<option value="4">Four</option>
</select> <br>
<label for="wordCount">Word Count:</label>
<select id="wordCount" name="wordCount">
<option value="0">Select</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</select>
<h2 id="packagePrice"></h2>
<input type="button" id="packageSubmit" value="Select Package" onclick="selectPackage();">
</form>
</div>
<script src="dropdown.js" async defer></script>
</body>
</html>
CodePudding user response:
You are missing an if
after the last else
in your javascript. You also added a semicolon after the parenthesis, which should not be there. Those are just syntax errors, now to fix bugs.
The variables articles
and wordCount
are only ever set once at the top of your code, so even if you change the drop downs, they are not updated. To fix this, you must move them into your getPrice
function.
As for why the packagePrice
header is never updated, it follows the same principle. You only ever set it once in your code, near the bottom. You must also move this line into the bottom of your getPrice
function
Your javascript should look like this
//Variables
var packPrice = "Choose a Package";
var packageID = "";
//Update the price when either input changes
document.getElementById("articles").addEventListener("input", function (e) {
getPrice();
});
document.getElementById("wordCount").addEventListener("input", function (e) {
getPrice();
});
//Sets the Price to Display & assigns the packageID
function getPrice() {
var articles = document.getElementById("articles").value;
var wordCount = document.getElementById("wordCount").value;
if(articles === "1" && wordCount === "500"){
packPrice = "£100";
packageID = "39";
}
else if (articles === "2" && wordCount === "500") {
packPrice = "£200";
packageID = "49";
}
else if(articles === "3" && wordCount === "500"){
packPrice = "£300";
packageID = "59";
}
else if(articles === "4" && wordCount === "500"){
packPrice = "£400";
packageID = "69";
}
else if (articles === "1" && wordCount === "1000") {
packPrice = "£200";
packageID = "79";
}
document.getElementById("packagePrice").innerHTML = packPrice;
};
//Displays Price of chosen Product
document.getElementById("packagePrice").innerHTML = packPrice;
//Submit button displays ID number
function selectPackage() {
alert(packageID);
};
CodePudding user response:
One approach is as follows:
//Variables
// here we've changed the code to *not* get the value, but to
// only get the element itself (we can retrieve the value
// later, from the element, if/when required):
let articles = document.getElementById("articles"),
wordCount = document.getElementById("wordCount"),
packPrice = "Choose a Package",
packageSubmit = document.querySelector('#packageSubmit');
// we've removed the definition of the packageID, since it's
// initialised to an empty String, and global variables are
// not something I like to rely on (they're too vulnerable
// to accidental changes); instead I added a hidden <input>
// to the HTML, and use the getPrice() function to update
// the value of that element.
//Sets the Price to Display & assigns the packageID
// we've moved the definition of the function so that it's
// defined earlier in the script than the place it is used:
let getPrice = function() {
let articleValue = articles.value,
wordCountValue = wordCount.value,
packPrice = `£${articleValue * 100}`,
// a simple calculation that appears to match the
// pattern of ascending package prices:
package = (wordCount.selectedIndex * 10) 29;
//Displays Price of chosen Product
// using textContent instead of HTML, since we're
// only updating the text, rather than adding elements:
document.getElementById("packagePrice").textContent = packPrice;
// here we use document.querySelector() along with a
// CSS selector to retrieve the element with the
// id of 'cache', and then set its value:
document.querySelector('#cache').value = package;
},
// button (not a submit button) displays the package number:
// using an Arrow function (since we're not using 'this'), to
// alert the value held in the element with the id of 'cache':
selectPackage = () => alert(document.querySelector('#cache').value);
//Update the price when either input changes
// you're trying (and failing) to bind an event-listener to a number,
// this won't work, they can only be bound to an EventTarget, so
// something that can receive events, such as an HTML element/node:
articles.addEventListener("input", getPrice);
wordCount.addEventListener("input", getPrice);
packageSubmit.addEventListener('click', selectPackage);
/* basic CSS reset, to remove default margins, padding
and force all elements to use the same base font-size,
and layout: */
*,
::before,
::after {
box-sizing: border-box;
font: normal 400 1rem / 1.5 sans-serif;
margin: 0;
padding: 0;
}
form {
/* using display: grid to improve the
aesthetics: */
display: grid;
/* setting a 0.5em gap between adjacent
columns and rows: */
gap: 0.5em;
/* setting the first column to be equal
to the max-width of the largest content
in that column, and the second to occupy
the remaining space: */
grid-template-columns: max-content 1fr;
/* providing a 1em margin above and below the
form while centering it on the horizontal
axis, in ltr and rtl languages: */
margin: 1em auto;
/* setting the width to be 80vw (viewport widths)
which is 80% of the width of the viewport,
except where that would be less than 30em
or when 80vw would be wider than 600px;
thereby capping the width to be 30em (minimum)
and 600px (maximum) but all other times at
80vw: */
width: clamp(30em, 80vw, 600px);
}
label {
/* placing the <label> elements in grid-column 1: */
grid-column: 1;
}
select,
button {
/* placing the <select> and <button> elements in
grid-column 2: */
grid-column: 2;
}
h2 {
/* increasing both font-weight and font-size of
the <h2> element(s): */
font-size: 1.5em;
font-weight: 700;
/* placing the elements in the grid, to occupy
all columns from the first (1) to the last (-1): */
grid-column: 1 / -1;
}
<div id="package">
<form target="_self">
<label for="articles">Number of Articles:</label>
<select id="articles" name="articles">
<!-- we've added both the disabled, and selected, attributes
to the first <option> since it seems to serve purely as
a label, and should not be selected by a user, but we
want the user to be able to select any of the other
options, so making this selected: -->
<option value="0" disabled selected>Select</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
<option value="4">Four</option>
</select> <br>
<label for="wordCount">Word Count:</label>
<select id="wordCount" name="wordCount">
<option value="0" disabled selected>Select</option>
<option value="500">500</option>
<option value="1000">1000</option>
<option value="1500">1500</option>
<option value="2000">2000</option>
</select>
<h2 id="packagePrice"></h2>
<button type="button" id="packageSubmit">Select Package</button>
<!-- a hidden <input> to cache the value of the packageID for
later retrieval: -->
<input type="hidden" id="cache" />
</form>
</div>
JavaScript:
- Arrow function expressions.
document.getElementById()
.document.querySelector()
.Element.innerHTML
.EventTarget.addEventListener()
.Node.textContent
.- Template-Literals.
CodePudding user response:
I believe the problem is that the values of the drop down boxes are never updated after you assign them. Your event listeners are set currently onto the .values of the elements, not on the elements themselves.
I would modify your code as follows:
Firstly, set variables to hold the element objects representing your drop-down lists as follows:
const articlesDropDown = document.getElementById("articles"); // the element object not its value
const wordCountDropDown = document.getElementById("wordCount"); // the element object not its value;
next, declare global variables to hold the values, and initialise them with the starting values:
let articles = articlesDropDown.value;
let wordCount = wordCountDropDown.value;
You might also call getPrice()
directly after these to display the starting/default conditions.
then, create event listeners for both variables to update when the drop-downs change, and call your function to display the results:
articlesDropDown.addEventListener('change', () => {
articles = articlesDropDown.value;
getPrice();
})
wordCountDropDown.addEventListener('change', () => {
wordCount = WordCountDropDown.value;
getPrice();
})
Your if-else
blocks look ok apart from the stray ;
but many developers prefer to use switch blocks when there are several cascading options. If you use switch
, remember to include a break
command after each condition or else you will end up with the default again.
Lastly, most js developers now use const
and let
to define variables, rather than var
. There's nothing wrong with var
but the scoping of let
is more versatile, and const
is useful to prevent inadvertant changes. You will definitely come across these so should get familiar with their use.
Good luck on your learning journey (for what it's worth, your approach of solving problems rather than doing countless exercises, is the way to go).