Not able to drop element when creating dynamic divs to drag and drop element in

Following up on my previous question. It works perfectly. But when I dynamically create the divs where the li element is dropped in, I am not able to drop the element in it.

I am using the basic HTML drag and drop feature. Why is the on drop working with dynamically created div?

Here is my code:

    ['harry', 'hermione', 'ron', 'ginny', 'luna'].forEach(met => {
        $(`#char`).append(`
            <div class="form-check py-1">
            <label class="form-check-label">
            <input type="checkbox" class="form-check-input pickTarget" name='checkTarget' value="${met}">${met}
            </label>
            </div>
            `);
    });

    $('.pickTarget').click(function() {
        let unselected = $('.pickTarget:checked').length >= 3;
        $('.pickTarget').not(":checked").attr("disabled", unselected);
    });

    $('.pickTarget').change(function() {
        if ($(this).is(':checked')) $(this).parent().append(`<div style='border: 1px solid red' class='float-right ml-3 text-muted target' id='drop_${this.value}'>Drag Number</div>`);
        else $(`#drop_${this.value}`).remove();
    });

    $('#list').on('dragstart', 'li', function(e) { e.originalEvent.dataTransfer.setData('text', e.target.id); });

    var $target = $('.target');
    var $list = $('#list');

    $target.on('drop', function(e) {
        e.preventDefault();
        let data = e.originalEvent.dataTransfer.getData('text');
        $list.append($(this).html());
        $(this).html($(`#${data}`));
    });

    $target.on('dragover', function(e) { e.preventDefault(); });
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<br />
<div id='char' class='w-50 float-left h-50 overflow-auto ml-5'><b>Characters</b> (select 3)</div>

<br />
<ul id="list" class='list-group d-inline-block ml-2'>
    <li id="drag1" class='list-group-item py-1' draggable='true' data-order="1">one</li>
    <li id="drag2" class='list-group-item py-1' draggable='true' data-order="2">two</li>
    <li id="drag3" class='list-group-item py-1' draggable='true' data-order="3">three</li>
</ul>

In my code, once you click on the checkbox next to a Harry Potter character, it creates a div. After selecting the 3 divs (only 3 allowed), divs are created next to the check box. I want to drag each of the one, two & three to each of the divs. Why is it not working?

Here is the fiddle for my code.

Answer

Your target divs are dynamically created so you need to bind that with static elements which are already present inside your dom . So , just use $("#char").on('drop', '.target',.. and same for dragover event .

Also, in your code when user uncheck the checkbox and if there are any li item inside target div they are also get removed . Instead you check if the target div has any class with name list-group-item if yes then just clone that element and then append same to your list and finally remove whole div .

Demo Code :

['harry', 'hermione', 'ron', 'ginny', 'luna'].forEach(met => {
  $(`#char`).append(`
            <div class="form-check py-1">
            <label class="form-check-label">
            <input type="checkbox" class="form-check-input pickTarget" name='checkTarget' value="${met}">${met}
            </label>
            </div>
            `);
});

$('.pickTarget').click(function() {
  let unselected = $('.pickTarget:checked').length >= 3;
  $('.pickTarget').not(":checked").attr("disabled", unselected);
});

$('.pickTarget').change(function() {
  if ($(this).is(':checked')) {
    $(this).parent().append(`<div style='border: 1px solid red' class='float-right ml-3 text-muted target' id='drop_${this.value}'><span class='${this.value}'>Drag Number</span></div>`);
  } else {
    //check if the div has li item inside it 
    if ($(`#drop_${this.value}`).find(".list-group-item").length > 0) {
      var cloned = $(`#drop_${this.value}`).find(".list-group-item").clone() //yes clone it
      $("#list ." + this.value).remove(); //remove Drag Number span
      $("#list").append($(cloned)) //append li again in list
    }
    $(`#drop_${this.value}`).remove(); //finally remove div
    //you can write code for sorting lis ..here 
  }
});

$('#list').on('dragstart', 'li', function(e) {
  e.originalEvent.dataTransfer.setData('text', e.target.id);
});
var $list = $('#list');
//change this
$("#char").on('drop', '.target', function(e) {
  e.preventDefault();
  let data = e.originalEvent.dataTransfer.getData('text');
  $list.append($(this).html());
  $(this).html($(`#${data}`));
});
//change this
$("#char").on('dragover', '.target', function(e) {
  e.preventDefault();
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<br />
<div id='char' class='w-50 float-left h-50 overflow-auto ml-5'><b>Characters</b> (select 3)</div>
<br />
<ul id="list" class='list-group d-inline-block ml-2'>
  <li id="drag1" class='list-group-item py-1' draggable='true' data-order="1">one</li>
  <li id="drag2" class='list-group-item py-1' draggable='true' data-order="2">two</li>
  <li id="drag3" class='list-group-item py-1' draggable='true' data-order="3">three</li>
</ul>