JS Variable is outputting as isNaN when I need a number - javascript

Here is the assignment so it's clear what I'm trying to do.
Write a program that calculates the price of a hotel room based on three factors. First, how many will be in one room: 1-2, 3-4, or 5-6? No more than six are allowed in a room. Second, are the guests members of AAA? Third, do they want a room with a view? The rate is calculated as follows:
Basic room rate is:
1-2 people = $50/night
3-4 people = $60/night
5-6 people = $70/night
There is a discount for AAA members off of the basic room rate per night:
1-2 people = 15%
3-4 people = 10%
5-6 people = 5%
A room with a view costs 10% more per night after all other calculations are performed.
The program should prompt the user for all the inputs, perform the calculations and output the total cost per night. It is suggested to use at least some nested if/else structures to calculate the cost.
Debuggers like firebug and JSLint haven't been any help and I suspect I'm just doing something completely wrong, though I haven't had trouble with "nested if" logic assignments before. Regardless I am a complete and utter newby.
When I test by inputting 1 for numberOfGuests, N for tripleAStatus, and N for roomView, finalRate is returning as isNaN (I know this means not a number), and I can't figure out why.
//Variable Declaration
var numberOfPeople;
var tripleAStatus;
var roomView;
var discountRate;
var roomRate;
var finalRate;
var discountPercent;
//Input
numberOfPeople = prompt("How many guests will their be? 6 Maximum.");
tripleAStatus = prompt("Are you a AAA Member? Y/N.");
roomView = prompt("Would you like your room to have a view?");
//Logic
if ((numberOfPeople <= 2) && (numberOfPeople > 0)) {
roomRate = 50;
discountPercent = .15;
} else if ((numberOfPeople <= 4) && (numberOfPeople > 2)) {
roomRate = 60;
discountPercent = .10;
} else if ((numberOfPeople <= 5) && (numberOfPeople > 4)) {
roomRate = 70;
discountPercent = .5;
} else {
alert("Your number of guests must be at least 1 and no more than 6");
}
if (tripleAStatus = "Y") {
discountRate = roomRate - (roomRate * discountRate);
} else if (tripleAStatus = "N") {
discountRate = roomRate;
} else {
alert("You need to answer with either Y or N");
}
if (roomView = "Y") {
finalRate = (discountRate) + ((discountRate) * .10);
} else if (roomView = "N") {
finalRate = discountRate;
} else {
alert("You need to answer with either Y or N");
}
//Output
document.write("Total cost per night is " + "$" + finalRate);

It looks like
discountRate = roomRate - (roomRate * discountRate);
Should read
discountRate = roomRate - (roomRate * discountPercent);
Which is why you're getting NaN in finalRate; discountRate hasn't been defined at this point, so your code actually reads discountRate = 1 - (1 * undefined).
As other posters have mentioned, you also need to change your conditionals to use == or ===; = is an assignment operator, so rather than checking if tripleAStatus is "Y", you're actually checking if "Y" evaluates to true (which it always will).
tripleAStatus = 'N';
if (tripleAStatus = 'Y') {
// tripleAStatus is now "Y", and the code inside this if will always be executed
}
Working changes: http://jsfiddle.net/5ZVkE/

In your If statements, you are assigning values by using single "=". Since the assignment always occurs, it will return true. In order to compare values, you need to use double "==" in the if statement. like this:
if (tripleAStatus == "Y") {
discountRate = roomRate - (roomRate * discountRate);
} else if (tripleAStatus == "N") {
discountRate = roomRate;
} else {
alert("You need to answer with either Y or N");
}

Replace the single '=' in your 'if' statements with '=='. You're currently using assignment operators instead of equality.
e.g.:
if (tripleAStatus == "Y") ...

You are using assignments instead of equality operators in your if statements. i.e. change
if (tripleAStatus = "Y")
to
if (tripleAStatus == "Y")

Please use ===!! this way, the type in the statement isn't casted and therefor more strictly checked if its the same type.
if (tripleAStatus === "Y") {
discountRate = roomRate - roomRate * discountRate;
} else if (tripleAStatus === "N") {
discountRate = roomRate;
}
/e -> & its faster!

prompt() returns a STRING not a NUMBER.
Use parseInt() with numberOfPeople.
And the other problem, you copied and pasted the wrong variable names in your formulas. Look at how you are using discountRate instead of discountPercent.

