?
Solved

jquery order form with dynamic rows

Posted on 2009-12-18
8
Medium Priority
?
1,229 Views
Last Modified: 2012-05-08
I am at the point of frustration with this form.  I get to a point and find a setback, get around the setback and there is another setback.  Before I go and do something stupid I was hoping someone could point out what the heck I am messing up.

I have attached the full js and the html porttion of the form.  

What works is the first line adds up everything fine, well I havent worked on the shipping or order total part, but that not what I am after.

What does not work is when you clone the row nothing adds up anymore, not on the same line and not down below.  What also needs to happen is then when I delete the row the totals get recalculated.

If I had hair I would be pulling it out.  Please help.
<script type="text/javascript">
var newRowNum = 0;
$(document).ready(function(){

	//$('.total_change').bind('blur',function() {
		//var price = $('#order_item_price').val()	
		//var quantity = $('#order_qty').val()	
		//var total = price * quantity;
		//if (!isNaN(total)) {					
			//$('#order_item_total').attr('value', total.toFixed(2))
		//} else {
			//alert('Ops Error! Please only numbers')
		//}
	//});	
		
	
    $('#add-order-row').click(function(){
		newRowNum += 1;
		var addRow = $(this).parent().parent();
        var masterRow = addRow.next();
		var newRow = masterRow.clone(false);
            
        // Change the ids for the new row
        //$(newRow).attr({
			//'id'    : 'order-row-' + newRowNum,
			//'name'  : 'order-row-' + newRowNum
        //}).find(':input, button, select').each(function(){
		//$(this).attr({
			//'id'    : $(this).attr('id') + "_" + newRowNum,
			//'name'  : $(this).attr('name') + "_" + newRowNum,
			//'class'  : $(this).attr('class') + "_" + newRowNum
		//});
	//}); 
   	// Append new row to DOM                
	masterRow.after(newRow);
	//$('#order_item_product_' + newRowNum).change(function () {
		//var id = $('#order_item_product_' + newRowNum).val();
		//$('#order_item_price_' + newRowNum).val($('#order_item_product').data(id).price);
	//}).change();

	//$('.total_change_' + newRowNum).change(function() {
		//var price = $('#order_item_price_' + newRowNum).val()	
		//var quantity = $('#order_qty_' + newRowNum).val()	
		//var total = price * quantity;
		//if (!isNaN(total)) {					
			//$('#order_item_total_' + newRowNum).attr('value', total.toFixed(2))
		//} else {
			//alert('Ops Error! Please only numbers')
		//}
	//}).change();	
      
	// Add the remove function to the new row
	$('button#order_item_delete_' + newRowNum).click(function(){
		$(this).parent().parent().remove();
		return false;                           
	});
	// prevent the default click
	return false;
	});
});


function moneyFormat(input) {
	   var dollars = Math.floor(input);
	   var tmp = new String(input);

	   for ( var decimalAt = 0; decimalAt < tmp.length; decimalAt++ ) {
	      if ( tmp.charAt(decimalAt)=="." )
	         break;
	   }

	   var cents  = "" + Math.round(input * 100);
	   cents = cents.substring(cents.length-2, cents.length)
	           dollars += ((tmp.charAt(decimalAt+2)=="9")&&(cents=="00"))? 1 : 0;

	   if ( cents == "0" )
	      cents = "00";

	   return(dollars + "." + cents);
	}

function IsNumeric(sText)

{
var ValidChars = "0123456789.";
var IsNumber=true;
var Char;


for (i = 0; i < sText.length && IsNumber == true; i++) 
   { 
   Char = sText.charAt(i); 
   if (ValidChars.indexOf(Char) == -1) 
      {
      IsNumber = false;
      }
   }
return IsNumber;

};

function calcProdSubTotal() {
 
 var prodSubTotal = 0;
 $("#order_item_total").each(function(){
     var valString = $(this).val() || 0;
     prodSubTotal += parseFloat(valString);
 });
 
 $("#order_product_total").val(moneyFormat(prodSubTotal));

};

function calcTotalQty() {
 var totalQty = 0;
 $("#order_qty").each(function() {
     var thisValue = $(this).val();
     if ( (IsNumeric(thisValue)) &&  (thisValue != '') ) {
         totalQty += parseInt(totalQty);    
     };
 });
 $("#total_order_qty").val(totalQty);
};

