Add and Remove Divs Function with PHP and jQuery

Asked

Viewed 166 times

0

Good morning guys, I’m facing a problem and I’d like to know if anyone can help me. I have developed a code to add and remove Divs dynamically and with autoincrement and decrease of the index. The problem occurs where the DIV increment starts at "1" but does not exceed "2" and, in addition, the first standard DIV, when adding another, is unusable, I can no longer change the information of the same. Another problem occurs in the action of adding other Divs, causing the information chosen in the previous Divs to be reset. My Remove function, whenever I remove any DIV, your next DIV should take your number by doing the decrease, which is not happening. Someone can give me a light ?

index php.:

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

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

                <div class=" select_height" id="div_produtos">
                    <b>Produto:</b>
                    <select class="selectpicker form-control" data-show-subtext="false" data-live-search="true" name="select_produtos-1" id="select_produtos-1" onchange="initProdutos(1);">
                        <?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" id="embalagem-1" name="embalagem-1" value="">
                </div>

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

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

                <div class="text-center select_height">
                    <b>Preço do Produto:</b>
                    <div id="preco-produto-1" name="preco-produto-1" class="font-pop"></div>
                </div>

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

Elements.php:

<?php
error_reporting(0);
$id = $_GET['id'];

header('Content-Type: text/html; charset=utf-8');
# Coloquei o charset no começo, é melhor que a página toda obedece ele se estiver aqui, e mudei pra utf-8 pra funcionar os caracteres especiais

$servidor = 'localhost';
$usuario = 'root';
$senha = '';
$dbname = 'testevip';

$connect = mysqli_connect($servidor, $usuario, $senha, $dbname);
$query_produtos = "SELECT * FROM produto ORDER BY desc_produto ASC";
$result2 = mysqli_fetch_all(mysqli_query($connect, $query_produtos), MYSQLI_ASSOC);

mysqli_close($connect);
?>
<div class="produtos-wrap" id="wrap-produtos-<?=$id?>" name="wrap-produtos-<?=$id?>">
    <div class=" text-center select_height">
        <b>Número:</b>
        <div id="index" class="font-pop"><?=$id?></div>
    </div>

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

    <div class=" select_height" id="div_produtos">
        <b>Produto:</b>
        <select class="selectpicker form-control" data-show-subtext="false" data-live-search="true" name="select_produtos-<?=$id?>" id="select_produtos-<?=$id?>" onchange="initProdutos(<?=$id?>);">
            <?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" id="embalagem-<?=$id?>" name="embalagem-<?=$id?>" value="">
    </div>

    <div class="text-center select_height">
        <b>Preço:</b>
        <br>
        <input type="text" maxlength="5" id="preco-<?=$id?>" name="preco-<?=$id?>" class="edit-input font-pop">
    </div>

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

    <div class="text-center select_height">
        <b>Preço do Produto:</b>
        <div id="preco-produto-<?=$id?>" name="preco-produto-<?=$id?>" class="font-pop"></div>
    </div>

    <div class="text-center select_height">
       <button id="remove-<?=$id?>" name="remove-<?=$id?>" class="remover" >X</button>
    </div>
</div>

Jquery:

function initProdutos(product_id) {
    var product = ((product_id === undefined) ? 1 : product_id);
    var letras_produtos = $("#select_produtos-" + product).val()
    const $preco = $("#preco-" + product);
    const $qtd = $("#quantidade-produto-" + product);
    const $total = $("#preco-produto-" + product);

    function recalculate() {
        const total = Number($preco.val() || 0) * Number($qtd.val() || 0);
        $total.text("R$ " + total);
    }
    $.ajax({
        type: "GET",
        url: "API.php",
        data: {
            "mode": "produtos", letras_produtos
        },
        dataType: "JSON",
        //CASO DÊ TUDO CERTO
        success: function(data) {
            console.log(data);
            $('#embalagem-' + product).val(data[0]['embalagem']);
            $('#number_id_produto-' + product).text(data[0]['id_produto']);
            $preco.val(data[0]['preco_base']);
            recalculate();
        },
        error: function(request, error) {
            console.log("Request: " + JSON.stringify(request));;
        }
    });
    $preco.on('input', recalculate);
    $qtd.on('input', recalculate);
    recalculate();
};