Related

Why does if statement not work and make my element disappear using display: none?

I am building a tip calculator and I couldn't make the if statement in my function work it just skips to calculating.
function calculate() {
var bill = parseInt(document.getElementById("bill").value);
var tip = parseInt(document.getElementById("tip").value) * .01;
var persons = parseInt(document.getElementById("persons").value);
if (bill == "" || tip == "") {
alert("Please enter value");
return;
};
if (persons == "" || persons <= 1) {
persons = 1;
document.getElementById("perPerson").style.display = "none";
} else {
}
let totalTipPer = (bill * tip) / persons;
let totalPer = (bill + (tip * 100)) / persons;
let totalTip = bill * tip;
let total = bill + (tip * 100);
totalTipPer = totalTipPer.toFixed(2);
totalPer = totalPer.toFixed(2);
total = total.toFixed(2);
totalTip = totalTip.toFixed(2);
document.getElementById("total-tip/person").innerHTML = totalTipPer;
document.getElementById("total-price/person").innerHTML = totalPer;
document.getElementById("total-tip").innerHTML = totalTip;
document.getElementById("total-price").innerHTML = total;
}
document.getElementById("calculate").onclick = function () {
calculate();
document.getElementById('results').style.display = 'block';
}
I expect the div encapsulating Tip Amount per person and total per person and to not appear when the input value of persons is empty.
Function parseInt returns 'An integer number parsed from the given string. If the first character cannot be converted to a number, NaN is returned.'
if you rpovide an empty value ('') it will return
NaN which is not equal to anything, even itself.
there are several ways to fix this:
check if it is a NaN with Number.isNaN(var)
use an intermediate value like var personsValue and check if it is equal to empty string ''.
use Hybrid suggested solution and assign a 0
value for falsy value('', undefined, n
ull etc...)
The issue is that persons becomes NaN, since if the value is left blank, "" becomes NaN when it is run through parseInt().
The way to fix this is by defaulting it to 0 if the field is left blank.
var persons = parseInt(document.getElementById("persons").value || 0);
as others pointed out parseInt is returning NaN if the field is blank, but this will also happen if the user inputs $5.00 for example.
Here's one way to make sure the value can be converted to a number before doing so.
// This function determines if a JavaScript String can be converted into a number
function is_numeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function calculate() {
// first put the input values into separate variables
billValue = document.getElementById("bill").value;
tipValue = document.getElementById("tip").value;
personsValue = document.getElementById("persons").value;
// use the is_numeric() function above to check if the values can be converted to numeric
if (!is_numeric(billValue) || !is_numeric(tipValue)) {
alert("Please enter values for bill and tip");
return;
}
// the rest of your code here
}
Hope this helps.

JS calculation issue