function calcShippingTotal() {
	
	// will have to change to work UPS and USPS options in.
	
 var totalQty = $("#total_order_qty").val() || 0;
 var weightPerItem = 25;
 var shippingMath = weightPerItem/100;
 //var shippingRate = $("#shipping-rate").text() || 0;
 var shippingRate = '1.25';
 var shippingWeight = parseInt(totalQty) * parseInt(weightPerItem);
 
 var shippingTotal = parseInt(shippingWeight) * parseInt(shippingRate);
 
 $("#order_shipping").val(moneyFormat(shippingTotal));

};

function calcTaxTotal() {
	
	// right now tax is only from NJ can pull tax rate from DB later.
	
 var totalProd = $("#order_product_total").val() || 0;
 //alert("total prod" + totalProd);
 var taxRate = 7;
 var taxMath = taxRate/100;
 var taxTotal = parseFloat(totalProd) * parseFloat(taxMath);
 
 $("#order_tax").val(moneyFormat(taxTotal));

};

function calcOrderTotal() {

 var orderTotal = 0;

 var productSubtotal = $("#order_product_total").val() || 0;
 var productTax = $("#order_tax").val() || 0;
 var shippingSubtotal = $("#order_shipping").val() || 0;
     
 var orderTotal = parseInt(productSubtotal) + parseFloat(productTax) + parseFloat(shippingSubtotal);
 
 $("#order-total").val(moneyFormat(orderTotal));
     
};

$(document).ready(function(){

	$('.total_change').bind('blur',function() {
 
     var $this = $(this);
     
     var price = $('#order_item_price').val()	
		var quantity = $('#order_qty').val()
     
     //var numPallets = $this.val();
     //var multiplier = $this
                         //.parent().parent()
                         //.find("td.price-per-pallet span")
                         //.text();
     
     if ( (IsNumeric(price)) && (price != '') && (IsNumeric(quantity)) && (quantity != '') ) {
         
         var rowTotal = parseInt(quantity) * parseFloat(price);
         $('#order_item_total').val(moneyFormat(rowTotal));                    
         
     } else {
     
         $this.css("background-color", "#ffdcdc"); 
                     
     };
     
     calcProdSubTotal();
     calcTotalQty();
     
     calcTaxTotal();
     calcShippingTotal();
     calcOrderTotal();
 
 });

});


$(document).ready(function(){
	$.extend({
	getUrlVars: function(){
		var vars = [], hash;
		var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
		for(var i = 0; i < hashes.length; i++) {
			hash = hashes[i].split('=');
			vars.push(hash[0]);
			vars[hash[0]] = hash[1];
		}
		return vars;
	},
	getUrlVar: function(name){
		return $.getUrlVars()[name];
	}
	});
	$.ajax({
		type: "GET",
		url: "query.php",
		dataType: "xml",
		data: {'type' : 'status'},
		success: function(xml) {
			var select = $('#order_item_status');
			$(xml).find('entry').each(function(){
				var orders_status_id = $(this).find('orders_status_id').text();
				var orders_status_name = $(this).find('orders_status_name').text();
				select.append("<option value='"+ orders_status_id +"'>"+orders_status_name+"</option>");
			});
		}
	});
	$.ajax({
		type: "GET",
		url: "query.php",
		dataType: "xml",
		data: {'type' : 'products'},
		success: function(xml) {
			var select = $('#order_item_product');
			$(xml).find('entry').each(function(){
				var products_id = $(this).find('products_id').text();
				var products_name = $(this).find('products_name').text();
				var products_price = $(this).find('products_price').text();
				select.append("<option value='"+ products_id +"'>"+products_name+"</option>");
				//$("input[name='order_item_price']").val(products_price);
				//$('#order_item_product').data(products_id, { name: products_name, price: products_price });
				//$('#order_item_product').change(function () {
					//var id = $('#order_item_product').val();
					//$('#order_item_price').val($('#order_item_product').data(id).price);      
			    //}).change();
			});
		}
	});
	var id = $.getUrlVar('id');
	alert("my id is " + id);
	$.ajax({
		type: "GET",
		url: "query.php",
		dataType: "xml",
		data: {'id' : id, 'type' : 'address'},
		success: function(xml) {
			var select = $('#customer_billing_id');
			var select1 = $('#customer_shipping_id');
			var telephone_field = $('#customers_telephone');
			var email_address_field = $('#customers_email_address');
			$(xml).find('entry').each(function(){
				var address_book_id = $(this).find('address_book_id').text();
				var customers_fullname = $(this).find('customers_fullname').text();
				var customer_street_address = $(this).find('customer_street_address').text();
				var customer_city = $(this).find('customer_city').text();
				var customer_state = $(this).find('customer_state').text();
				var customer_postal_code = $(this).find('customer_postal_code').text();
				var customer_country = $(this).find('customer_country').text();
				var customers_email_address = $(this).find('customers_email_address').text();
				var customers_telephone = $(this).find('customers_telephone').text();
				select.append("<option value='"+ address_book_id +"'>"+customers_fullname+" "+customer_street_address+" "+customer_city+", "+customer_postal_code+""+customer_country+"</option>");
				select1.append("<option value='"+ address_book_id +"'>"+customers_fullname+" "+customer_street_address+" "+customer_city+", "+customer_postal_code+""+customer_country+"</option>");
				$("input[name='customers_telephone']").val(customers_telephone);
				$("input[name='customers_email_address']").val(customers_email_address);
			});
		}
	});
});

