kaisle kaisle - 3 months ago 14
jQuery Question

Jquery each function not including last of "each"

Here is the codepen that will make this a lot easier: http://codepen.io/kaisle/pen/rLqEXY

Long story short: Click a '+' button for one of the products. The "Current Order" box now shows a list item with that flavor, the quantity you chose, and the total price. The "order total" now shown on the current order div, is adjusted by the price of the wholesale order items as you click them.
The issue is that the last item in each category is not being included in the total price.

To test this: Click '+' once for each flavor in 'Craft Soda - 10mg THC/can'. The "Order total" should be $180 ($36 each times 5 flavors). But instead the "Order total" shows $144 (the first four flavors are being included, the last of the 5 is not). Below is the .each code that generates the list item.

$('.picker .product.hardcandy .qty').each(function(i, e) {
var $this = $(this);
var orderAmt = parseInt($this.find('.amt').html());
var itemPrice = orderAmt*($(this).siblings('.wholesale-pricing').children('.priceper').html());


if (orderAmt > 0) {
chosenHardCandy += '<li>' + orderAmt + ' x ' + $this.find('.flavor').html() + ' Hard Candy - $' + '<span class="newPriceHardCandy">' + itemPrice + '</span></li>';
}

var sum = 0;

$('.newPriceHardCandy').each(function(){
sum += parseFloat($(this).text());
});

$('.indTotalHardCandy').html(sum);
$('.currentorder .chosen.hardcandy').html(chosenHardCandy);
});


Something in the code below (I believe) is where it breaks. The gist of the code below: If the order amount is at least 1, add in a new list item to the list, in this example format: '3 x Root Beer Hard Candy - $540'. Then take the sum (in this example 540), add it to the other sums of the other list items, and output the total

if (orderAmt > 0) {
chosenHardCandy += '<li>' + orderAmt + ' x ' + $this.find('.flavor').html() + ' Hard Candy - $' + '<span class="newPriceHardCandy">' + itemPrice + '</span></li>';
}

var sum = 0;
$('.newPriceHardCandy').each(function(){
sum += parseFloat($(this).text());
});


I am thinking I am just skipping something simple. I found a quick fix of adding an empty product flavor line at the end of each item, but that seems like a poor fix for something that's probably wrong with my jquery.

Answer

The problem is that you are calculating the sum based on elements that don't exist in the DOM yet.

Currently, you first create a string of HTML with the .newPriceHardCandy elements in the variable chosenHardCandy. You then try to sum those up using $('.newPriceHardCandy').each(), but that selects elements that are already in the DOM, not elements in your string. Then after that you add the actual elements to the DOM with $('.currentorder .chosen.hardcandy').html(chosenHardCandy);

You need to change the order of your code to add that string of html to the DOM first, and then work out the sum.

Also, there's no need to keep recalculating the sum inside the outer .each() statement, but the fact that you do currently is why you get a sum of everything except the last item: by the time the last iteration runs you have updated the DOM with all the previous items, so the sum code finds those, it just doesn't find the last one that exists only in the string variable at that point.

So try something like this:

// FIRST build a string of elements to total
$('.picker .product.hardcandy .qty').each(function(i, e) {
  var $this = $(this);
  var orderAmt = parseInt($this.find('.amt').html());
  var itemPrice = orderAmt * ($(this).siblings('.wholesale-pricing').children('.priceper').html());

  if (orderAmt > 0) {
    chosenHardCandy += '<li>' + orderAmt + ' x ' + $this.find('.flavor').html() + ' Hard Candy - $' + '<span class="newPriceHardCandy">' + itemPrice + '</span></li>';
  }
});
// SECOND add the string to the DOM
$('.currentorder .chosen.hardcandy').html(chosenHardCandy);

// FINALLY calculate the sum
var sum = 0;
$('.newPriceHardCandy').each(function() {
  sum += parseFloat($(this).text());
});
$('.indTotalHardCandy').html(sum);

Here's a forked version of your demo with that change made: http://codepen.io/anon/pen/rLqXGA - note: I also clicked the "tidy JS" option, and I applied the fix only to the hard candy part of the code - you would need to do the same thing for the sodas and so forth.

Comments