Search code examples
jqueryjquery-selectorsjquery-select2jquery-select2-4

Clone select2 element in current version (4.0.13)


The essence of what I’m trying to do is already asked & answered here in this SO question. That question includes a fiddle and code that works in an prior release of select2 (v3.3.2), but does not work when using the current release (4.0.13). I've created two annotated fiddles using the code from that question that also shows the problem and error that I'm getting in my project's fiddle.

Fiddles from SO question #17175534
v3.3.2 (working): https://jsfiddle.net/24chd7t9/
v4.0.13 (broken): https://jsfiddle.net/ka19ez4L/

Basically, I'm trying to achieve a very similar result to the above question, but using the latest stable select2 release (4.0.13). Switching to the prior release creates some other issues for my project, so I'm hoping to get this working in the current version.

Description:
I have a table, and each row contains a column with a select2 dropdown. Initially the table has just one such row, but there is a button allowing users to add rows.

Snip of table with multiple rows - working

When the “Add” customer button is clicked, the following block of code runs. After it creates the new row, it clones the select2 element and appends it to the second column of the new row.

$("#add-cust").click(function () {
        let table = document.getElementById("job-customers");
        let last_customer = parseInt(table.tBodies[0].rows.length, 10);
        let new_customer = last_customer+1;
        var row = table.insertRow(-1);
        row.setAttribute('id', 'row-customer-'+new_customer);
        row.setAttribute('class', 'customer');
        let cell1 = row.insertCell(-1);
        let cell2 = row.insertCell(1); 
        cell1.innerText = new_customer;

        //LOOP ROWS IN TBODY COL2 & DESTROY SELECT2 ELEMENTS
        $("#job-customers").find("tbody td:nth-child(2)").each(function () {
            $(this).children("select")
            .select2("destroy")
            .end();
        });
        //CLONE & APPEND
        $("#row-customer-" + last_customer + " td:nth-child(2)")
           .children("select").clone()
           .appendTo(cell2);
        $('.select2').select2();
    });

Fiddles: (same exact code in both)
JSFiddle using select2 v3.3.2: https://jsfiddle.net/07Lgxdyt/ (Working)
JSFiddle using select2 v4.0.13: https://jsfiddle.net/97mrx1jL/ (Broken)

After clicking Add in the 4.0.13 fiddle, a new row is inserted and the select2 element is cloned, but the previous row's element is no longer functional. Clicking Add again breaks all select2 functionality and result in the following error:

The select2('destroy') method was called on an element that is not using Select2.

I suspect this has to do with how the current release creates the select2 element in the DOM, but am not certain. The code $('.select2').select2(); doesn't appear to be re-initializing the previously destroyed select2 elements in the 4.0.13 version. I've tried using different selectors to re-initialize select2() on the prior row dropdowns, even writing specific ones for each dropdown/row, but the error message is always the same. I didn't see anything in the release notes for select2 v4 that seemed applicable either.

Any help in troubleshooting or getting past this error would be greatly appreciated.


Solution

  • After doing some iterative testing, I was able to solve this issue.

    In case anyone else runs into this, the issue is that in the current version multiple select2 elements cannot use the same id, though this doesn't appear to be the case in prior versions of select2.

    To solve the problem I just assign a new ID each time a select2 element is cloned. See below the code that clones and assigns the id, where newidval is an incremented element ID

    $("#row-customer-" + last_customer + " td:nth-child(2)")
    .children("select").clone()
    .attr('id', newidval)
    .appendTo(cell2);
    

    Here is the final working JSFiddle: https://jsfiddle.net/nm3ey6w7/