</script>


html --------------

<fieldset>
		<legend>Product Order Sheet</legend>
		<input type="hidden" id="total_order_qty" name="total_order_qty" value="">
		<dl>
			<p style="line-height: 5px;"><button type="button" name="add-order-row" id="add-order-row">Add Row</button></p>
		</dl>
        <dl id="order-row" name="order-row">
        	<dd style="line-height: 5px; text-align: right;">Qty:<input type="text" name="order_qty" id="order_qty" class="total_change" size="6" maxlength="6" />&nbsp;&nbsp;&nbsp;Product:<select size="1" name="order_item_product" id="order_item_product" class="total_change"></select>&nbsp;&nbsp;&nbsp;Price:<input type="text" name="order_item_price" id="order_item_price" class="total_change" size="6" maxlength="20" />&nbsp;&nbsp;&nbsp;Total:<input type="text" name="order_item_total" id="order_item_total" class="total_change" size="6" maxlength="20" />&nbsp;&nbsp;&nbsp;<button type="button" name="order_item_delete" id="order_item_delete" class="total_change">Delete</button></dd>
		</dl>
		<dl>
			<dd style="line-height: 5px; text-align: right; border-top: 2px solid black;">&nbsp;&nbsp;&nbsp;</dd>
		</dl>
		<dl>
			<dd style="line-height: 5px; text-align: right;">Product Total:&nbsp;&nbsp;&nbsp;<input type="text" name="order_product_total" id="order_product_total" size="6" maxlength="10" value="" /></dd>
		</dl>
		<dl>
			<dd style="line-height: 5px; text-align: right;">Tax:&nbsp;&nbsp;&nbsp;<input type="text" name="order_tax" id="order_tax" size="6" maxlength="10" /></dd>
		</dl>
		<dl>
			<dd style="line-height: 5px; text-align: right;">Shipping:&nbsp;&nbsp;&nbsp;<input type="text" name="order_shipping" id="order_shipping" size="6" maxlength="10" /></dd>
		</dl>
		<dl>
			<dd style="line-height: 5px; text-align: right;">Order Total:&nbsp;&nbsp;&nbsp;<input type="text" name="order_total" id="order_total" size="6" maxlength="10" value="$0.00" /></dd>
		</dl>
	</fieldset>

Open in new window

0
Comment
Question by:iceman19330
  • 4
  • 4
8 Comments
 
LVL 82

Accepted Solution

