jqueryicheck

Grand total not computing right in the first click of "Select All" checkbox


I have created a cart page. Every cart item has their own checkboxes. I use regular checkbox which is <input type="checkbox">. It is all working fine until I use iCheck plugin.

I cannot think of a better title composition of my question because it a weird circumstance.

Basically, what I want to happen is, every time I tick a checkbox, the grand_total will reflect. It works fine when I tick checkboxes until I checked all individually. grand_total reflects correctly. However, if I tick the select all checkbox for the first time, it will compute all cart_items excluding the last item in the cart. And when I click the select_all for the last time, it reflects correctly. I cannot figure out what's causing this because it works fine when I used regular checkbox. Maybe I am missing something.

Here is a quick demo of what happens: Quick Demo Video

At the first click of select_all, it seems like there are only 2 ticked checkboxes even though 3 are checked. 2 ticked checkboxes

And when I click it again there are now 3 everytime. 3 ticked checkboxes

so it seems like it happens at every first click of select all. Then works fine afterwards. And if I reload the page, there comes the problem again.

Here is my HTML code

<section class="cart_area">
    <div class="table-responsive">
        <table>
            <thead>
                <tr>
                    <th class="text-center">
                        <input type="checkbox" name="" id="" class="i-checks select_all">
                    </th>
                    <th>Product</th>
                    <th>Quantity</th>
                    <th class="text-center">Total</th>
                </tr>
            </thead>
            <tbody>
                <input type="hidden" name="cart_items" class="cart_items">
                <?php
                    $cart_items = $cakeOrdering->get_data("SELECT * FROM vw_cart_items WHERE cartID = ? ORDER BY cart_itemID DESC", array($_SESSION['cartID']));
                    if(!empty($cart_items)){
                        if(is_array($cart_items) || is_object($cart_items)){
                            foreach($cart_items as $cart_item){
                ?>
                <tr data-id="<?php echo $cart_item['cart_itemID'] ?>">
                    <td class="text-center">
                        <input type="checkbox" name="" id="" class="i-checks cart_item_checkbox">
                    </td>
                    <td class="product">
                        <img src="../img/cake_uploads/<?php echo $cart_item['image']; ?>" alt="" class="product-img">
                        <div class="prod-info">
                            <p class="prod-name"><?php echo $cart_item['prod_name'] ?></p>
                            <p class="prod-price" data-price="<?php echo $cart_item['price']; ?>">₱&nbsp;<?php echo number_format($cart_item['price'], 2, ".", ","); ?></p>
                            <a href="#" class="action text-info mr-2">Edit</a>
                            <a href="#" class="action text-danger">Delete</a>
                        </div>
                    </td>
                    <td class="quantity">
                        <div class="quantity-box">
                            <button class="minus-qty">-</button>
                            <input type="number" placeholder="1" value="<?php echo $cart_item['qty']; ?>" class="qty" disabled>
                            <button class="add-qty">+</button>
                        </div>
                    </td>
                    <td class="total text-right" data-total="<?php echo $cart_item['total_price']; ?>">₱&nbsp;<?php echo number_format($cart_item['total_price'], 2, ".", ","); ?></td>
                </tr>
                <?php }}}else{ ?>
                <tr>
                    <td colspan="4" class="text-center">There are no products in you cart. Shop now.</td>
                </tr>
                <?php } ?>
            </tbody>
        </table>
    </div>
    <div class="row mt-4">
        <div class="col-lg-7"></div>
        <div class="col-lg-5">
            <div class="cart-total-text">
                <div class="cart-head">Cart Total</div>
                <div class="total-boxes">
                    <p>Sub Total <span class="sub-total">₱ 0.00</span></p>
                </div>
                <div class="total-boxes">
                    <p>Total <span class="grand-total">₱ 0.00</span></p>
                    <input type="hidden" name="grand-total" class="grand-total">
                </div>
                <div class="cart-footer text-right">
                    <button class="btn pest_btn" id="checkout">Proceed to Checkout</button>
                </div>
            </div>
        </div>
    </div>
</section>

here is my old codes with regular checkbox: (This one works with regular checkbox)

function sum() {
    var overall_total = 0;

    $(".cart_checkbox:checked").closest("tr").find('.total_price').each(function() {
        total_price = $(this).data('total_price');
        overall_total = overall_total + parseFloat(total_price);
    })
    
    $('.overall_total').text(formatToCurrency(overall_total));
    return overall_total;
}

//   Select All
$('.select_all').on('change', function() {
    $('.cart_checkbox').not(this).prop('checked', this.checked);
    sum();
});

//   Individual Checkboxes
$(".cart_checkbox").change(function() {
    var total_length = $(".cart_checkbox").length;
    var checked_length = $(".cart_checkbox:checked").length
    //check if length less then total
    if (checked_length < total_length) {
        $('.select_all').prop('checked', false); //uncheck
    } else {
        $('.select_all').prop('checked', true); //check
    }

    sum();                  
});

And Here's my code with iCheck: (When I convert codes into iCheck, this problem occurs)

//   Select All
$(".select_all").on("ifClicked", function () {
    $(".select_all").on("ifChecked ifUnchecked", function (e) {
        if (e.type == "ifChecked") {
        $(".cart_item_checkbox").iCheck("check");
        } else {
        $(".cart_item_checkbox").iCheck("uncheck");
        }
    });
    sum();
});

