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();
});
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 select2).
Normally you would clone a <template>
which wouldn't be initialised to a select2, but as you're cloning .service-group:first
there's an added complication: if you clone()
a select2 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 select2 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>