k.lin
k.lin

Reputation: 11

adding numbers extracted from strings javascript

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

Upvotes: 1

Views: 208

Answers (2)

jfriend00
jfriend00

Reputation: 707328

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);

Upvotes: 2

Bergi
Bergi

Reputation: 664513

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);

Upvotes: 1

Related Questions