Total sum with multiple values dynamically using jQuery

Asked

Viewed 719 times

0

I’m trying to do a function that takes the values of all <div class="preco-produto"> make the total sum and population in the <div id="final">.

I made the function that separates the number value from the String of div, but I’m not managing to make the presentation of the total dynamic.

I need that whenever the value of each field <div class="preco-produto"> is changed, directly from the <div id="final"> also be, making an automatic calculation.

Remembering that whenever the user clicks on the "Add" button, another is created div with the same fields of the first, ie there may be several <div class="preco-produto">. Can someone shed some light on how I can change my code to make it happen ?

index php.:

<div id="allProducts">
                <div class="produtos-wrap"> <!---- DIV A SER CLONADA / ADICIONADA !---->
                    <div class=" text-center select_height">
                        <b>Número:</b>
                        <div class="index" class="font-pop">1</div>
                    </div>

                    <div class="text-center select_height">
                        <b>ID:</b>
                        <div class="font-pop number_id_produto">0</div>
                    </div>

                    <div class=" select_height">
                        <b>Selecione um produto:</b>
                        <select class="selectpicker form-control teste" data-show-subtext="false"
                                data-live-search="true" name="select_produtos[]" onchange="initProdutos(this)">
                            <?php
                            foreach ($result2 as $item_produtos) {
                                echo '<option data-subtext="' . $item_produtos['desc_produto'] . '" value="'
                                    . $item_produtos['desc_produto'] . '">' . $item_produtos['desc_produto'] . '</option>';
                            }
                            ?>
                        </select>
                    </div>

                    <div class="text-center select_height">
                        <b>Embalagem:</b>
                        <br>
                        <input type="text" maxlength="2" class="edit-input font-pop" name="embalagem[]" value="">
                    </div>

                    <div class="text-center select_height">
                        <b>Preço:</b>
                        <br>
                        <input type="text" maxlength="5" name="preco[]" class="edit-input font-pop" value="0">
                    </div>

                    <div class="text-center select_height">
                        <b>Quantidade:</b>
                        <br>
                        <input type="text" maxlength="3" class="edit-input font-pop" value="0"
                               name="quantidade-produto[]">
                    </div>

                    <div class="text-center select_height">
                        <b>Preço do Produto:</b>
                        <div class="font-pop preco-produto" onchange="split()">R$ 0</div>
                    </div>

                    <div class="text-center select_height">
                        <button class="remover">X</button>
                    </div>
                </div>
            </div>
            <button id="add-button" onclick="">+</button>
        </div>

        <div class="container" id="produto-total">
            <div class="assinatura col-lg-6">
                Assinatura
            </div>

            <div class="preco-final col-lg-6">
                <b>Preço total:</b>
                <div id="total"></div>
            </div>
        </div>

Jquery:

function initProdutos(e) {
    var wraper = $(e).closest(".produtos-wrap"); // pega a div principal
    var letras_produtos = $(e).val()
    const $preco = $("[name='preco[]']", wraper);
    const $qtd = $("[name='quantidade-produto[]']", wraper);
    const $total = $(".preco-produto", wraper);
    const $final = $('#total');

    function recalculate() {
        const total = Number($preco.val() || 0) * Number($qtd.val() || 0);
        $total.text("R$ " + total);
    }

    function sub(){
        $($preco).on('change',function () {
            var sub = $(this).val().replace(',', '.');
            $(this).val(sub);
        })
    }

    function split(){
        $($total).each(function () {
            var str = $(this).html();
            var res = str.split(" ");
            $($final).text(res[1]);
        })
    }

    function total(){
        $('.preco-produto div').on('change',function () {
            var t = 0;
            $('.preco-produto').each(function (i,e) {
                if ($(e).val()){
                    if (isNaN(i)) {$(e).val(''); return; }
                    t += parseFloat(i);
                    $($final).text('R$ ' + t.toFixed(2));
                }
            })
        })
    }

    $.ajax({
        type: "GET",
        url: "API.php",
        data: {
            "mode": "produtos", letras_produtos
        },
        dataType: "JSON",
        //CASO DÊ TUDO CERTO
        success: function (data) {
            $('[name="embalagem[]"]', wraper).val(data[0]['embalagem']);
            $('.number_id_produto', wraper).text(data[0]['id_produto']);
            recalculate();
            sub();
            total();
        },
        error: function (request, error) {
            console.log(error);
        }
    });
    $preco.on('input', recalculate, sub());
    $qtd.on('input', recalculate);
    $total.on('div',split(),total());
    $final.on('div',split(),total());
    recalculate();
    sub();
    split();
    total();
};

