Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am new to javascript and am trying to create a simple price calculator in javascript for my website (cupcake shop website). first, i have the user choose from a list of flavor choices and post that to a textarea, when the user selects vegan flavors, i would add $3.50 to the end when posting to the textarea, and when the user selects non vegan, the price is $2.75. everything posted to the textarea are strings. so for the calculator, I extract the last 5 characters (which is the price) and add them up to get a subtotal. I used a loop to go thru the list in the textarea to extract the numbers one by one and add them up, however, the calculation came out wrong. Can anyone tell me what is wrong with it???

function addOption(selectbox,text,value )
{
var optn = document.createElement("OPTION");
optn.text = text;
optn.value = value;
selectbox.options.add(optn);
}

function addOption_list(selectbox){
var flavors = new Array("blueberry vegan","butterscotch","cappuccino vegan","carrot     
cake","carrot vegan","chocolate walnut vegan",
"chocolate peanut butter vegan","green tea & chocolate","keylime","lavender     
vegan","lemon","lemon cream vegan","mandarin orange",
"mint chocolate","mocha","peanut butter & double chocolate","raspberry swirl","red   
velvet","sesame","sesame oreo",
"strawberry","strawberry 2 vegan","tangerine","thia tea","triple   
chocolate","vanilla","very berry","vietnamese coffee","yuzu");
for (var i=0; i < flavors.length;++i){

addOption(document.drop_list.flavors_list, flavors[i], flavors[i]);
}
}

var $ = function (id){
return document.getElementById(id);
}

var cart = [];
var update_cart = function(){
if(cart.length == 0){
    $("flavor_name").value = "";
} else{
    var list = "";
    for(var i in cart){ 
        list += (parseInt(i) +1) + ". " + cart[i] + /*":  $3.50" + */ "\n"; 
    }
    $("flavor_name").value = list;


    var sum = 0;
    for(var i = 0; i < cart.length; i++){
        var price = parseFloat(list.substring(list.length - 5));
        sum += parseFloat( price.toFixed(2) );
    }

    $("subtotal").value = sum;
    var tax = parseFloat(($("subtotal").value * .08875).toFixed(2));
    $("sales_tax").value = tax;

    var total = parseFloat(price + tax).toFixed(2);
    $("total").value = total;

    }
}




var selectDropdown = function(){
    var dropdownValue=document.getElementById("flavors_list").value;
   // alert("You selected : " + dropdownValue);


if(dropdownValue == "blueberry vegan" || dropdownValue == "cappuccino vegan" ||   
       dropdownValue == "carrot vegan" || dropdownValue == "carrot vegan" ||
   dropdownValue == "chocolate walnut vegan" || dropdownValue == "chocolate peanut   
       butter vegan" || dropdownValue == "lavender vegan" || dropdownValue == "lemon   
       cream vegan" || dropdownValue == "strawberry 2 vegan"){
    alert("Adding " + dropdownValue + " to cart.");
    cart[cart.length] = dropdownValue + ":  $3.25";
    update_cart();
} else{
    alert("Adding " + dropdownValue + " to cart.");
    cart[cart.length] = dropdownValue + ":  $2.75";
    update_cart();
} 
}

HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"     
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Home-Little Sweetie Cupcakes</title>
<link href="little_sweetie_styles.css" rel="stylesheet" type="text/css" />
<link rel="Shortcut Icon" href="favicon.ico" />
<script type="text/javascript" src="invoice.js"></script>


</head>

<body onLoad="addOption_list()";>
<div class="cart_content">

    <span class="content_title">
        Price Calculator
    </span>
    <p class="bodytext">To place an order, please enter the desired flavor from  
               the dropdown list:</p>
    <FORM name="drop_list" action="yourpage.php" method="POST" >
        <SELECT NAME="flavors_list" id="flavors_list"  
                    onchange="selectDropdown()">
        <Option value="" >Flavors List</option>
        </SELECT>
    </form>
    <div>
    <!--<textarea id="shopping_cart" rows="5" cols="50"></textarea>-->
    <table id="invoice">
    <tr>
        <td width="150"><textarea id="flavor_name" rows="10" cols="40" 
                     disabled="disabled" /></textarea></td>
        <td>&nbsp;</td>
        <td id="calculator">
            <label class="bodytext">Subtotal: </label><input 
                                type="text" id="subtotal" size="10" disabled="disabled" 
                                  /><br />
            <label class="bodytext">Sales Tax: </label><input 
                                 type="text" id="sales_tax" size="10" 
                                  disabled="disabled" /><br />
            <label class="bodytext">Total: </label><input type="text" 
                                id="total" size="10" disabled="disabled" /><br />
        </td>

    </tr>

    </table>
           </body>
           </html>

Thanks in advance

share|improve this question
 
What's "wrong" mean? –  SomeKittens Aug 5 '12 at 0:37
 
if you use jsfiddle.net to create an example, I'll be happy to help –  NicoSantangelo Aug 5 '12 at 0:37
 
Don't use a for-in loop to iterate cart. It is an array, and the proper way to iterate arrays in JS is for (var n=0; n<cart.length; n++){} –  Michael Berkowski Aug 5 '12 at 0:41
 
Show us the actual HTML and we can do a much better job helping you figure out how to sum the values you're trying to. –  jfriend00 Aug 5 '12 at 0:48
 
Line 8: parseInt(i) --> Oh no. One does not simply do this. This parseInt(i,10) is better. –  Derek 朕會功夫 Aug 5 '12 at 1:04
show 1 more comment

2 Answers

I see multiple issues in your code, but without a working example to look at where we can see the actual HTML and values, it's hard to know for sure what all the issues are. Here are some of the issues:

  1. parseInt() should always be passed the second parameter (the radix) otherwise it will guess what the radix is based on the content.
  2. You should NEVER use the for (x in a) to iterate the contents of an array. That can include properties that are added to the array in addition to the array elements. It is much safer to use for (var i = 0; i < array.length; i++).
  3. Floating point math is not perfect so if you want perfect financial math, you should convert everything to a number of cents and do integer math on that.
  4. Neither parseInt() nor parseFloat() will tolerate a $ in the string so you must remove those first.
  5. When iterating an array with a for loop, the incrementing index is just the index into the array. You have to actually reach into the array and get each value.

In this block of code, it's unclear what you're trying to iterate. Every pass through the for loop is just using the same value of list. It's not iterating an array.

for(var i = 0; i < cart.length; i++){
    var price = parseFloat(list.substring(list.length - 5));
    sum += parseFloat( price.toFixed(2) );
}

FYI, it's much safe to extract a number from the end of your string like this:

function getNumber(str) {
    var matches = str.match(/([\d\.]+)\s*$/)
    if (matches) {
        return (+matches[1]);
    }
    return(0);
}

var str = "xxx $99.45\n";
var num = getNumber(str);
share|improve this answer
 
I don't think he gets errors with his parseFloat: The string he uses is something like "… $3.50\n".substr(-5) :-| –  Bergi Aug 5 '12 at 0:53
 
@Bergi - it's not completely obvious because we don't know the possible range and certainly the code isn't safe against variable length numbers (like something greater than $9.99). It would be much safer to extract all trailing digits and periods or something like that rather than extracting a fixed length string. –  jfriend00 Aug 5 '12 at 1:07
1  
I added to my answer a safer way to extract the number from your string. –  jfriend00 Aug 5 '12 at 1:25
 
...but I'm quite sure that he actually does not want to extract them from the end of the string :-| –  Bergi Aug 5 '12 at 1:31
 
@Bergi - it's unclear what the input actually looks like (I hate javascript questions that operate on phantom HTML that we haven't been given), but this part of the OP's code looks like it's extracting from the end: list.substring(list.length - 5). –  jfriend00 Aug 5 '12 at 1:46
show 2 more comments
for(var i in cart)

You should traverse the array with a for-loop and a counting variable, as you do below. Additional benefit: No need to parseInt the property names.

I extract the last 5 characters (which is the price) and add them up to get a subtotal:

for(var i = 0; i < cart.length; i++){
    var price = parseFloat(list.substring(list.length - 5));
    sum += parseFloat( price.toFixed(2) );
}

Yes, for every item in cart you get the price out of the last five characters of the (same) list string. WTF?

What you wanted was to get the price for each item in the cart. And I'm quite sure there are not only <$10 items which have only 4 characters in their string representation. So, remove the first character (the dollar sign) of a cart item and apply parseFloat on that:

for (var i=0; i<cart.length; i++) {
    var price = parseFloat(cart[i].substring(1));
    sum += price;
}

Also, you should not use parseFloat( price.toFixed(2) );. Apart from some IE bugs, floating point maths will never be reliable, and does not get better when constantly rounding. Instead compute with the integer number of cents (although JS technically has no integers):

var price = Math.floor(parseFloat(str, 10) * 100);
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.