by:
hielo earned 2000 total points
ID: 26086170
I don't know what you are doing with the ajax part, but this should give you a really good head start, mainly because it is more clear (IMHO). Save at test.html and try it. Be sure to read through the comments:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<title>Hielo</title>
	<style type="text/css">
		.order-row{margin:15px 0px;}
	</style>
	<script type="text/javascript" src="http://www.google.com/jsapi"></script>
	<script type="text/javascript">google.load("jquery","1.3.2");</script>
	<script type="text/javascript">
	$(document).ready(function(){
		$('#add-order-row').bind('click',function(){
			//you should have at least one row - the initial row. So if you are adding a new row
			//then you will have at least two rows. When this is the case, all the delete
			//buttons should be enabled.
			$("input.delete").attr("disabled","");

			//clone first row
			var newRow = $('.order-row:eq(0)').clone(true);

			//insert at the end
			newRow.insertAfter($('.order-row:last'));
			
			//iterate through every row
			$(".order-row").each(function(rowNumber,currentRow){

				//within each row, assign unique ids to the elements
				$("*",currentRow).each(function(){
					if(this.id.match(/(\d)+$/))
					{
						this.id=this.id.replace(RegExp.$1,rowNumber);
					}

					//now "blank-out" new row values
					if(currentRow==newRow.get(0))
					{
						switch(this.name)
						{
							case 'order_item_product'://SELECT LIST
								this.selectedIndex=0;
								break;

							case 'order_item_delete'://DELETE BUTTON
							case 'order_item_total'://SUBTOTAL
								//do nothing
								break;

							default:
								//reset input text boxes to blank
								this.value='';
								break;
						}
					}
				});
			});
		});//end: add-new-row


		//here you handle the clicking of  the Delete button
		$("input.delete").live("click",function()
		{
			//if there is more than one row, remove the clicked row
			if( $('.order-row').size()>1){
				$(this).closest('.order-row').remove();
			}
			//if the number of rows left is one, disable the delete button
			if( $('.order-row').size()==1)
			{
				$('.order-row:eq(0) input.delete').attr('disabled','disabled');
			}
			computeTotals();
		});
		
		
		//now recompute values whenever there are changes
		$('.total_change').bind('change',computeTotals);
	});


	function computeTotals()
	{
		var total=0;
		//iterate over every row to compute the subtotal for each row
		$('.order-row').each(function(rowNumber,currentRow){

		//get the value of quantity within the currentRow
		var q= $("input[name='order_qty']",currentRow).val();

		//for purposes of computing the subtotal, reset to zero if it is 
		//not numeric
		if(isNaN(q))
		{
			q=0;
		}

		//get the value of quantity within the currentRow
		var p=$("input[name='order_item_price']",currentRow).val();
		//for purposes of computing the subtotal, reset to zero if it is 
		//not numeric
		if( isNaN(p))
		{
			p=0;
		}

		//update the subtotal to two decimal places.
		$(".subTotal",currentRow).val( "$"+(p*q).toFixed(2) );
				
		//update the total counter
		total=(parseFloat(total)+parseFloat(p*q)).toFixed(2);
		});
			
		//update the total field
		$("#order_product_total").val("$"+total);

		//you figure these out
		var tax=0.00;
		var shipping=0.00;

		$('#order_total').val( "$"+ parseFloat(total + tax + shipping).toFixed(2) );//"$" + (total + tax + shipping)
	}
	</script>

</head>
<body>
	<fieldset>
		<legend>Product Order Sheet</legend>
		<input type="hidden" id="total_order_qty" name="total_order_qty" value="" />

		<p><input type="button" name="add-order-row" id="add-order-row" value='Add Row'/></p>
		<dl>
			<dd class="order-row" style="text-align: right;">
					Product:<select size="1" name="order_item_product" id="order_item_product_0" class=""><option></option><option value='1'>apples</option><option value='1'>oranges</option></select>&nbsp;&nbsp;&nbsp;
					Qty:<input type="text"   name="order_qty" id="order_qty_0"                   class="total_change" size="6" maxlength="6" />&nbsp;&nbsp;&nbsp;
					Price:<input type="text" name="order_item_price"   id="order_item_price_0"   class="total_change" size="6" maxlength="20" />&nbsp;&nbsp;&nbsp;
					Total:<input readonly='readonly' type="text" name="order_item_total"   id="order_item_total_0"   class="subTotal" value='$0.00' size="6" maxlength="20"/>&nbsp;&nbsp;&nbsp;
					<input type="button"     name="order_item_delete"  id="order_item_delete_0"  class="delete" value='Delete' disabled='disabled'/>
			</dd>
			<dd style="line-height: 5px; text-align: right; border-top: 2px solid black;">&nbsp;&nbsp;&nbsp;</dd>
			<dd style="line-height: 5px; text-align: right;">Product Total:&nbsp;&nbsp;&nbsp;<input type="text" name="order_product_total" id="order_product_total" size="6" maxlength="10" value='$0.00' /></dd>
			<dd style="line-height: 5px; text-align: right;">Tax:&nbsp;&nbsp;&nbsp;<input type="text" name="order_tax" id="order_tax" size="6" maxlength="10" /></dd>
			<dd style="line-height: 5px; text-align: right;">Shipping:&nbsp;&nbsp;&nbsp;<input type="text" name="order_shipping" id="order_shipping" size="6" maxlength="10" /></dd>
			<dd style="line-height: 5px; text-align: right;">Order Total:&nbsp;&nbsp;&nbsp;<input type="text" name="order_total" id="order_total" size="6" maxlength="10" value="$0.00" /></dd>
		</dl>
	</fieldset>

