Home > Enterprise >  Error duplicating Div with Select2 library
Error duplicating Div with Select2 library

Time:11-14

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 class cloned;

  • 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 to name0, email0, and phone0;

  • 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 the inputs instead of the IDs;

  • <div clas="row box" id="clone"></div> - typo in class;

  • There was no way to trigger addRow() so I added a simple button, 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>

  • Related