Reputation: 2980
I'm using Selectize.js and I need to clone html subform with transformed select elements. After I clone and insert subform select functionality is broken.
I have read that one of the solution is to call destroy() method for cloned selects and after initialize selectize for them again.
I tried to follow this advice and my code looks like:
$(formFields).find("select").each(function(){
if (this.selectize) {
this.selectize.destroy();
}
});
What I expect to see is standard select elements, but I see selectized elements with not working dropdown functionality. Any ideas?
Upvotes: 11
Views: 9208
Reputation: 635
I'll just add my own solution here as well. Thanks to @David Cramblett for his useful answer.
$('select')
.each(function(index, el) {
el.selectize.destroy()
})
This loops through all select elements and unselectizes them. Even though I think running destroy
on all select elements at once would have been preferable (it does not work that way); but this works fine for me.
Upvotes: 0
Reputation: 31
// i equal to duplcate number
let i = 0;
var original = document.querySelector(".duplcate");
$(document).ready(function() {
$(".selectize-select").selectize({
sortField: "text",
});
});
$("#add-student-btn").click(function() {
// Determine if selectize.js is in use on any element and disable
// before cloning.
var selectizeElements = {};
$(original)
.find("select")
.each(function() {
if ($(this)[0].selectize) {
selectedValue = $(this)[0].selectize.getValue();
selectizeElements[$(this).attr("id")] = {
inputOptions: Object.values($(this)[0].selectize.options),
inputValue: $(this)[0].selectize.getValue(),
};
// Destroy the selectize.js element
$(this)[0].selectize.destroy();
}
});
var clone = original.cloneNode(true); // "deep" clone
i = i + 3;
// original.children[0].removeChild(original.children[0].children[2]);
clone.id = "duplicater" + i; // there can only be one element with an ID
clone.style.display = "block";
clone.children[0].children[1].children[0].id = "relation" + i;
clone.children[0].children[0].children[0].id = i;
this.parentNode.parentNode.insertBefore(clone, this.parentNode);
// Clear any data that was already entered in the cloned row
$(clone)
.find("input,select,textarea")
.each(function() {
$(this).val("");
$(this).attr("checked", false);
});
// Re-enable any selectize.js fields if needed, adding back
// any options and selected values to the original row.
if (!$.isEmptyObject(selectizeElements)) {
$.each(selectizeElements, function(key, value) {
$(original)
.find("select#" + key)
.selectize();
});
$(clone)
.find("select.selectize-select")
.selectize();
// Copy back options and values to cloned row
$.each(selectizeElements, function(key, value) {
//return back options and values to orginal element
$(original).find('select#' + key)[0].selectize.addOption(value.inputOptions);
$(original).find('select#' + key)[0].selectize.setValue(value.inputValue);
//add options to the cloned elements
$(clone).find('select#' + key)[0].selectize.addOption(value.inputOptions);
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="post" class="flexAlignCenter flexColumn">
<div class="formGroup">
<div class="inputDetails flexAlignStart flexColumn">
<label for="name">Name</label>
<input type="text" id="name" name="name" placeholder="" required>
</div>
<div class="inputDetails flexAlignStart flexColumn">
<label for="phone">Phone</label>
<input type="number" id="phone" name="phone" placeholder=""
max="999999999">
</div>
</div>
<div class="formGroup">
<div class="inputDetails flexAlignStart flexColumn">
<label for="password">password</label>
<input type="password" id="password" name="password"
placeholder="enter password">
</div>
</div>
<div class="formGroup">
<div class="inputDetails flexAlignStart flexColumn">
<label for="name">Address</label>
<input type="text" id="address" name="address" placeholder="Enter address">
</div>
</div>
<div class="formGroup duplcate">
<div class="formGroup">
<div class="inputDetails flexAlignStart flexColumn">
<label for="name">Student</label>
<select name="student[]" class="form-control selectize-select" id="0">
<option>choose Student</option>
<option value='1'>Student1</option>
<option value='2'>Student2</option>
<option value='3'>Student3</option>
<option value='4'>Student4</option>
</select>
</div>
<div class="inputDetails flexAlignStart flexColumn">
<label for="name">RelationShip</label>
<select name="relation[]" class="form-control selectize-select" id="relation0">
<option >choose relationShip</option>
<option value="1">Father</option>
<option value="2">Mother</option>
<option value="3">Sister</option>
</select>
</div>
</div>
</div>
<div class="add-new-dev-type">
<div class="addClass">
<span id="add-student-btn" style="font-size:32px; ">+</span>
<span >Add student</span>
</div>
<input type="submit" value="submit" />
</div>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.13.3/js/standalone/selectize.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.13.3/css/selectize.min.css" rel="stylesheet"/>
if you have a lot of onchange functions that change other selectize options, you should make a hidden copy from the elements you want to duplicate and add it before the visible one. The cloned one will be created from the hidden one.
Upvotes: 1
Reputation: 89
// When add button is clicked
$('#add').on('click',function(){
$('.combobox').each(function(){ // do this for every select with the 'combobox' class
if ($(this)[0].selectize) { // requires [0] to select the proper object
var value = $(this).val(); // store the current value of the select/input
$(this)[0].selectize.destroy(); // destroys selectize()
$(this).val(value); // set back the value of the select/input
}
});
$('#monsters .form-group:first')
.clone() // copy
.insertAfter('#monsters .form-group:last'); // where
selectizeme(); // reinitialize selectize on all .combobox
});
try visit here: http://mariolurig.com/selectize-demo.htm
Upvotes: 5
Reputation: 585
The selectize object is added to the original select / input element instance. Make sure to add a [0] to specify the selectize object:
$(this)[0].selectize.destroy();
See Selectize API Docs for specific example.
Additionally, I have seen a lot of unanswered questions about cloning selectize.js elements. Here is approximately how I went about the process:
// Trigger when add row button clicked
$('.row-add').click(function() {
// Find last row in table (or div) to clone from
var lastRow = $("myTable").find('tr').last();
// Determine if selectize.js is in use on any element and disable
// before cloning.
var selectizeElements = {};
lastRow.find('select').each(function() {
if ($(this)[0].selectize) {
// Store last row's current options and value(s) to
// restore after destroying for clone purposes.
selectizeElements[$(this).attr('id')] = {
inputOptions: $(this)[0].selectize.options,
inputValue: $(this)[0].selectize.getValue()
}
// Destroy the selectize.js element
$(this)[0].selectize.destroy();
}
});
// Clone last row
newRow = lastRow.clone().insertAfter(lastRow);
// Clear any data that was already entered in the cloned row
newRow.find( 'input,select,textarea' ).each(function() {
$(this).val( '' );
$(this).attr( 'checked', false );
});
// Re-enable any selectize.js fields if needed, adding back
// any options and selected values to the original row.
if (!$.isEmptyObject(selectizeElements) {
$.each(selectizeElements, function(key, value) {
lastRow.find('select#'+key).selectize();
newRow.find('select#'+key).selectize();
})
// Copy back options and values to cloned row
$.each(selectizeElements, function(key, value) {
lastRow.find('select#'+key)[0].selectize.addOption(value.inputOptions);
lastRow.find('select#'+key)[0].selectize.setValue(value.inputValue);
});
}
// I usually update the id and name attribute index number here so
// that each form element has a unique id and name.
});
You can find some working example code in this Repo
Upvotes: 15