</body>
</html>

Open in new window

0
 

Author Comment

by:iceman19330
ID: 26088560
Excellent.  I have a question about tax and adding the order total.

The code snippet is what I have for the tax and it populates the field and the calculation is correct.  However I take that the last line of "$('#order_total').val( "$"+ parseFloat(total + tax + shipping).toFixed(2) );//"$" + (total + tax + shipping)" doesn't update.  Unless I am misunderstanding the last line where it looks like it is taking the total, tax and shipping and adding it.

//you figure these out
		var tax=0.00;
		var taxRate = 7;
		var taxMath = taxRate/100;
		//var taxTotal = ;
		$("#order_tax").val( "$"+(parseFloat(total) * parseFloat(taxMath)).toFixed(2) );
		tax=(parseFloat(total*taxMath)).toFixed(2);
		
		var shipping=0.00;

		$('#order_total').val( "$"+ parseFloat(total + tax + shipping).toFixed(2) );//"$" + (total + tax + shipping)

Open in new window

0
 

Author Comment

by:iceman19330
ID: 26088784
Okay I think I got the tax part figured out.

//you figure these out
		var tax=0.00;
		var taxRate = 7;
		var taxMath = taxRate/100;
		$("#order_tax").val( "$"+(total*taxMath).toFixed(2) );

		$("#order_total").val( "$"+(parseFloat(total)+parseFloat(total*taxMath)).toFixed(2) );
		
		var shipping=0.00;

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 82

Expert Comment

by:hielo
ID: 26088785
In javascript the "+" operator is used for both, addition AND concatenation. Since you are interested in addition only, you need to find a way to "tell" the javascript interpreter to interpret the digits/values as numeric quantities NOT as strings. An easy way to do that is to multiply the values by 1: ex:

var x="5";//notice that here 5 is a string, not a number
var y= 7 + x*1;//x is first multiplied by 1, forcing it into numeric context, THEN it is added to 7:

So, to summarize, multiplication will force "numeric strings" into numeric context. So try:
var tax=0.00;
		var taxRate = 7;
		var taxMath = taxRate/100;
		//var taxTotal = ;
		$("#order_tax").val( "$"+(total*taxMath).toFixed(2) );
		tax=(total*taxMath).toFixed(2);
		
		var shipping=0.00;

		$('#order_total').val( "$"+ parseFloat(total*1 + tax*1 + shipping*1).toFixed(2) );//"$" + (total + tax + shipping)

Open in new window

0
 

Author Comment

by:iceman19330
ID: 26088803
Updated it since then just trying to work a few things around.

//you figure these out
		var tax=0.00;
		var taxRate = 7;
		var taxMath = taxRate/100;
		$("#order_tax").val( "$"+(total*taxMath).toFixed(2) );
		tax = (parseFloat(total*taxMath)).toFixed(2);
		
		var shipping=0.00;

		$('#order_total').val( "$"+ (parseFloat(total) + parseFloat(tax) + parseFloat(shipping)).toFixed(2) );//"$" + (total + tax + shipping)

Open in new window

0
 
LVL 82

Expert Comment

by:hielo
ID: 26088813
FYI: on the code you posted you are computing the tax twice. Do so just once and store the value onto a variable. Then use that variable to update the tax input field and to compute the grand total:
...		
		//update the total field
		$("#order_product_total").val("$"+total);

		var taxRate = 7;
		var tax=((taxRate/100)*total).toFixed(2);
		$("#order_tax").val( "$" + tax );
		var shipping=0.00;

		$('#order_total').val( "$"+ parseFloat(total*1 + tax*1 + shipping*1).toFixed(2) );

Open in new window

0
 
LVL 82

Expert Comment

by:hielo
ID: 26088815
>>parseFloat(total) + parseFloat(tax) + parseFloat(shipping)
Yes, that will work too. I find the "multiply by 1" to be easier, so that is what I prefer, but both accomplish the same thing - force numeric evaluation.
0
 

Author Closing Comment

by:iceman19330
ID: 31667859
Thanks very much.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this article you'll learn how to use Ajax calls within your CodeIgniter application. To explain this, I'll illustrate how to implement a simple contact form to allow visitors to send you an email through your web site.
Introduction If you're like most people, you have occasionally made a typographical error when you're entering information into an online form.  And to your consternation, the browser remembers the error, and offers to autocomplete your future entr…
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
Suggested Courses

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question