2 answers

1


First you need to create a Event Handler for the price and quantity fields using the event input (this event is triggered in real time whenever you change the fields).

Also create a separate function to format the value in "R$ X,XX" format using .toLocaleString().

And create another function to do the general calculation (calculos()). This function will also call you when removing a div from the list.

In the Event Handler you will go through all the elements with the class .preco-produto and keep adding up the values. Just enter the code below (with explanatory comments):

function calculos(){
   // variável do total
   var total = 0;
   // soma tudo e coloca na div do total
   $(".preco-produto").each(function(){
      // pega apenas o valor e ignora o "R$", remove o ponto e substitui vírgula por ponto
      var p = parseFloat($(this).text().match(/[\d|,|\.]+/)[0].replace(".", "").replace(",", "."));
      total += p;
   });
   // coloca o valor total na div "total"
   $("#total").text(formataMoeda(total));
}

$(document).on("input", "[name='preco[]'], [name='quantidade-produto[]']", function(){
   // pega a div principal
   var wraper = $(this).closest(".produtos-wrap");
   // pega a quantidade   
   var qtd_produto = $("[name='quantidade-produto[]']", wraper).val();
   // pega o preço
   var preco_produto = $("[name='preco[]']", wraper).val().replace(",", ".");
   // div com o valor do produto
   var total_produto = $(".preco-produto", wraper);
   // coloca o valor total do produto
   total_produto.text(formataMoeda(qtd_produto * preco_produto));
   calculos(); // chama a função para calcular o total geral
});

// função para formatar a moeda em Real
function formataMoeda(v){
   return v.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' });
}
  • Sam, he’s making an error in the '.toLocaleString' function, did I put his code in the wrong place or something ? On the console it looks like this: https://prnt.sc/o1wroo , https://prnt.sc/o1wrxa

  • Would it be better if I changed the 'price-product' element from DIV to an input ? Or you won’t have any future problems ?

  • The function of formatting the coin has to have a value. Note that you only put formatMoeda() without a value.

  • Leave as div has no problem at all, it is even better because it is only an illustrative element to show the value.

  • I was able to fix this question, now it occurs that, whenever I remove some DIV that was with its value added in the "Total", this value is not subtracted from the Total value. How can I ask this question ?

  • I changed the answer. Just call the function calculos() at the end of the function that removes an item from the list.

  • It worked out, thank you very much Sam. You would have an indication of some material or something of a kind for me to delve into the study in Jquery / Javascript ?

  • W3 Schools is a good place to start.

  • Okay, thank you so much for the tip and for the help Sam, thank you from my heart !

  • Sam, I’m sorry to bother you, but I’d like to ask you a question about a bug that’s occurring with this code. If the value of the product by a decimal value, in the Total it does not read, and if the quantity of the product is greater than 100, the Total also Buga. What may be happening Print’s: https://prnt.sc/o2wbuf , https://prnt.sc/o2wc2n

  • Just correcting, if the price of the Product passes the value of R$999, the Total price already Uga.

  • 1

    Oops! Blz? Replace this line: var p = parseFloat($(this).text().match(/[\d|,|\.]+/)[0].replace(".", "").replace(",", "."));

  • It worked, thank you Sam !

Show 8 more comments

0

Are you trying to listen to events that don’t exist in div. Events should be heard directly on the buttons and inputs of your cart.

See the example below and try to adapt it to your need.