I have a simple vat calculator, but there is something funny with one of the calculation. The problem is in the last column, saying moms. e=a + d * 0.25 is correct, but the code below is not. It shows a too big number when calculating.
JS Code:
$(document).ready(function() {
$('#submit').click(function() {
//get cost and check value
var cost = $('#cost').val();
var check = $('#checkBox');
if (cost != null && cost != "") {
if (cost < 350) {
//c = a * 1
$('#total').val(cost);
$('#toll').val("");
$('#moms').val("");
} else {
if (check.is(':checked')) {
//c = a* 1.107* 1.25
$('#total').val((cost * 1.107 * 1.25).toFixed(2));
//d = a * 0.107
$('#toll').val((cost * 0.107).toFixed(2));
} else {
$('#total').val((cost * 1.25).toFixed(2));
$('#toll').val("");
$('#moms').val("");
}
if ($('#toll').val() != null && $('#toll').val() != "") {
//e = (a + d) * 0.25
var moms = (cost + $('#toll').val()) * 0.25;
$('#moms').val(moms.toFixed(2));
}
}
}
})
});
The value of input elements will always be a string. In most of your code, you're using the "cost" value in such a way that it will be implicitly converted to a number. However, the + operator is different, and will preferentially perform string concatenation to addition.
If you explicitly force the cost to be a number when you initialize it, things should work better:
var cost = +$('#cost').val();
That leading unary + operator will force the string value to be treated as a number. Now, of course, if the string doesn't look like a good number, then cost will be set to NaN, so you should check for that:
if (!isNaN(cost)) {
That can replace your current check to see if cost is not empty.
edit Sorry, you'll also need to convert the value of $('#toll').val() so that line would look like:
var moms = (cost + +$('#toll').val()) * 0.25;
The JavaScript + operator really likes strings.

Advice on how to code Luhn Credit Card validation with Javascript?

I'm pretty awful at Javascript as I've just started learning.
I'm doing a Luhn check for a 16-digit credit card.
It's driving me nuts and I'd just appreciate if someone looked over it and could give me some help.
<script>
var creditNum;
var valid = new Boolean(true);
creditNum = prompt("Enter your credit card number: ");
if((creditNum==null)||(creditNum=="")){
valid = false;
alert("Invalid Number!\nThere was no input.");
}else if(creditNum.length!=16){
valid = false;
alert("Invalid Number!\nThe number is the wrong length.");
}
//Luhn check
var c;
var digitOne;
var digitTwo;
var numSum;
for(i=0;i<16;i+2){
c = creditNum.slice(i,i+1);
if(c.length==2){
digitOne = c.slice(0,1);
digitTwo = c.slice(1,2);
numSum = numSum + (digitOne + digitTwo);
}else{
numSum = numSum + c;
}
}
if((numSum%10)!=0){
alert("Invalid Number!");
}else{
alert("Credit Card Accepted!");
}
</script>
The immediate problem in your code is your for loop. i+2 is not a proper third term. From the context, you're looking for i = i + 2, which you can write in shorthand as i += 2.
It seems your algorithm is "take the 16 digits, turn them into 8 pairs, add them together, and see if the sum is divisible by 10". If that's the case, you can massively simplify your loop - you never need to look at the tens' place, just the units' place.
Your loop could look like this and do the same thing:
for (i = 1; i < 16; i +=2) {
numSum += +creditNum[i];
}
Also, note that as long as you're dealing with a string, you don't need to slice anything at all - just use array notation to get each character.
I added a + in front of creditNum. One of the issues with javascript is that it will treat a string as a string, so if you have string "1" and string "3" and add them, you'll concatenate and get "13" instead of 4. The plus sign forces the string to be a number, so you'll get the right result.
The third term of the loop is the only blatant bug I see. I don't actually know the Luhn algorithm, so inferred the rest from the context of your code.
EDIT
Well, it would have helped if you had posted what the Luhn algorithm is. Chances are, if you can at least articulate it, you can help us help you code it.
Here's what you want.
// Luhn check
function luhnCheck(sixteenDigitString) {
var numSum = 0;
var value;
for (var i = 0; i < 16; ++i) {
if (i % 2 == 0) {
value = 2 * sixteenDigitString[i];
if (value >= 10) {
value = (Math.floor(value / 10) + value % 10);
}
} else {
value = +sixteenDigitString[i];
}
numSum += value;
}
return (numSum % 10 == 0);
}
alert(luhnCheck("4111111111111111"));
What this does is go through all the numbers, keeping the even indices as they are, but doubling the odd ones. If the doubling is more than nine, the values of the two digits are added together, as per the algorithm stated in wikipedia.
FIDDLE
Note: the number I tested with isn't my credit card number, but it's a well known number you can use that's known to pass a properly coded Luhn verification.
My below solution will work on AmEx also. I submitted it for a code test a while ago. Hope it helps :)
function validateCard(num){
var oddSum = 0;
var evenSum = 0;
var numToString = num.toString().split("");
for(var i = 0; i < numToString.length; i++){
if(i % 2 === 0){
if(numToString[i] * 2 >= 10){
evenSum += ((numToString[i] * 2) - 9 );
} else {
evenSum += numToString[i] * 2;
}
} else {
oddSum += parseInt(numToString[i]);
}
}
return (oddSum + evenSum) % 10 === 0;
}
console.log(validateCard(41111111111111111));
Enjoy - Mitch from https://spangle.com.au
#Spangle, when you're using even and odd here, you're already considering that index 0 is even? So you're doubling the digits at index 0, 2 and so on and not the second position, fourth and so on.. Is that intentional? It's returning inconsistent validations for some cards here compared with another algorithm I'm using. Try for example AmEx's 378282246310005.

