jquerytogglebutton

Bootstrap5 Toggle No Event Response With jQuery.Clone(True)


I enjoy the practicality of Bootstrap5 Toggle plugin. The purpose of plugin provide user the option to toggle from one Module A to Module B. Each line item is wrap under DIV class .lineitem-wrapper.

Other elements in .lineitem-wrapper includes span and input text which are link to events. Work like a charm.

However, the issue comes with the clone elements of lineitem-wrapper and the toggle plugin stop responding. The other elements like span and input text events are working absolutely fine.

$('.btn-lineitem-add-stkgl').on('click', function(e) {

  //clone with event the last lineitem-wrapper 
  new_lineitemStkGL = $('.lineitems-wrapper').last().find('.lineitem-wrapper').clone(true);
  //....

  //tried the destroy and initialize method but same error
  // $('.check-moduleId').bootstrapToggle('destroy');
  //$('.check-moduleId').bootstrapToggle();

  $('.lineitems-wrapper').append(new_lineitemStkGL);
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/css/bootstrap.min.css" integrity="sha512-Ez0cGzNzHR1tYAv56860NLspgUGuQw16GiOOp/I2LuTmpSK9xDXlgJz3XN4cnpXWDmkNBKXR/VDMTCnAaEooxA==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/js/bootstrap.min.js" integrity="sha512-EKWWs1ZcA2ZY9lbLISPz8aGR2+L7JVYqBAYTq5AXgBkSjRSuQEGqWx8R1zAX16KdXPaCjOCaKE8MCpU0wcHlHA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<link href="https://cdn.jsdelivr.net/npm/bootstrap5-toggle@5.1.1/css/bootstrap5-toggle.min.css" rel="stylesheet">

<script src="https://cdn.jsdelivr.net/npm/bootstrap5-toggle@5.1.1/js/bootstrap5-toggle.ecmas.min.js"></script>

<div class="row"><div class="col"><a href="#" class="btn btn-otline-dark me-0  rounded-1  btn-lineitem-add-stkgl"><i class="mdi mdi-playlist-plus "></i> Add new item</a></div></div>


<div class="row lineitems-wrapper mb-1">
  <div class="row lineitem-wrapper mb-1">
    <!-- line item module by toggle -->
    <div class="col-1 m-0">
      <input
        type="checkbox"
        class="pm-0 check-moduleId"
        data-size="sm"
        checked
        data-toggle="toggle"
        data-onlabel="GL"
        data-offlabel="STK"
        data-onstyle="primary"
        data-offstyle="warning">
    </div>
    <div class="col-3 pm-0 ">
      <div class="input-group">
        <input type="text" class="form-control input-lineitem-code px-1 " placeholder="Select Stock / GL ">
        <!-- the stkgl edit btn -->
        <div class="input-group-prepend position-relative">
          <span class="input-group-text text-primary mdi mdi-magnify border-bottom-0 px-1 btn-lineitem-edit-stkgl cursor-pointer"> </span>
        </div>
      </div>
    </div>
  </div>


Solution

  • The issue you are having when attempting to clone the last row to append a new row to the target area, is because the bootstrap-toggle component needs to be initialized over the corresponding input type="checkbox".

    Such stage happens when the page is loaded, and all elements already existing at that time and matching the criteria, will be changed as bootstrap-toggles.

    If you try to clone such a row having its inner toggle already initialized, will cause you to clone the whole toggle initialized for the original row and it will be messed up for its new role in a different row.

    So what you need to do to achieve that result, is having a template element describing a row, that won't be affected by the initialization stage occuring at page load so that you will be using this one to create your clones that will be initialized on demand at the time of appending.

    I created a very simple demo to show a simple scenario...

    <template> : The Content Template element

    The HTML element serves as a mechanism for holding HTML fragments, which can either be used later via JavaScript or generated immediately into shadow DOM.

    https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content

    The HTMLTemplateElement.content property returns a element's template contents (a DocumentFragment).

    $('.btn-lineitem-add-stkgl').on('click', function(e) {        
        
        //fetch the content of the template row
        const templateContent = $('#row').prop('content');    
        
        //clone its elements
        const newLineItem = $(templateContent).children().clone(true);    
        
        //append the cloned elements to the target area
        $('.lineitems-wrapper').append(newLineItem);    
        
        //initialize the bootstrap toggle on the new row by calling the corresponding method on the input element
        newLineItem.find('.check-moduleId')[0].bootstrapToggle();  
    });
    <!-- bootstrap.min.css -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/css/bootstrap.min.css" integrity="sha512-Ez0cGzNzHR1tYAv56860NLspgUGuQw16GiOOp/I2LuTmpSK9xDXlgJz3XN4cnpXWDmkNBKXR/VDMTCnAaEooxA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    
    <!-- jquery.min.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <!-- bootstrap.min.js -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/js/bootstrap.min.js" integrity="sha512-EKWWs1ZcA2ZY9lbLISPz8aGR2+L7JVYqBAYTq5AXgBkSjRSuQEGqWx8R1zAX16KdXPaCjOCaKE8MCpU0wcHlHA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    
    <!-- bootstrap5-toggle.min.js -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap5-toggle@5.1.1/css/bootstrap5-toggle.min.css" rel="stylesheet">
    
    <!-- bootstrap5-toggle.ecmas.min.js -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap5-toggle@5.1.1/js/bootstrap5-toggle.ecmas.min.js"></script>
    
    <!-- add new item button -->
    <div class="row mx-2 my-2">
      <div class="col">
        <a href="#" class="btn btn-outline-dark rounded-1 btn-lineitem-add-stkgl">
          <i class="mdi mdi-playlist-plus"></i> Add new item
        </a>
      </div>
    </div>
    
    <hr>
    
    <!-- target zone for appending new items -->
    <div class="row lineitems-wrapper mx-1">    
    </div>
    
    <!-- template for new row to be appended -->
    <template id="row">
      <div class="row lineitem-wrapper mb-1">    
        <div class="col-2">
          <input
            type="checkbox"
            class="pm-0 check-moduleId"
            data-size="sm"
            checked
            data-toggle="toggle"
            data-onlabel="GL"
            data-offlabel="STK"
            data-onstyle="primary"
            data-offstyle="warning">
        </div>      
        <div class="col-5">
          <div class="input-group">
            <input type="text" class="form-control input-lineitem-code px-1" placeholder="Select Stock / GL ">        
          </div>
        </div>    
      </div>
    </template>