var produtos = [
  {codigo: '001', nome: "Arroz", valor: 1.99},
  {codigo: '002', nome: "Feijão", valor: 12.25},
  {codigo: '003', nome: "Ovo", valor: 6.11},
  {codigo: '004', nome: "Farinha", valor: 7.07},
];

produtos.forEach(function (item) {
  $('<option />')
    .attr('value', item.codigo)
    .text(`${item.nome} - R$ ${item.valor}`)
    .appendTo('#produtos');
});

$(document).on('click', '#btn-add', function () {
  var $dropdown = $('#produtos'), codigo = $dropdown.val();
  
  // 1. Se dropdown não possui nenhum item selecionado nao faça nada
  if (!codigo.length) return;
  
  // obter o item pelo codigo
  var item = getProdutoByCodigo(produtos, codigo);
  
  // 2. Se item selecionado já está no carrinho, 
  // incrementar a quantidade se nao tiver adiciona-lo
  if (!$(`tr#${item.codigo}`).length) addProduto(item);
  else incrementarQuantidade(item);
  
  atualizarTotal();
});

$(document).on('change', '.field-qtd', function () {
  var $this = $(this), 
      item = getProdutoByCodigo(produtos, $this.data('codigo')), 
      qtd = $this.val(),
      subTotal = (qtd * item.valor).toFixed(2);
  
  $this.parents('tr').find('.subtotal').text(`R$ ${subTotal}`);
  atualizarTotal();
});

$(document).on('click', '.btn-remover', function () {
  $(this).parents('tr').remove();
  atualizarTotal();
});

function getProdutoByCodigo(produtos, codigo) {
  return produtos.filter(produto => produto.codigo === codigo)[0];
}

function createDropdownQuantidade(item) {
  var $dropdown = $('<select />')
    .attr({name: 'quantidade'})
    .addClass('form-control field-qtd')
    .data('codigo', item.codigo);
    
   for (var i = 1; i < 100; i ++) {
    $('<option />').attr('value', i).text(i).appendTo($dropdown);
   }
   
   return $dropdown;
}

function addProduto(item) {  
  var $tr = $('<tr />').attr('id', item.codigo);
  $('<td />').text(item.codigo).appendTo($tr);
  $('<td />').text(item.nome).appendTo($tr);
  $('<td />').append(createDropdownQuantidade(item)).appendTo($tr);  
  $('<td />').text(`R$ ${item.valor.toFixed(2)}`).appendTo($tr);
  $('<td />').addClass('subtotal').text(`R$ ${item.valor.toFixed(2)}`).appendTo($tr);
  
  var $button = $('<button />')
    .addClass('btn btn-danger btn-remover')
    .html('&times;')
    .attr('title', 'Remover');
    
  $('<td />').append($button).appendTo($tr);
  
  $tr.appendTo('#cart-body');
}

function incrementarQuantidade(item) {
  var $dropdown = $(`tr#${item.codigo}`).find('select'), qtd = $dropdown.val();
  $dropdown.val(++qtd).trigger('change');
}

function atualizarTotal() {
  var total = 0;
  $('#cart-body').find('tr').each(function () {
    var codigo = $(this).attr('id'), 
        qtd = $(this).find('.field-qtd').val(), 
        item = getProdutoByCodigo(produtos, codigo);
  
    total += (qtd * item.valor);
  });
    
  $('.total').text(`R$ ${total.toFixed(2)}`);
}
.field-qtd {max-width: 100px;}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

<div class="form-inline my-3">
 <select name="produtos" id="produtos" class="form-control">
  <option value="">- Selecione -</option>
 </select>
 <button type="button" class="btn btn-primary ml-2" id="btn-add">Add</button>
</div>

<table class="table">
  <thead>
    <th>Código</th>
    <th>Produto</th>
    <th>Qtd</th>
    <th>Preço unitário</th>
    <th>Subtotal</th>
    <th>Remover</th>
  </thead>
	
  <tbody id="cart-body"></tbody>
  <tfoot>
    <tr>
      <td colspan="5" class="text-right text-uppercase border-top">total</td>
      <td class="total border-top">R$ 0.00</td>
    </tr>
  </tfoot>
<table>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.