开发者

JavaScript - numeric data vs NaN

I'm sure I'm contravening some deep dark law of javascript, but I'm not really a JS developer and this is driving me mad. This function is cal开发者_如何学Goled on an orderform to read the quantity and price of items, row by row, and then provide the subtotal, delivery and total.

The problem is with line 10 - it keeps "forgetting" that the variable data throughout is numeric (floating point) and so returns lots of NaN. How can I force the variables throughout this function to behave as numbers rather than strings?

EDIT

Here's the revised code based on feedback so far (thank you!). It's still not working ;)

<script type="text/javascript">
function subTotal(rows) {
    var i, subTotal, lineTotal, orderShip, orderTotal;
    for (i = 1; i <= rows; ++i) {
        //Grab values from form
        var quantity = parseFloat($('#quantity' + i).val());
        var uPrice = parseFloat($('#uPrice' + i).val());

        //Error checking
        alert('quantity = ' + quantity +' and uPrice = ' + uPrice);
        if (isNaN(quantity)) alert('quantity = NaN');
        if (isNaN(uPrice)) alert('uPrice = NaN');

        if ((quantity == '') || (uPrice == '')) {
        } else {
            lineTotal = quantity * uPrice;
            alert('lineTotal = ' + lineTotal);
            subTotal += lineTotal;
            alert('subTotal = ' + subTotal);
        }
        //If we've maxed out the number of rows, then subTotal should be calculated - push back to form.
        if (i == rows) { 
            $('#orderSubTotal').val(subTotal );
            orderShip = subTotal * 0.25;
            $('#orderShip').val(orderShip.toFixed(2));
            orderTotal = subTotal + orderShip;
            $('#orderTotal').val(orderTotal.toFixed(2));
        }
    }
}
</script>

<form>
<table>
<tr>
    <td><input type="text" id="item1" name="item1" value="Some description" readonly="readonly" /></td>
    <td><input type="text" id="quantity1" name="quantity1" value="25" onchange="javascript:subTotal('2')" /></td>
    <td><input type="text" id="uPrice1" name="uPrice1" value="1.50" readonly="readonly" /></td>    
</tr>
<tr>
    <td><input type="text" id="item2" name="item2" value="Some description" readonly="readonly" /></td>
    <td><input type="text" id="quantity2" name="quantity2" value="25" onchange="javascript:subTotal('2')" /></td>
    <td><input type="text" id="uPrice2" name="uPrice2" value="2.75" readonly="readonly" /></td>    
</tr>
<tr>
    <td colspan="3">
      SubTotal 
      <input type="text" id="orderSubTotal" name="orderSubTotal" readonly="readonly" style="text-align: right" value="0.00" />
      <br />Shipping 
      <input type="text" id="orderShip" name="orderShip" readonly="readonly" style="text-align: right" value="0.00" />
      <br />Total 
      <input type="text" id="orderTotal" name="orderTotal" readonly="readonly" style="text-align: right" value="0.00" />    
    </td>  
</tr>
</table>
</form>


I think the real problem is in your loop: You're looping from 0 to rows inclusive. So if you pass in 10 for rows, you'll be looping 11 times, starting with 0 and continuing through (including) 10. I suspect that's your real problem. If you don't have a quantity0 element, or (assuming rows is 10) you don't have a quantity10 element, then $("#quantity" + i).val() will return undefined, which converts to NaN when you convert it (implicitly or explicitly). (And the same for uPrice0 / uPrice10.) And of course, once you have NaN, any mathematical operation using it results in NaN.

In terms of your question about how to ensure they don't change, basically, convert them to numbers early. You're currently using quantity and uPrice without converting them, which means initially they're strings. Now, JavaScript is pretty smart about converting them for you, but sometimes you want to be explicit.

Separately: Where does x come from?

You haven't shown any data to work with, but just speculatively:

function subTotal(rows) {
    var i, subTotal, lineTotal, quantity, uPrice, orderShip, orderTotal;

    subTotal = 0;
    for (i = 0; i < rows; ++i) {
    // OR
    //for (i = 1; i <= rows; ++i) {
        quantity = $('#quantity' + i).val();
        uPrice = $('#uPrice' + i).val();
        if ((quantity == '') || (uPrice == '')) {
        } else {
            quantity = parseFloat(quantity);
            uPrice   = parseFloat(uPrice);
            // Might consider checking isNaN(quantity) and isNan(uPrice) here
            lineTotal = quantity * uPrice;
            subTotal += lineTotal;
            alert('subtotal = ' + subTotal);
        }
        if (i == x) {                           // Where does `x` come from?
            $('#orderSubTotal').val(subTotal );
            orderShip = subTotal * 0.25;
            $('#orderShip').val(orderShip.toFixed(2));
            orderTotal = subTotal + orderShip;
            $('#orderTotal').val(orderTotal.toFixed(2));
        }
    }
}


The problem is that you're performing a mathematical calculation on the fields before using parseFloat:

var lineTotal = quantity * uPrice;   // <-- result is most likely NaN here
subTotal = parseFloat(subTotal ) + parseFloat(lineTotal);

Perform your parsing at the point you get the values to make life a little easier:

    var quantity = parseFloat($('#quantity' + i).val());
    var uPrice = parseFloat($('#uPrice' + i).val());

Then change the subTotal = line to this:

        subTotal += lineTotal;

Another possible issue is if the result of $('#uPrice' + i).val() doesn't start with a parseable float — if it starts with a currency symbol, e.g. £ or $, for instance — parseFloat will always return NaN for that field. You can work around it using $('#uPrice' + i).val().slice(1).


Do some error checking:

function subTotal(rows) {
    var subTotal = 0;
    while (var i=0; i < rows; i++) {
        // convert as soon as you get the values
        var quantity = parseFloat($('#quantity' + i).val());
        var uPrice = parseFloat($('#uPrice' + i).val());
        if (isNaN(quantity) || isNaN(uPrice)) { // error checking
            alert("Invalid values on row " + i);
            continue;
        }
        var lineTotal = quantity * uPrice;
        subTotal += lineTotal;
        alert('subtotal = ' + subTotal);
        if (i == x) {
            $('#orderSubTotal').val(subTotal );
            var orderShip = subTotal * 0.25;
            $('#orderShip').val(orderShip.toFixed(2));
            var orderTotal = subTotal + orderShip;
            $('#orderTotal').val(orderTotal.toFixed(2));
        }
    }
}

You're probably running into an index problem at some point, getting a NaN from one of the (non-existing fields), adding it to subTotal which makes it a NaN instantly.


You better convert the value before doing any mathematical operation. So the code should be:

var numQuanitity = parseFloat(quantity);
var numPrice = parseFloat(uPrice);
if (isNaN(numQuanitity) || isNaN(numPrice)) {
   //you can alert or ignore
}
else {
   var lineTotal = numQuanitity * numPrice;
   subTotal += lineTotal;
   alert('subtotal = ' + subTotal);
}
...
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