jqueryjquery-select2selectinput

Multiple select2 input of the same class on same page


This code gives add-more functionality with jquery clone & Append methods for select2 input which is not responding after clicking add more. What am I missing?

    <div class="row">

      <div class="col-md-12 service-group">
            <div class="row">
                <div class="form-group mb-3 col-md-6">
                    <label class="form-label">Service</label>
                    <div >
                        <select type="text" class="form-select service-select" placeholder="Services" value="" name="items[0][service]" id="service-0" required>
                            <option value="" disabled selected>Select your option</option>
                            @foreach ($services as $service)
                                <option value="{{$service->service_name}}"  data-id="{{$service->amount}}">{{$service->service_name}}</option>
                            @endforeach
                            
                            
                        </select>
                        
                    </div>
                    </div>

                    <div class="form-group mb-3 col-md-6">
                    <label class="form-label">Amount</label>
                    <div >
                        <input type="text" class="form-control" name="items[0][amount]" id="amount-0" placeholder="Amount"  required>
                  
                    </div>
                </div>
                <div class="form-group mb-3 col-md-12">
                  <label class="form-label">Description</label>
                  <textarea class="form-control" id="description-0" name="items[0][description]" rows="6" placeholder="Description.." required></textarea>
              </div>
            </div>

      </div>

      
    </div>

</div>

<div class="more-service-box"></div>

<div class="col-md-12">
    <button type="button" id="addmore" class="btn btn-default"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-plus" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
      <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
      <circle cx="12" cy="12" r="9"></circle>
      <line x1="9" y1="12" x2="15" y2="12"></line>
      <line x1="12" y1="9" x2="12" y2="15"></line>
  </svg> Add More</button>
    <button type="button"   id="remove" class="btn btn-default"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-minus" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
      <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
      <circle cx="12" cy="12" r="9"></circle>
      <line x1="9" y1="12" x2="15" y2="12"></line>
  </svg> Remove</button>
</div>
  $(".service-select").select2({
    placeholder: "Select a programming language",
    allowClear: true
  });


// Add Service , Amount, Description
$('#addmore').click(function () {

    var index = $('.service-group').length;
    
    var $service = $('.service-group:first').clone();

    $service.find('select[name*=service]')
        .val('')
        .attr('name', 'items[' + index + '][service]')
        .attr('id', 'service-' + index);

    $service.find('input[name*=amount]')
        .val('')
        .attr('name', 'items[' + index + '][amount]')
        .attr('id', 'amount-' + index);

    $service.find('textarea[name*=description]')
        .val('')
        .attr('name', 'items[' + index + '][description]')
        .attr('id', 'description-' + index);

        
        

    $service.appendTo('.more-service-box');


    $("body").on("change", "select[id=service-"+ index +"]", function() {
        //get amount for data-attribute
        var amount = $(this).find("option:selected").data("id");
        //assign value
        $(this).closest(".service-group").find("input[id=amount-"+ index +"]").val(amount)
    })


   
    
});



$("body").on("change", "select[id=service-0]", function() {
    //get amount for data-attribute
    var amount = $(this).find("option:selected").data("id");
    //assign value
    $(this).closest(".service-group").find("input[id=amount-0]").val(amount)
})





$("#remove").on("click", function() {  
    $(".more-service-box").children().last().remove();  
});  

Solution

  • You need to initialise any new selects after they are added to the DOM. The initial $(".service-select").select2( will only apply to the ones that exist at the time.

    In your code, the first step would be to copy the initialisation code to after $service.appendTo:

    $service.appendTo('.more-service-box');
    $('#service-' + index).select2({
        placeholder: "Select a programming language",
        allowClear: true
    });
    

    However, this will only work if you create a new select (without the ).

    Normally you would clone a <template> which wouldn't be initialised to a , but as you're cloning .service-group:first there's an added complication: if you clone() a parent, it clones the [tag:select2] elements so when you re-init it with .select2() it doesn't work (as the elements are already there).

    The ideal solution would be to use a <template> (as that's what it's for).

    In your case, you need to remove the before cloning, then add it back after cloning.

    $('.service-group:first').find("select").select2("destroy")
    

    Updated snippet:

    $(".service-select").select2({
      placeholder: "Select a programming language",
      allowClear: true
    });
    
    $('#addmore').click(function() {
      var index = $('.service-group').length;
      $('.service-group:first').find("select").select2("destroy")
      var $service = $('.service-group:first').clone();
      
      $service.find('select[name*=service]')
        .val('')
        .attr('name', 'items[' + index + '][service]')
        .attr('id', 'service-' + index);
    
      $service.appendTo('.more-service-box');
    
      $('.service-group').find("select").select2({
        placeholder: "Select a programming language",
        allowClear: true
      });
    });
    
    $("#remove").on("click", function() {
      $(".more-service-box").children().last().remove();
    });
    <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/css/select2.min.css" rel="stylesheet" />
    <script src="//code.jquery.com/jquery-2.2.4.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.4/js/select2.min.js"></script>
    
    <div class="row">
      <div class="col-md-12 service-group">
        <div class="row">
          <div class="form-group mb-3 col-md-6">
            <label class="form-label">Service</label>
            <div>
              <select type="text" class="form-select service-select" placeholder="Services" value="" name="items[0][service]" required>
                <option value="" disabled selected>Select your option</option>
                <option value="service 1">service 1</option>
                <option value="service 2">service 2</option>
                <option value="service 3">service 3</option>
              </select>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <div class="more-service-box"></div>
    
    <div class="col-md-12">
      <button type="button" id="addmore" class="btn btn-default">Add More</button>
      <button type="button" id="remove" class="btn btn-default">Remove</button>
    </div>