//   Individual Checkboxes
$(".cart_item_checkbox").on("ifChanged", function () {
    var total_length = $(".cart_item_checkbox").length;
    var checked_length = $(".cart_item_checkbox").filter(":checked").length;

    if (checked_length < total_length) {
        $(".select_all").iCheck("uncheck");
    } else {
        $(".select_all").iCheck("check");
    }
    sum();
});

function sum() {
    var grand_total = 0;
    $(".cart_item_checkbox:checked")
        .closest("tr")
        .find(".total")
        .each(function () {
        total = $(this).data("total");
        grand_total = grand_total + parseFloat(total);
        });

    $(".sub-total").text(formatToCurrency(grand_total));
    $(".grand-total").text(formatToCurrency(grand_total));
    $(":input.grand-total").val(grand_total);
    return grand_total;
}

Solution

  • To make this work i have use $(this).closest("div").hasClass("checked") this will check if the parent of the checkbox has checked class or not because the iCheck plugin adds this class dynamically . Then , i have pass different selector depending on which event handler has called the sum() function.

    Demo Code :

    $(document).ready(function() {
      $('input').iCheck({
        checkboxClass: 'icheckbox_square-blue',
        increaseArea: '20%',
        handle: 'checkbox'
      });
    })
    
    //keep only clicked..event
    $(".select_all").on("ifClicked", function(e) {
      //reverse cndtion..
      if (!$(this).closest("div").hasClass("checked")) {
        $(".cart_item_checkbox").iCheck("check");
      } else {
        $(".cart_item_checkbox").iCheck("uncheck");
      }
      sum($(".cart_item_checkbox").parent(".checked")); //pass the slector 
    });
    
    
    $(".cart_item_checkbox").on("ifChanged", function() {
      var total_length = $(".cart_item_checkbox").length;
      var checked_length = $(".cart_item_checkbox").filter(":checked").length;
    
      if (checked_length < total_length) {
        $(".select_all").iCheck("uncheck");
      } else {
        $(".select_all").iCheck("check");
    
      }
      sum($(".cart_item_checkbox:checked")); //here pass different selector
    });
    
    function sum(el) {
      var grand_total = 0;
      el.closest("tr")
        .find(".total")
        .each(function() {
          total = $(this).data("total");
          grand_total = grand_total + parseFloat(total);
        });
    
      //remove formatToCurrency..for demo..purpose.
      $(".sub-total").text((grand_total));
      $(".grand-total").text((grand_total));
      $(":input.grand-total").val(grand_total);
      return grand_total;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/iCheck/1.0.3/skins/all.min.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/iCheck/1.0.3/icheck.min.js"></script>
    <section class="cart_area">
      <div class="table-responsive">
        <table>
          <thead>
            <tr>
              <th class="text-center">
                <input type="checkbox" name="" id="" class="i-checks select_all">
              </th>
              <th>Product</th>
              <th>Quantity</th>
              <th class="text-center">Total</th>
            </tr>
          </thead>
          <tbody>
            <input type="hidden" name="cart_items" class="cart_items">
    
    
            <tr data-id="1">
              <td class="text-center">
                <input type="checkbox" name="" id="" class=" cart_item_checkbox">
              </td>
              <td class="product">
                <img src="../img/cake_uploads/<?php echo $cart_item['image']; ?>" alt="" class="product-img">
                <div class="prod-info">
                  <p class="prod-name">
                    A
                  </p>
                  <p class="prod-price" data-price="12">₱&nbsp; 12
                  </p>
                  <a href="#" class="action text-info mr-2">Edit</a>
                  <a href="#" class="action text-danger">Delete</a>
                </div>
              </td>
              <td class="quantity">
                <div class="quantity-box">
                  <button class="minus-qty">-</button>
                  <input type="number" placeholder="1" value="2" class="qty" disabled>
                  <button class="add-qty">+</button>
                </div>
              </td>
              <td class="total text-right" data-total="24">₱&nbsp; 24
              </td>
            </tr>
            <tr data-id="2">
              <td class="text-center">
                <input type="checkbox" name="" id="" class="i-checks cart_item_checkbox">
              </td>
              <td class="product">
                <img src="../img/cake_uploads/<?php echo $cart_item['image']; ?>" alt="" class="product-img">
                <div class="prod-info">
                  <p class="prod-name">
                    A
                  </p>
                  <p class="prod-price" data-price="12">₱&nbsp; 12
                  </p>
                  <a href="#" class="action text-info mr-2">Edit</a>
                  <a href="#" class="action text-danger">Delete</a>
                </div>
              </td>
              <td class="quantity">
                <div class="quantity-box">
                  <button class="minus-qty">-</button>
                  <input type="number" placeholder="1" value="3" class="qty" disabled>
                  <button class="add-qty">+</button>
                </div>
              </td>
              <td class="total text-right" data-total="36">₱&nbsp; 36
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <div class="row mt-4">
        <div class="col-lg-7"></div>
        <div class="col-lg-5">
          <div class="cart-total-text">
            <div class="cart-head">Cart Total</div>
            <div class="total-boxes">
              <p>Sub Total <span class="sub-total">₱ 0.00</span></p>
            </div>
            <div class="total-boxes">
              <p>Total <span class="grand-total">₱ 0.00</span></p>
              <input type="hidden" name="grand-total" class="grand-total">
            </div>
            <div class="cart-footer text-right">
              <button class="btn pest_btn" id="checkout">Proceed to Checkout</button>
            </div>
          </div>
        </div>
      </div>
    </section>