HTML form - value depends on two different drop-down menus - javascript

Hello javascript experts!
I'm a novice here, trying to create a script to add up membership fees on a website (I'm a volunteer). Any help is greatly appreciated.
I used this website: http://www.javascript-coder.com/javascript-form/javascript-calculator-script.phtml to set up my html.
It worked just fine (I set up 3 functions, one to calculate the membership price, another for the postage and the other the total amount due - I have not included them below but know they work fine).
UNTIL I realized that the value of postage (which I had calculated only using the first drop-down menu: id=country) was also dependant on the amount in the second drop down menu (the second drop-down menu's id: membership_type). That is to say, the postage is not only determined by country but also by membership type. I tried to set up a script that would vary the value of the postage depending on the value of the membership type but it isn't working.
I'm not a coder as you can tell so I've spent a lot of time looking for the correct way to do this but have come to a deadend....
var membership_prices = new Array();
membership_prices["regular"]=40;
membership_prices["student"]=24;
membership_prices["emeritus"]=24;
membership_prices["regularplus"]=62;
membership_prices["studentplus"]=46;
membership_prices["emeritusplus"]=46;
var extra_postage_cost = new Array();
extra_postage_cost["USA"]=0;
extra_postage_cost["Canada"]=0;
<!-- this is the part that needs work: Edited since original post -->
extra_postage_cost["Other_Country"]
if (document.getElementById('membership_type').value =="regular")
extra_postage_cost["Other_Country"]=8;
else if (document.getElementById('membership_type').value =="student")
extra_postage_cost["Other_Country"]=8;
else if (document.getElementById('membership_type').value =="emeritus")
extra_postage_cost["Other_Country"]=8;
else if (document.getElementById('membership_type').value =="regularplus")
extra_postage_cost["Other_Country"]=16;
else if (document.getElementById('membership_type').value =="studentplus")
extra_postage_cost["Other_Country"]=16;
else if (document.getElementById('membership_type').value =="emeritusplus")
extra_postage_cost["Other_Country"]=16;
else
extra_postage_cost["Other_Country"]=0;
<!-- end of what I believe needs work -->
Here is the rest of the code:
function getMembershipPrice ()
{
var membershipPrice=0;
var theForm = document.forms["membershipform"];
var selectedMembership = theForm.elements["membership_type"];
membershipPrice = membership_prices[selectedMembership.value];
return membershipPrice;
}
function getExtraPostagePrice ()
{
var extraPostagePrice = 0;
var theForm = document.forms["membershipform"];
var selectedPostage = theForm.elements["country"];
extraPostagePrice = extra_postage_cost[selectedPostage.value];
return extraPostagePrice;
}
function getAmountDue()
{
var amountDue = getMembershipPrice() + getExtraPostagePrice();
document.getElementById('amountDue').innerHTML ="Amount Due $"+amountDue;
}
In the drop-down menus themselves I have this kind of code inside the brackets for each drop-down menu:
select name="membership_type" id="membership_type" onchange="getAmountDue()"
select name="country" id="country" onchange="getAmountDue()"

I assume the country drop down is defaulted to USA. If this is the case, simply add an "onchange" event listener to the dropdowns that call a function to update the extra charge.
So instead of having an array object for extra postage, just have a variable extraPostage initially set to zero and update it when the drop downs change.
var extraPostage = 0;
function onSelectChange(){
var countrySelect = document.getElementById('countrySelect');
var typeSelect = document.getElementById('membership_type');
if(countrySelect.value != "Other Country"){
extraPostage = 0;
return;
}
else{
var type = typeSelect.value;
switch(type){
case "regular":
extraPostage = 8;
break;
case "student":
extraPostage = 8;
break;
case "emeritus":
extragPostage = 8;
break;
//keep going for each different possibility
}
}

You did good for being a self-proclaimed amateur. I think that you can probably more easily solve your problem with a multi-dimensional array so you can associate the membership prices with the corresponding postage:
var MEMBERSHIP = 0;
var POSTAGE = 1;
var membership_prices = new Array();
membership_prices["regular"] = [40, 8];
membership_prices["student"] = [24, 8];
membership_prices["emeritus"] = [24, 8];
membership_prices["regularplus"] = [62, 16];
membership_prices["studentplus"] = [46, 16];
membership_prices["emeritusplus"] = [46, 16];
Now, to access the membership price and postage price, if other country is selected, you can simply run:
membership_prices["regular"][MEMBERSHIP] // returns 40
membership_prices["regular"][POSTAGE] // returns 8
I used MEMBERSHIP and POSTAGE instead of 0 and 1 so it might make your code more readable when you're getting the values for the membership and the posting. Or if you prefer, you can simply access the inner array with the 0 and 1:
membership_prices["regular"][0] // returns 40
membership_prices["regular"][1] // returns 8

If I'm understanding what you're trying to do it looks like you were on the right track, but needed to invert how you're thinking about the logic in relation to the variable. You also had a few extra "s and {}s.
Try this in place of the code below <!-- this is the part that needs work: -->.
if (document.getElementById('membership_type').value =="regular")
extra_postage_cost["Other_Country"]= 8;
else if (document.getElementById('membership_type').value =="student")
extra_postage_cost["Other_Country"]= 8;
else if (document.getElementById('membership_type').value =="emeritus")
extra_postage_cost["Other_Country"]= 8;
else if (document.getElementById('membership_type').value =="regularplus")
extra_postage_cost["Other_Country"]= 16;
else if (document.getElementById('membership_type').value =="studentplus")
extra_postage_cost["Other_Country"]= 16;
else if (document.getElementById('membership_type').value =="emeritusplus")
extra_postage_cost["Other_Country"]= 16;
else
extra_postage_cost["Other_Country"]= 0;

Try this:
var otherCountryPostageCost = 0,
membershipType = document.getElementById('membership_type');
if (membershipType == "regular" || membershipType == "student" || membershipType == "emeritus"){
otherCountryPostageCost = 8;
} else if (membershipType == "regularplus" || membershipType == "emeritusplus") {
otherCountryPostageCost = 16;
}
extra_postage_cost["Other_Country"] = otherCountryPostageCost;

I'm a novice too :) I thought for some time the most readable way of adding other countries' extra postage, assuming there will be many, and concluded with the following:
extra_postage_cost["Country"] = [ (regular), (student), (emeritus) ]
Where each value in parentheses is a number. For example:
extra_postage_cost["Ostia"] = [10, 20, 30, 60, 60, 30];
For this to work we need to define some variables and functions. The idea is to link the numerical order of a type (student, regular) in membership_types to the numerical position in each of the extra postage cost arrays.
membership_types = ["regular", "student", "emeritus",
"regularplus", "studentplus", "emeritusplus"];
function membership_index(m_type) {
var index = -1;
for(var i = 0; i < membership_types.length; i++) {
if(m_type == membership_types[i]) {
index = i;
}
}
return index;
}
Then when retrieving, it's kinda ugly :( but we want to first address the country, then the numerical position for the cost, that matches the membership type.
extraPostage = extra_postage_cost[whichCountry][membership_index(whichMembership)];
The result is here : http://jsfiddle.net/TgdEW/
p.s. I think technically you're not creating arrays, but objects, so I declare variable_name = {}

Related

What's wrong with my Loop

I'm new in JavaScript and there is some thing wrong in my codes that I cannot find it! it is driving me crazy.
Ok, this is what I want to do, the user chooses how many poets worked together to write a poem. if the number is one or no number is entered the outcome is the same, that is, the user enters the Last name and the Initial of the poet and the function puts it in desired order, BUT when it is more than one poet (in this example it is 2) I want it to ask for the next poet's Last name and Initial, so I used array, but for some reason the result is just based on the first poet's details only, like this: Lname(0), Iname(0) & ,
and it doesn't ask for the second poet's LName and initial!
Please let me know what am I doing wrong!
var Initial, LastName, authors;
var num=1;
var Iname = [],Lname = [];
var index = 0;
num=bookForm.txtNumber.value;
num=Number(num);
if (num > 1) {
if (num == 2) {
while (index <= 1){
Iname[index] = bookForm.txtInitial.value;
Lname[index] = bookForm.txtLastName.value;
bookForm.txtInitial.value="";
bookForm.txtLastName.value="";
bookForm.txtInitial.focus();
index = index + 1;
}
authors = Lname[0]+", "+Iname[0]+" & "+Lname[1]+", "+Iname[1]+" "
}
}
else {
Initial = bookForm.txtInitial.value+" "
LastName = bookForm.txtLastName.value+", ";
authors = LastName+Initial;
}
It looks, you reinitialize value of field with
bookForm.txtInitial.value="";
bookForm.txtLastName.value="";
when you pass for the second time in your loop, the value is empty.

.length on array crashing when length is 1 (maybe issue with split)

I'm having trouble with this code. I've tried to troubleshoot it many times and seem to have isolated the issue, but can't figure out the cause.
If the variable called string is set to something in the form of "text v. text," the code runs fine and the first if-statement triggers the sentence. If the string contains text but no "v." i.e. nothing that meets the search separator value, the function fails and does not execute the second if-statement.
Link to Fiddle: http://jsfiddle.net/qsq4we99/
Snippet of code, there also would need to be a html div with ID "outputtext."
function brokenCode()
{
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
brokenCode();
In this simplified example there is no clear explanation why the search operations need to occur (they are there because in the real code they are needed... but something about them seems to be causing the problem (even in this simple example). If the two searches are removed, the code runs smoothly.
You can't start setting variables from the array without checking for length. Before setting findText1 & findText2, check to make sure the length of the array is greater than zero.
function brokenCode() {
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
if (number > 0) {
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
}
brokenCode();

JavaScript using isNaN to validate returns NaN

I have some code here that will make validations of whether or not the input from a text box is NOT an empty string and isNaN. When i do these validations on amounts entered, i would like it to add them up.. however when a user does not enter anything in one or more amount fields the program should just add entered fields. But instead i get NaN showing in the total field.
link to full code: http://jsfiddle.net/KxNqQ/
var $ = function (id) {
return document.getElementById(id);
}
var calculateBills = function () {
var myErrorFlag = "N";
for (i = 1; i <= 4; i++) {
AmountNumber = 'amount' + i;
AmountValue = $(AmountNumber).value;
if (AmountValue != "" && isNaN(AmountValue)) {
$(AmountNumber).style.color = "red";
myErrorFlag = "Y";
} else {
$(AmountNumber).style.color = "black";
myErrorFlag = "N";
}
}
if (myErrorFlag != "Y") {
var Amount = 0;
for (i = 1; i <= 4; i++) {
Amount += parseInt($('amount' + i).value,10);
}
$('total').value = Amount;
}
}
var clearFields = function () {
for (i = 1; i <= 4; i++) {
itemName = 'item' + i;
$(itemName).value = "";
}
for (i = 1; i <= 4; i++) {
amountName = 'amount' + i;
$(amountName).value = "";
}
$('total').value = "";
}
window.onload = function () {
$("clearfields").onclick = clearFields;
$("addbills").onclick = calculateBills;
}
I think you've got your requirements a little bit confused, or at the very least I was confused by them. So in order to answer your question, I'm going to rephrase the requirements so I understand them better. This is a useful exercise that I try to do when I'm not 100% sure of the requirements; if I can't get the requirements right, what's to say I'll get the code right?
So the requirements – as I understand them – are:
Given each amount input
When the input has a value
And that value is a number
Then add the value to the total
And make the input color black
But if the input does not have a value
Or that value is not a number
Then make the input color red
Going through your code, I can see a number of problems with it. First, I noticed that both AmountNumber and AmountValue are global variables, because they were not declared local with the var keyword. So before fixing our code, let's change that. Let's also change the variable names to something that more accurately describe what they are, hopefully making the code easier to understand:
var input = $('amount' + i);
var value = input.value;
Now, note that I chose to store the element in the input variable. This is so we don't have to look it up multiple times within the loop. Looking things up in the DOM can be expensive so we'll want to keep it to a minimum. There are other was to look up elements as well, such as getElementsByClassName, querySelector and querySelectorAll; those are left as an exercise for the reader to research and evaluate.
Next, in each iteration of the loop, you check that AmountValue is not a string and simultaneously is not a number:
if (AmountValue != "" && isNaN(AmountValue)) {
This will be true so long as AmountValue is truthy (which is the case for non-empty strings) and so long as isNaN thinks it's a number (which is the case for strings that contain numbers.) It really is rather confusing; if I understand your code correctly this clause is there to check for invalid input and if it is true should mark the input field red and set a flag. I.e. this is the but clause in the aforementioned requirements.
Let's rewrite this to be the when clause instead, we'll take care of the but later. Before we do that, let's look at the myErrorFlag. It's used – I think – to see whether all input is well formed and in that case, add it all up. Well, validation and summation can be done in one fell swoop, so let's get rid of the flag and sum the values while validating them. So we replace myErrorFlag with a total variable:
var total = 0;
Now, let's get back to our clause. The requirements say:
When the input has a value
And that value is a number
Then add the value to the total
In code, that should look something like this:
if (value && !isNaN(value)) {
total += parseInt(value, 10);
input.style.color = 'black';
}
There are a couple of things going on here. For one, the if statement has been turned on its head a bit from what it was. It first checks to see that value is truthy, then that it is a number. The second check can be a bit tricky to read, because it is essentially a double negation; in english it reads "is not not a number", i.e. "is a number". I'll leave it as an exercise for the reader to figure out whether there's a more easily understood way of writing this check.
Now what about the but clause in our requirements?
But if the input does not have a value
Or that value is not a number
Then make the input color red
Well, it's essentially the inverse of our previous statement, so let's simply add an else clause:
else {
input.style.color = 'red';
}
Because the requirements doesn't mention the total variable in this clause, it is simply ignored and doesn't show up in the end result.
Adding it all up (no pun intended) the code – with comments – looks like this:
var calculateBills = function () {
var total = 0;
for (i = 1; i <= 4; i++) {
// Given each amount input
var input = $('amount' + i);
var value = input.value;
if (value && !isNaN(value)) {
// When the input has a value
// And that value is a number
// Then add the value to the total
total += parseInt(value, 10);
// And make the input color black
input.style.color = 'black';
} else {
// But if the input does not have a value
// Or that value is not a number
// Then make the input color red
input.style.color = 'red';
}
}
$('total').value = total;
};
There are more things that could be learned from this to make for better code. For instance, this code will break if the number of inputs change, or if their id names change. This is because they are selected specifically by their IDs and as such, if those change then this code will no longer function.
Another potential issue is that we're setting inline styles on the inputs as we loop over them. This means that in order to keep this code up to date with the styling of the site, it'll have to change. Generally, mixing styling and functionality like this is not a good idea and should be avoided. One way of doing so is to use class names instead, and toggle these on and off. Incidentally, this could also help the previous problem I mentioned.
There are other problems as well, but we'll leave those for another day. Hope this helps!
Try this
var calculateBills = function () {
var Amount = 0;
for (i = 1; i <= 4; i++) {
var AmountElement = $('amount' + i),
AmountValue = AmountElement.value;
if (AmountValue != "" && !isNaN(AmountValue)) {
AmountElement.style.color = "red";
Amount += parseInt(AmountValue,10);
} else {
AmountElement.style.color = "";
}
}
$('total').value = Amount;
};
Demo
Anyway, instead of using elements with id like id="amount1", id="amount2", id="amount3", etc., you could use classes (e.g class="amount") and get them with .getElementsByClassName

using for loop and if statement to check id names with numbers

for (var i = 1; i < 81; i++){
if($(this).hasClass('member-'+i)){
('promote'+i) = true;
}
}
I have 80 droppable boxes. They each has an id called member-1, member-2, etc., when someone drags an item into the boxes, the variable will be turned to true and be passed to another function.
So far I found this is not working. I wasn't sure why. It is inside a droppable drop function.
since I have 80 boxes...I don't feel like typing them out manually.
Make promote an array, rather than 80 different variables. Then you can do:
var promote = [];
for (var i = 1; i < 81; i++){
if($(this).hasClass('member-'+i)){
promote[i] = true;
}
}
Much better would be to just see what classes do exist rather than testing for 81 different classes:
var matches, promotes = [], cls = this.className;
var regex = /member-(\d+)/g;
while (matches = regex.exec(cls)) {
// matches[1] contains the number from the member-xx class name
promotes.push(parseInt(matches[1], 10));
}
// promotes is an array that contain a list of the member-xx numbers that exist
// on this object

validate 2 dropdowns (only some combinations valid)

I am completely new to JavaScript.
I have size and color dropdowns on a page for users to order a product, but only certain combinations are available i.e. pink is the only color in large sizes.
I thought I'd make an array of allowed sizes and test the user input against these.
If the choice is invalid then I want a popup to tell the user why.
In the real world I'll use SQL & PHP to create the array of allowed choices, in the example below I've hard coded 3 valid choices for testing. Unfortunately the code below doesn't do anything.
I'm sure it's a simple newb mistake. I really don't know what I'm doing :)
Can somebody help me out?
The validation function is supposed to happen when user clicks the form submit...
<form id="form1" name="form1" method="post" onsubmit="return validate_form()"
action="cart.php">
Here's the function:
<script type="text/javascript">
function validate_form() {
var allowed = new Array();
allowed[0]="10,beige";
allowed[1]="10,black";
allowed[2]="10,pink";
var chosenColInd = document.getElementById("colID");
var chosenColText = colID.options[colID.selectedIndex].text;
var chosenSizeInd = document.getElementById("sizeID");
var chosenSizeText = sizeID.options[sizeID.selectedIndex].text;
var chosenSizeCol = chosenSizeText+","+chosenColText;
var found = "false";
for ( var i = 0; i < allowed.length; i++ ) {
if (allowed[i]=chosenSizeCol) {
found = "true";
}
}
if (found = "false") {
alert( 'The variation you have selected is currently unavailable. Please select another.' );
return false;
} else {
return true;
}
}
</script>
There are a few lines where you use the assignment operator (that is single equals =) instead of one of the equality operators (that is double or triple equals, triple is usually preferred in JavaScript). Example:
if (found = "false") {
Would appear to be the problem at first sight - it's an assignment not a comparison :) use triple equals === instead of single:
if(found === "false") {
Also, consider the following (commented) updates to your code, which reflects more the typical style of JavaScript code:
function validate_form() {
//no need to use new Array(), use array literal instead
var allowed = [
"10,beige",
"10,black",
"10,pink"
];
var chosenColInd = document.getElementById("colID");
var chosenColText = colID.options[colID.selectedIndex].text;
var chosenSizeInd = document.getElementById("sizeID");
var chosenSizeText = sizeID.options[sizeID.selectedIndex].text;
var chosenSizeCol = chosenColText+","+chosenSizeText;
var found = "false";
for ( var i = 0; i < allowed.length; i++ ) {
//use equality operator instead of assignment
if (allowed[i]===chosenSizeCol) {
found = true; //may as well use a boolean rather than string
break; //exit loop early, no need to continue if we've already found
}
}
if (!found) { //no need to do a comparison with already boolean values
alert( 'The variation you have selected is currently unavailable. Please select another.' );
}
//may as well just return found here now that we're using a boolean
return found;
}

Categories

Resources