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 called 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);
}
...
Related
I already solve it,
Here is my HTML code 👇
<strong>Product Price = $20</strong><br>
<strong>Bag Price = $10</strong><br>
<hr>
<label>Quantity of products</label>
<br>
<input type="number" id="quantity">
<br>
<input type="checkbox" id="with_bag">
<label>With a bag</label>
<br>
<p>Total Price 👇</p>
<input type="text" id="total_price" readonly>
And here is my jQuery code 👇
// Calculate total price (On Keyup)
$(document).on("keyup", "#quantity", function() {
var quantity = $('#quantity').val();
var content_price = $("#with_bag").is(':checked') ? 10 : 0;
var total_price = (20 * quantity) + content_price;
$('#total_price').val('$' + total_price.toFixed(2));
});
// Calculate total price (On Click)
$(document).on('click', '#with_bag', function(){
var quantity = $('#quantity').val();
var total_price = 20 * quantity;
if(this.checked){
total_price = (20 * quantity) + 10;
}
$('#total_price').val('$' + total_price.toFixed(2));
});
I just want to know, how to get these two different events (on keyup & on click) at the same function?
You can make a function and track your event conditionally if this is exactly what you want.
function myFunction(event){
var quantity = $('#quantity').val();
if(event.type == "keyup"){
var content_price = $("#with_bag").is(':checked') ? 10 : 0;
var total_price = (20 * quantity) + content_price;
$('#total_price').val('$' + total_price.toFixed(2));
}
else{
var total_price = 20 * quantity;
if($('#with_bag').is(":checked")){
total_price = (20 * quantity) + 10;
}
$('#total_price').val('$' + total_price.toFixed(2));
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<strong>Product Price = $20</strong><br>
<strong>Bag Price = $10</strong><br>
<hr>
<label>Quantity of products</label>
<br>
<input type="number" onkeyup="myFunction(event);" id="quantity">
<br>
<input type="checkbox" onclick="myFunction(event);" id="with_bag">
<label>With a bag</label>
<br>
<p>Total Price 👇</p>
<input type="text" id="total_price" readonly>
I have a function to add up my sum and charge respectively. But when i alert sum + charge, i get NaN. why is this happening?
<script>
sum = 0;
charge = 0;
$('.panel').append(
'<div class="container" style=" font-size:14px; "> '+
'<table style="width:100%;" class="table" id="tables">'+
'<td class="name" >'+std.name+'</td>'+
'<td><p class="total" ><span class="min-total" name="total" id="total"></span></p></td>'+
'</table>'+
'</div>'
$('.panel').on('keyup','.quantity',function()
container = $(this).closest('div');
quantity = Number($(this).val());
price = Number($(this).closest('div').find('.price').data('price'));
container.find(".min-total span").text(quantity * price);
sum = 0;
$(".sum-total").each(function(){
sum = sum + Number($(this).text());
})
}
$('.charge').on('keyup','.charge',function(){
$('.charge span').text( Number($(this).val()));
charge = Number($(this).val());
alert(sum + charge);
</script>
The wikipedia definition says:
In computing, NaN, standing for not a number, is a numeric data type
value representing an undefined or unrepresentable value. https://en.wikipedia.org/wiki/NaN
In your code either $(this).text() or $(this).val() cannot be computed by Number() and return NaN. Make sure the value of those is either a Number or a string made of numbers.
I'm trying to display a calculation of two radio groups, in real time, before users click submit button.
<div class="container-5">
<div class="choices1">
<h1 class>Regular<br>Regular Choice</h1>
<input type="radio" id="thirteen" name="style" value="13.00">
</div>
<div class="choices2">
<h1>Popular<br>Popular Choice</h1>
<input type="radio" id="fifteen" name="style" value="15.00">
</div>
<div class="choices3">
<h1>Fancy<br>Fancy Choice<br>Literally.</h1>
<input type="radio" id="twenty" name="style" value="20.00">
</div>
</div>
<div class="container-8">
<div class="gratuity1">
<h1 class>15%<br>Good.</h1>
<input type="radio" id="15" name="tip" value=".15">
</div>
<div class="gratuity2">
<h1>20%<br>Excellent Service.</h1>
<input type="radio" id="20" name="tip" value=".20">
</div>
<div class="gratuity3">
<h1>25%<br>Beyond Excellent</h1>
<input type="radio" id="25" name="tip" value=".25">
</div>
</div>
I'm using pure javascript.
Each of these categories is suppose to represent the value of the selected radio button. Once I've defined the variables I created if statements to test if both buttons were selected and event would occur
var styleVal1= 3.0;
var styleVal2 = 5.0;
var styleVal3 = 10.0;
var tipVal1 = 0.1;
var tipVal2 = 0.15;
var tipVal3 = 0.2;
var total = 0.00;
if (document.getElementById("thirteen").selected) {
document.getElementById("thirteen").addEventListener("click", function() {
total = styleVal1;
document.getElementById("total").innerHTML = "Total:$ " + total;
if (document.getElementById("15").selected) {
total += total * tipVal1;
document.getElementById("total").innerHTML = "Total:$ " + total;
} else if (document.getElementById("20").selected) {
total += total * tipVal2;
document.getElementById("total").innerHTML = "Total:$ " + total;
} else (document.getElementById("25").selected) {
total += total * tipVal3;
document.getElementById("total").innerHTML = "Total:$ " + total;
}
});
}
I also created if statements for document.getElementById("fifteen").selected) {} and if (document.getElementById("twenty").selected {}
Am I not putting this in the right order or am I missing something? Is it even possible to do else if statements inside if statements?
As I see your JS code is wrong logically.
First of all click event is not yet binded because this condition if (document.getElementById("thirteen").selected) will always return false and event will not binded to radio element.
else cannot have a condition. else (document.getElementById("25").selected) this is wrong.
I've corrected your code but you neeed to correct the rest,
document.getElementById("thirteen").addEventListener("click", function() {
total = styleVal1;
document.getElementById("total").innerHTML = "Total:$ " + total;
if (document.getElementById("15").selected) {
total += total * tipVal1;
document.getElementById("total").innerHTML = "Total:$ " + total;
} else if (document.getElementById("20").selected) {
total += total * tipVal2;
document.getElementById("total").innerHTML = "Total:$ " + total;
} else if (document.getElementById("25").selected) { //changed this to else-if
total += total * tipVal3;
document.getElementById("total").innerHTML = "Total:$ " + total;
}
});
I'm simply trying to take inputs from html input fields.
The problem is, my function always evaluate the inputs to 0.
What should I do my code to work as I expected (to take inputs from fields and pass them to my javascript functions). If there is alike answered questions asked before, please refer.
Please do not propose jQuery solutions - I can't follow its full of parantheses syntax.
P.S. Zeros on ternary, are just for avoiding NaNs. Nothing else.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<strong>Data</strong>
<hr>Price:
<input type="text" id="price" value="0">
<br>Prepay:
<input type="text" id="prepay" value="0">
<br>Percent:
<input type="text" id="percent" value="0">
<br>Month:
<input type="text" id="month" value="0" onchange="refactorTable('payment-plan')">
<br>
<hr>
<strong>Table</strong>
<table id="payment-plan" border="1">
<thead>
<tr>
<td>Month</td>
<td>Amount</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script type="text/javascript">
var Sum = parseInt(document.getElementById('price').value);
var PrePayment = parseInt(document.getElementById('prepay').value);
var Percent = parseInt(document.getElementById('percent').value);
var Month = parseInt(document.getElementById('month').value);
//console.log(Sum +" -- "+ PrePayment +" -- "+ Percent +" -- "+ Month);
function monthlyPaymentPlan(Sum, PrePayment, Percent, Month) {
var BigJohn = Sum - PrePayment;
//console.log(BigJohn);
var monthly = Math.ceil((BigJohn + BigJohn * Percent) / Month);
return Month > 0 ? monthly : 0;
}
function lastMonth(Sum, PrePayment, Percent, Month) {
return Month > 0 ? Sum - monthlyPaymentPlan(Sum, PrePayment, Percent, Month) * (Month - 1) : 0;
}
function refactorTable(tbl_id) {
var table = document.getElementById(tbl_id).getElementsByTagName('tbody')[0];
table.innerHTML = "";
var i = 0;
var rows = document.getElementById('month').value;
rows = parseInt(rows);
for (i = 0; i < rows - 1; i++) {
table.insertRow(-1).innerHTML = "<td>" + (i + 1) + "</td><td>" + monthlyPaymentPlan(Sum, PrePayment, Percent, Month) + "</td>";
}
table.insertRow(-1).innerHTML = "<td>" + rows + "</td><td>" + lastMonth(Sum, PrePayment, Percent, Month) + "</td>";
}
</script>
</body>
</html>
You are getting the values when the page renders, instead of when the function is supposed to run. Place your assignments inside a function and call the function.
// Define the variables globally so they can be used in any function
var Sum;
var PrePayment;
var Percent;
var Month;
// Call this function to set the values of the global variables.
function getValues() {
Sum = parseInt(document.getElementById('price').value);
PrePayment = parseInt(document.getElementById('prepay').value);
Percent = parseInt(document.getElementById('percent').value);
Month = parseInt(document.getElementById('month').value);
}
// Call the getValues function first to set the values and then continue on
// with your function calculations.
function refactorTable(tbl_id) {
getValues();
// Do the rest...
}
You need to get the values at the time the function is called. Right now you're getting the values on page load (which is 0).
function refactorTable(tbl_id) {
var Sum = parseInt(document.getElementById('price').value);
var PrePayment = parseInt(document.getElementById('prepay').value);
var Percent = parseInt(document.getElementById('percent').value);
var Month = parseInt(document.getElementById('month').value);
var table = document.getElementById(tbl_id).getElementsByTagName('tbody')[0];
table.innerHTML = "";
var i=0;
var rows = document.getElementById('month').value;
rows = parseInt(rows);
for(i=0; i<rows-1; i++) {
table.insertRow(-1).innerHTML = "<td>" + (i+1) + "</td><td>" + monthlyPaymentPlan(Sum, PrePayment, Percent, Month) + "</td>";
}
table.insertRow(-1).innerHTML = "<td>" + rows + "</td><td>" + lastMonth(Sum, PrePayment, Percent, Month) + "</td>";
}
You have need to update input variable value on change of id="month" so you can get updated value.
var Sum = '';
var PrePayment = '';
var Percent = '';
var Month = '';
function inputsval() {
Sum = parseInt(document.getElementById('price').value);
PrePayment = parseInt(document.getElementById('prepay').value);
Percent = parseInt(document.getElementById('percent').value);
Month = parseInt(document.getElementById('month').value);
}
function refactorTable(tbl_id) {
inputsval();
//Your other code.....
}
var Sum = parseInt(document.getElementById('price').value);
This is not defining a function, or a macro. This is a one-time calculation of a number, and it seems this is going to happen when the page starts up. So, it won't ever change from its first value (0).
You should probably move these declarations inside of refactorTable. Thankfully, you already have them set up to be passed as arguments.
This JavaScript function works independently for each line in the php foreach loop below just fine. However I Want to add those
two independent totals together to get a grand total and display it in the DIV tag below. I can't figure out how to set aside the
amounts and then add them together. The grand total should update with each change of quanity just like the amounts currently do.
Right now totalprice just reflects one amount but not a grand total.
<head>
<script type="text/javascript">
function update(iteration){
var qty = document.getElementById('qty_' + iteration).value;
// alert('quantity_' + iteration);
var price = document.getElementById('price_' + iteration).value;
price = price.substring(0, 7);
qty = parseInt(qty);
var amount = (qty * price).toFixed(2) ;
parseFloat(document.getElementById('amount_' + iteration).value = amount).toFixed(2);
//HERE's the code that's not working..
var subtotal;
for(var i =1; i < itemCount; i++) {
subtotal += document.getElementById('amount_' + i).value;
}
//this works
var divobj = document.getElementById('totalPrice');
divobj.style.display='block';
divobj.innerHTML = "Total $"+parseFloat(subtotal);
}
</script>
</head>
<?php
$listitems = unserialize($row["products"]);
$i=1;
foreach($listitems as $item)
{
echo '<tr><td>'.$item["code"].'</td><td><input type="number" id="qty_'.$i.'" name="qty_'.$i.'" min="1" size="3" value="1" onChange="iteration = '.$i.'; update(iteration); " /></td>';
echo '<td><input type="hidden" name="price_'.$i.'" id="price_'.$i.'" value="';
echo $item['price'];
echo '" />';
echo $item['price'];
echo '</td><td><input type="text" name="amount_'.$i.'" id="amount_'.$i.'" size="6" readonly value="';
echo $item['price'];
echo '"/></td></tr>';
$i++;
}
?>
<div id="totalPrice"></div>
Couple things stick out.
parseInt( ) needs a radix parameter.
parseInt(qty, 10);
Im confused on what this line is doing:
parseFloat(document.getElementById('amount_' + iteration).value = amount).toFixed(2);
parseFloat returns a floating point, but you arent setting it to anything?
The problem that is causing your error is the var subtotal declaration.
You are declaring a variable to equal amount + itself, which doesn't exist yet.
What do you want subtotal to equal?
Edit:
Now that you updated, you want to iterate the number of items and add them all together.
var subtotal;
for(var i =0; i < itemCount; i++) {
subtotal += document.getElementById('amount_' + i).value;
}
This would iterate over 0-itemCount of the amount elements.