I am trying to clone a div, which contains some input, and one of those is the Select2 library, when cloning it clones me but the library does not work.
attached bug: "Uncaught TypeError: Cannot set properties of null (setting 'outerHTML')".
This is my html code.
<div style="width: 100%;">
<div >
<div >
<input id="txtinput0" name="username" placeholder="Enter Full Name" type="text" data-parsley-pattern="^[a-zA-Z\s.] $" />
</div>
</div>
<div >
<div >
<input id="txtinput0" name="email" placeholder="Enter VALID EMAIL and check the result" type="email" />
</div>
</div>
<div >
<div >
<input id="txtinput0" name="phone" placeholder="Enter Phone e.g.: 363012345" type="text" data-parsley-pattern="^\ {1}[0-9] $"/>
</div>
</div>
<div >
<div >
<select multiple="multiple" style="width: 100%;" id="select0" data-placeholder="Select a company" >
<div clas="options">
<option value="1">Google</option>
<option value="1">Amazon</option>
<option value="1">Facebook</option>
<option value="1">Airbnb</option>
</div>
</select>
</div>
</div>
</div>
</div>
<div clas="row box" id="clone"></div>
And this is the javascript with which I try to clone the whole div, including the select2
$(document).ready(function() {
$('#select0').select2();
});
var i=1;
var prev =0;
function addRow() {
var clone = $("#row_examenes").clone()
clone.find("#txtinput" prev).attr("id", "txtinput" i);
clone.find("#select" prev).attr("id", "select" i);
clone.find("#select" prev "_chosen").attr("id", "select" i "_chosen1");
clone.appendTo($("#clone"));
document.getElementById("select" i "_chosen1").outerHTML=""
$myid = $('#select' i);
$myid.show().select2();
i ;
prev ;
}
CodePudding user response:
There are quite a few problems in the code, but the big issue is:
When you initialise a Select2, it hides the original
<select>
and adds some extra HTML on the page. If you then clone the block of HTML where that Select2 is, you clone all that extra Select2 stuff. And if you then try an initialise that cloned stuff as a Select2, it won't work.The fix is described in many duplicate questions here on SO already (try searching for "select2 clone"), here's an example: you need to destroy the original Select2 before cloning it, and then re-initialise it as a Select2 again once it is cloned;
Some of the other issues in the code are:
There is no element with id
row_examenes
. I added it as a<div>
enclosing the<div >
;Once you clone that div, the clone will have the same ID (
row_examenes
), and the code does not change that ... duplicate IDs are invalid HTML. Instead we can clone the<div>
nested inside, with classcloned
;All 3x text
<input>
s have the same ID,txtinput0
- this is invalid, and jQuery will only be able to find the first one. I changed them toname0
,email0
, andphone0
;The HTML has an unbalanced
</div>
, the opening<div>
I added fixes that too;After the clone is created, and before the IDs are updated, it includes elements with non-unique IDs. It isn't actually in the DOM yet, and you are using
clone.find()
to scope your search to find them, so probably that's OK ...? But it seems unnecessarily risky, when we don't have to do it that way - why not play it safe, and search for theinput
s instead of the IDs;<div clas="row box" id="clone"></div>
- typo inclass
;There was no way to trigger
addRow()
so I added a simplebutton
, and a click handler for it;
Here's a working, simplified snippet with those issues fixed:
$(document).ready(function () {
$('#select0').select2();
$('button').on('click', addRow);
});
// How many clones on the page?
let clones = 0;
function addRow() {
// We've added a clone
clones ;
// First need to destroy original select2, so the clone does not include
// extra stuff select2 generates.
$('#select0').select2('destroy');
// Now create our clone
let clone = $("#row_examenes .cloned").clone()
clone.find('input[name="username"]').attr("id", "name" clones);
clone.find('input[name="email"]').attr("id", "email" clones);
clone.find('input[name="phone"]').attr("id", "phone" clones);
clone.find("select").attr("id", "select" clones);
// HTML is updated, add it to the DOM
clone.appendTo($("#clone"));
// Reinitialise the original select2
$('#select0').select2();
// And initialise our new select2
$('#select' clones).select2();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/select2.min.js"></script>
<button>Create a clone</button>
<div id="row_examenes">
<div >
<div >
<div >
<input id="name0" name="username" placeholder="Enter Full Name" type="text" />
</div>
</div>
<div >
<div >
<input id="email0" name="email" placeholder="Enter VALID EMAIL and check the result" type="email" />
</div>
</div>
<div >
<div >
<input id="phone0" name="phone" placeholder="Enter Phone e.g.: 363012345" type="text" />
</div>
</div>
<div >
<div >
<select multiple="multiple" id="select0" >
<div clas="options">
<option value="1">Google</option>
<option value="1">Amazon</option>
<option value="1">Facebook</option>
<option value="1">Airbnb</option>
</div>
</select>
</div>
</div>
</div>
</div>
<div id="clone"></div>