var index = 1;
$(function () {
    var id = index + 1;
    $.ajax({
        type: "GET",
        url: "elements.php?id=" + id,
        //CASO DÊ TUDO CERTO
        success:function(data){
            $(document).on('click', '#add-button', function () {
                const div = document.getElementById('allProducts');
                div.innerHTML += data;
                index = id;
            })
            $(document).on('click', '.remover', function () {
                $(this).parents('.produtos-wrap').remove();
                index = id - 1;
            })
        },
        error:function(request, error)
        {
            console.log(error);
            // console.log("Request: " + JSON.stringify(request));
        }
    });
})

Finally a print of how it is in the browser: https://prnt.sc/o0i6fw

  • It is not the best way to put id on everything that is element (by the way, it is the worst form). This is because it will not work if a div is removed in the middle of the others, because it will get a smaller id that already exists. Use only one id to identify the entire div and each addition and removal, use a function to rearrange the numbering. In short, you have to reevaluate the code.

  • I understand Sam. Do you know of any other question that has a similar topic that I can take from reference, some video or material on the internet, or even a hint of how I can start refactoring code in the right way ?

  • I’ll post an answer.

1 answer

2


As I commented, it does not need (nor does it make sense) to put id’s in everything that is element, or change the Names with different names.

The only thing you need to enumerate is the text of this div below, which enumerates the list:

<div id="index" class="font-pop">1</div>

Only instead of using id="index", use class="index". That’s because when you clone the div, use id="index", will duplicate the id, and this can not. Already the class you can duplicate without problems. So it will be like this:

<div class="index" class="font-pop">1</div>

Another point is that you do not need to use AJAX to insert a div equal to the one that is already loaded on the page. Simply clone the one that exists. Therefore, you do not need to use AJAX. Instead, create a function that clones the div, using .append().

To do this, create a copy of the div by loading the page:

$(function () {
   var clone = $('#allProducts').html(); // cópia da div existente
   ...

And the function that will add a new div:

function addProd(){
   $('#allProducts').append(clone);
   ids(); // enumera as divs
}

The function ids() is to enumerate the Divs. It should be called whenever a div is added or removed:

function ids(){
   $(".index").each(function(i,e){
      $(e).text(i+1);
   });
}

It will fetch all classes .index and change the text with the numbers in the sequence.

This part of the script will be so complete:

$(function () {
   var clone = $('#allProducts').html();
   $(document).on('click', '#add-button', addProd);

   $(document).on('click', '.remover', function () {
      $(this).parents('.produtos-wrap').remove();
      ids();
   });

   function addProd(){
      $('#allProducts').append(clone);
      ids();
   }

   function ids(){
      $(".index").each(function(i,e){
         $(e).text(i+1);
      });
   }
})

THE HTML

Remove all id’s and change the name's in array form, adding the brackets at the end of the name, in this way, for example:

<input type="text" maxlength="2" class="edit-input font-pop" name="embalagem[]" value="">
                                                                            ↑↑

And remove the name of Divs, because this attribute is for form elements (input, select etc).

Withdraw the id="number_id_produto" and add the class .number_id_produto in the div concerning ID:

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

Add a class .preco-produto in the div of the product price to be found.

At the end, your HTML should look like this:

<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"></div>
       </div>

       <div class=" select_height">
           <b>Produto:</b>
           <select class="selectpicker form-control" 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">
       </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"></div>
       </div>

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

Issue of select onchange

Change the parameter to this:

onchange="initProdutos(this);"

The this will be received at the function initProdutos, which will be select itself. Then just search for the main div of select with .closest(".produtos-wrap") and use .find() to find the elements you want, which can be by name, since they are unique.

The function initProdutos should stay that way:

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);

    function recalculate() {
        const total = Number($preco.val() || 0) * Number($qtd.val() || 0);
        $total.text("R$ " + total);
    }
    $.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']);
            $preco.val(data[0]['preco_base']);
            recalculate();
        },
        error: function(request, error) {
            console.log("Request: " + JSON.stringify(request));;
        }
    });
    $preco.on('input', recalculate);
    $qtd.on('input', recalculate);
    recalculate();
};
  • Sam, thank you so much for your help and explanation. I switched the code to do the test, and the Divs part is working perfectly, but the uploading of the data coming from the bank is not happening. The error that comes back to me through the console, is the "parsererror" in the function initProducts. You know that can be ?

  • There’s a clasp on this line: const $qtd = $("[name='quantidade-produto[]']", wraper);

  • Here too: $('[name="embalagem[]"]'

  • 1

    Oh yes, I closed the missing ones and it worked. Thank you so much for the help Sam, thank you from my heart for the explanation, helped me a lot to understand how I should have done !

Browser other questions tagged

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