JavaScript: Is the `if / else` statement faster than the conditional statement in?

Consider the following two pieces of code:
var adj=0>grip.y?0<grip.x?0:-180:0<grip.x?-360:-180;
and
var adj;
if (grip.y < 0) {
if (grip.x > 0)
adj = 0;
else
adj = -180;
}
else {
if (grip.x > 0)
adj = -360;
else
adj = -180;
}
They both produce the same result, but which is faster?
The speed difference will be negligible - use whichever you find is more convinient and readable. There wont be any problem with the wrong conditional construct.
Use switch conditions,that is faster than if and other conditional statements.
Just to check the performance in JavaScript, I tried to do a small experiment.
console.time("ternary operator");
const val = (5 > 2) ? true : false;
console.log(val);
console.timeEnd("ternary operator");
console.time("if condition");
let val2;
if (5 > 2) {
val2 = true;
} else {
val2 = false;
}
console.log(val2)
console.timeEnd("if condition");
and the output is quite shocking as the if condition is almost twice faster than the ternary statements.
Results :-
So to conclude I would suggest using the if condition over the ternary operator.

Problem with JavaScript arithmetic

I have a form for my customers to add budget projections. A prominent user wants to be able to show dollar values in either dollars, Kila-dollars or Mega-dollars.
I'm trying to achieve this with a group of radio buttons that call the following JavaScript function, but am having problems with rounding that make the results look pretty crummy.
Any advice would be much appreciated!
Lynn
function setDollars(new_mode)
{
var factor;
var myfield;
var myval;
var cur_mode = document.proj_form.cur_dollars.value;
if(cur_mode == new_mode)
{
return;
}
else if((cur_mode == 'd')&&(new_mode == 'kd'))
{
factor = "0.001";
}
else if((cur_mode == 'd')&&(new_mode == 'md'))
{
factor = "0.000001";
}
else if((cur_mode == 'kd')&&(new_mode == 'd'))
{
factor = "1000";
}
else if((cur_mode == 'kd')&&(new_mode == 'md'))
{
factor = "0.001";
}
else if((cur_mode == 'md')&&(new_mode == 'kd'))
{
factor = "1000";
}
else if((cur_mode == 'md')&&(new_mode == 'd'))
{
factor = "1000000";
}
document.proj_form.cur_dollars.value = new_mode;
var cur_idx = document.proj_form.cur_idx.value;
var available_slots = 13 - cur_idx;
var td_name;
var cell;
var new_value;
//Adjust dollar values for projections
for(i=1;i<13;i++)
{
var myfield = eval('document.proj_form.proj_'+i);
if(myfield.value == '')
{
myfield.value = 0;
}
var myval = parseFloat(myfield.value) * parseFloat(factor);
myfield.value = myval;
if(i < cur_idx)
{
document.getElementById("actual_"+i).innerHTML = myval;
}
}
First of all, Don't set myfield.value = myval after doing the math. You'll accumulate rounding errors with each additional selection of one of the radio buttons. Keep myfield.value as dollars all the time, then calculate a display value. This will also reduce the number of cases in your if-else cascade, as you will always be converting from dollars.
Now calculate by division -- you'll never have to multiply by 0.001 or 1000 since you're always converting in the same direction.
Use Math.round() to control rounding errors. You can multiply your original value first, then divide by a larger factor to also help control rounding errors; e.g. both these are the same in pure mathematics:
newvalue = value / 1000;
newvalue = (value * 10) / 10000;
Added
switch (new_mode)
{
case 'd':
divisor = 1;
break;
case 'kd':
divisor = 1000;
break;
case 'md':
divisor = 1000000;
break;
}
var displayValue = myfield.value / divisor;
Also, don't assign a string of numbers divisor = "1000"; use actual numbers divisor = 1000 (without the quotes)
Javascript's floating point numbers are a constant source of irritation.
You should try adding toFixed() to reduce the inevitable absurd decimals, and I've actually had to resort to forcing it to do it's rounding down where I don't care about it by doing something like:
number_to_be_rounded = Math.round(number_to_be_rounded*1000)/1000;
number_to_be_rounded = parseFloat(number_to_be_rounded.toFixed(2));
It's ugly, but it's close enough for a non-financial system.

Categories

Resources