0

I am working on the below code. Why am I not able to use the $('.quantity').each(function() when adding the content dynamically to the document? As you can see the $('.quantity').each() is functioning properly when is hard coded but not working on dynamic content.

$("#add").on("click", function(){
   $("#content").empty();
   for (var i = 0; i < 2; i++) {
   $("#content").append(`<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
    <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
    <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
    <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>`);
   }
   
});

 $('.quantity').each(function() {
        var spinner = jQuery(this),
            input = spinner.find('.number'),
            btnUp = spinner.find('.quantity-up'),
            btnDown = spinner.find('.quantity-down'),
            val = input.text(),
            min = input.data('min'),
            max = input.data('max');
        spinner.find(".number").text(val);
          btnUp.click(function() {
            var oldValue = parseFloat(input.text());
            if (oldValue >= max) {
                var newVal = oldValue;
            } else {
                var newVal = oldValue + 1;
            }
            spinner.find(".number").text(newVal);
            spinner.find(".number").trigger("change");
        });

        btnDown.click(function() {
            var oldValue = parseFloat(input.text());
            if (oldValue <= min) {
                var newVal = oldValue;
            } else {
                var newVal = oldValue - 1;
            }
            spinner.find(".number").text(newVal);
            spinner.find(".number").trigger("change");
        });

    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">Add Content</button>
<h3>Dynamic <sub> Not Working</sub></h3>

<div id="content"></div>
========================================
<h3>Hard Coded <sub> Working</sub></h3>
<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
    <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
    <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
    <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>
halfer
  • 18,701
  • 13
  • 79
  • 158
Behseini
  • 5,416
  • 18
  • 60
  • 107
  • Why add event handlers in a loop anyway? Just use event delegation; see [Event binding on dynamically created elements?](https://stackoverflow.com/q/203198/215552). – Heretic Monkey Jul 23 '20 at 15:12

3 Answers3

1

On DOM load, a listener is set on all elements with the specified class. Later when an element is loaded dynamically, that element lacks the listener.

One solution is to make the listener adder a function and call it whenever the dynamic content is added. I have edited the snippet for this solution.

Else, you can seperate the click listener function and add it in the dynamic content during creation.

$("#add").on("click", function(){
   $("#content").empty();
   for (var i = 0; i < 2; i++) {
   $("#content").append(`<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
    <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
    <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
    <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>`);
   }
   
listenerAdd();
});

function listenerAdd(){
 $('.quantity').each(function() {
        var spinner = jQuery(this),
            input = spinner.find('.number'),
            btnUp = spinner.find('.quantity-up'),
            btnDown = spinner.find('.quantity-down'),
            val = input.text(),
            min = input.data('min'),
            max = input.data('max');
        spinner.find(".number").text(val);
          btnUp.click(function() {
            var oldValue = parseFloat(input.text());
            if (oldValue >= max) {
                var newVal = oldValue;
            } else {
                var newVal = oldValue + 1;
            }
            spinner.find(".number").text(newVal);
            spinner.find(".number").trigger("change");
        });

        btnDown.click(function() {
            var oldValue = parseFloat(input.text());
            if (oldValue <= min) {
                var newVal = oldValue;
            } else {
                var newVal = oldValue - 1;
            }
            spinner.find(".number").text(newVal);
            spinner.find(".number").trigger("change");
        });

    });
}
listenerAdd();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">Add Content</button>
<h3>Dynamic <sub> Not Working</sub></h3>

<div id="content"></div>
========================================
<h3>Hard Coded <sub> Working</sub></h3>
<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
    <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
    <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
    <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>
vcode
  • 440
  • 4
  • 8
1

Your code is ok, it's just misplaced. I've taken the code with button logic and wrapped it in a named function. You will use this function when creating new buttons.

Also, your HTML for the new buttons should be wrapped in $(...) to store them and use them after you append them to #content

function enableButtons() {
  var spinner = jQuery(this),
    input = spinner.find('.number'),
    btnUp = spinner.find('.quantity-up'),
    btnDown = spinner.find('.quantity-down'),
    val = input.text(),
    min = input.data('min'),
    max = input.data('max');
  spinner.find(".number").text(val);
  btnUp.click(function() {
    var oldValue = parseFloat(input.text());
    if (oldValue >= max) {
      var newVal = oldValue;
    } else {
      var newVal = oldValue + 1;
    }
    spinner.find(".number").text(newVal);
    spinner.find(".number").trigger("change");
  });

  btnDown.click(function() {
    var oldValue = parseFloat(input.text());
    if (oldValue <= min) {
      var newVal = oldValue;
    } else {
      var newVal = oldValue - 1;
    }
    spinner.find(".number").text(newVal);
    spinner.find(".number").trigger("change");
  });

}
$("#add").on("click", function() {
  $("#content").empty();
  for (var i = 0; i < 2; i++) {
    var buttonElements = $(`<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
    <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
    <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
    <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>`);
    $("#content").append(buttonElements);

    buttonElements.each(enableButtons);
  }

});

$('.quantity').each(enableButtons);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="add">Add Content</button>
<h3>Dynamic <sub> Not Working</sub></h3>

<div id="content"></div>
========================================
<h3>Hard Coded <sub> Working</sub></h3>
<div class="btn-group d-flex btn-num-controls quantity" role="group" aria-label="Basic example">
  <button type="button" class="btn quantity-button quantity-down outline-0">-</button>
  <button type="button" class="btn number cart-odqty" data-min="1" data-max="8" data-step="1" value="1" id="">1</button>
  <button type="button" class="btn quantity-button quantity-up outline-0">+</button>
</div>
darklightcode
  • 2,317
  • 1
  • 12
  • 14
0

You can setup jQuery as a live listener by attaching it to the parent like this:

$("#parent").on("click", ".child", (event) => {...});

This way the listener is attached to all childs, even if they have been added after the listener was setup.

So in your case something like $("document").on("click", "#add", (event) => {...});

mind
  • 382
  • 6
  • 18