克隆的Select2无响应。

52
我试图克隆一个包含Select2工具的行,但使用jQuery克隆该行时,克隆的Select2无法响应。在下面的图片中,第一个Select2正常工作,但克隆的第二个和第三个Select2无法响应。

代码片段:

$(document).ready(function() {
  var clonedRow = $('.parentRow').clone().html();
  var appendRow = '<tr class = "parentRow">' + clonedRow + '</tr>';
  $('#addRow').click(function() {
    $('#test').after(appendRow);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<tr class="parentRow" id="test">
  <td>
    <g:message code="educationDetails.educationLevel.label" default="Education Level" />
  </td>
  <td>
    <div style="float: left;">
      <g:select name="degree.id" from="${EducationalDegree.list()}" optionKey="id" optionValue="title" noSelection="['': '']" id="degree" value="${cvEducationDetailCO?.degree?.id}" onchange="changeGradeSelectData(this.value)" />
    </div>
    <div>
      <a href="javascript:void(0)" id="addRow">
        <img alt="" title="Add Additional Education Level" src="/static/images
                                                                /top_submit_1.gif">
      </a>
    </div>
  </td>
</tr>


我认为你需要再次在克隆的元素上重新初始化select2。或者尝试在clone中使用true选项运行,像这样:clone(true) - krishwader
谢谢您的回复,能否请您详细说明一下?我尝试重新初始化,但仍然没有成功。 - ABC
我尝试过了,但是不起作用,可能是我的流程不正确,所以您能稍微解释一下吗? - ABC
你能为你的问题创建一个fiddle吗?这将非常有帮助! - krishwader
14个回答

75
在克隆行之前,您需要调用其destroy方法禁用选择元素上的Select2:

destroy

撤消Select2对DOM所做的更改。通过Select2进行的任何选择都将被保留。

请参见http://ivaynberg.github.io/select2/index.html

在克隆行并将其插入DOM后,您需要在两个选择元素(原始选择和新克隆的选择)上启用select2。

这是一个JSFiddle,展示了如何完成此操作:http://jsfiddle.net/ZzgTG/

Fiddle的代码

HTML

<div id="contents">
    <select id="sel" data-placeholder="-Select education level-">
        <option></option>
        <option value="a">High School</option>
        <option value="b">Bachelor</option>
        <option value="c">Master's</option>
        <option value="c">Doctorate</option>
    </select>
</div>
<br>
<button id="add">add a dropdown</button>

CSS(层叠样式表)
#contents div.select2-container {
    margin: 10px;
    display: block;
    max-width: 60%;
}

jQuery
$(document).ready(function () {
    $("#contents").children("select").select2();
    $("#add").click(function () {
        $("#contents")
            .children("select")
            // call destroy to revert the changes made by Select2
            .select2("destroy")
            .end()
            .append(
                // clone the row and insert it in the DOM
                $("#contents")
                .children("select")
                .first()
                .clone()
        );
        // enable Select2 on the select elements
        $("#contents").children("select").select2();
    });
});

关于这个小问题:如果我选择“硕士”选项,它会自动变成“博士”选项。你能看一下吗?! - Michel Ayres
1
感谢详细的解释!注意:由于select2移动到一个适当的github组织,因此原样的小提琴已经损坏。 您可以通过更新到“https://select2.github.io/select2/select2-3.3.2/select2.js”和“https://select2.github.io/select2/select2-3.3.2/select2.css”来修复。 还要注意“https”,这可以防止破损(firefox在像jsfiddle这样的https页面上阻止不安全的混合内容)。 修复后的小提琴:https://jsfiddle.net/nxabgfsv/ - Jules Kerssemakers
4
请注意,此示例使用的是 select2 3.x 版本; 在当前的 4.x 系列中,重复的 ID (#sel) 不再有效(这也是无效的 HTML),您需要设置 id="" 或更新克隆的 ID 以使其唯一。 - Jules Kerssemakers

11

在克隆之前,您必须先销毁 select2,但是 `.select2('destroy')` 无法正常工作。 请使用以下代码:

$myClone = $("section.origen").clone();

$myClone.find("span").remove();
$myClone.find("select").select2();

$("div").append($myClone);

非常令人沮丧,但是克隆一个启用了select2<select>,然后跟着使用cloned.select2("destroy");会抛出错误"The select2('destroy') method was called on an element that is not using Select2."...你的解决方案是我在此情况下唯一有效的方法。 - Tim Lewis

9

我也遇到了同样的问题,尝试动态地向表格中添加一行时。(该行包含多个select2实例。)

我通过以下方式解决了这个问题:

function addrow()
{
    var row = $("#table1 tr:last");

    row.find(".select2").each(function(index)
    {
        $(this).select2('destroy');
    }); 

    var newrow = row.clone();       

    $("#table1").append(newrow);

    $("select.select2").select2();
}

诀窍在于,在克隆行之前,您需要单独销毁所有.select2实例。然后在克隆后,重新初始化.select2。 希望这对其他人也有用。


谢谢,这在我的使用情况下有效。还有一点需要补充的是,我们需要重新初始化每个 select 实例。 - mangatinanda

7

我实际上创建了一个账户来回答这个问题,因为我花了一些时间让它工作起来。

在克隆之前使用以下代码不起作用:

$('.selectpicker').select2('destroy')

但是这个在我的情况下可以解决问题:

$('.selectpicker').select2('destroy');
$('.selectpicker')
    .removeAttr('data-live-search')
    .removeAttr('data-select2-id')
    .removeAttr('aria-hidden')
    .removeAttr('tabindex');

只需删除select2添加的所有其他属性。

编辑#1

好吧,看起来您还需要从被克隆的元素中删除ID,因为当在选择器上找不到自己的唯一ID时,select2会尝试添加自己的唯一ID,但是当您确实有选择器时,情况变得混乱,selet2仅附加在具有相同ID的最后一个元素上。


3
我曾经遇到过同样的问题,解决方法也几乎相同,还需要清除选项项目的ID: $(ddls[i]).removeAttr('data-select2-id'); $(ddls[i]).find('option').removeAttr('data-select2-id'); - jeanadam
@jacvalle - 你救了我的一天!如果你有 optgroups,也请从那里删除 ids ;) - qdev

3
我用以下方式解决了这个问题:
在添加新行之前调用destroy方法。
 $(".className").select2("destroy");  //Destroy method , connect with class no ID (recomend)

在调用select2 jQuery函数后:

$(".className").select2({               
                placeholder: "Example",
                allowClear:true 
            });

希望这可以帮到你;)


这不再是真的了 https://select2.org/programmatic-control/methods#destroying-the-select2-control - Muhammad Omer Aslam

3

在克隆之前,您必须先销毁所有的select2组件。例如:

    var div = $("#filterForm div"); 

    //find all select2 and destroy them   
   div.find(".select2").each(function(index)
    {
        if ($(this).data('select2')) {
            $(this).select2('destroy');
          } 
    });

    //Now clone you select2 div 
    $('.filterDiv:last').clone( true).insertAfter(".filterDiv:last"); 

    //we must have to re-initialize  select2 
    $('.select2').select2(); 

这将从克隆的选择元素中删除选项。 - Nilaksha Perera

2

我通过创建不同的克隆函数来解决这个问题:

jQuery.fn.cloneSelect2 = function (withDataAndEvents, deepWithDataAndEvents) {
  var $oldSelects2 = this.is('select') ? this : this.find('select');
  $oldSelects2.select2('destroy');
  var $clonedEl = this.clone(withDataAndEvents, deepWithDataAndEvents);
  $oldSelects2.select2();
  $clonedEl.is('select') ? $clonedEl.select2() :
                            $clonedEl.find('select').select2();
  return $clonedEl;
};

1
//Paste this code after your codes.
$('span.select2').remove();
$('select.select2').removeAttr('data-select2-id');
$('select.select2').select2();

4
欢迎来到SO。在回答中添加一些解释而不仅仅是一段代码是很常见的。您可以解释您的代码是做什么的以及为什么它能解决问题。 - KillerX
此代码在复制后移除现有的select2。 - Mohamed Raza

1

以下是我用于克隆由select2管理的选择输入的方法:
1. 销毁要克隆的选择器
2. 使用true参数进行克隆
3. 从克隆中删除'id'和'data-select2-id'属性
4. 从克隆中的每个选项中删除'data-select2-id'属性
5. 重新初始化已被克隆的元素
6. 初始化克隆元素并重置值

以下是一个示例:

const origin = $('select').last(); // last in case there are more than one select
origin.select2('destroy');
const cloned = origin.clone(true);
cloned.removeAttr('data-select2-id').removeAttr('id');
cloned.find('option').removeAttr('data-select2-id');
origin.select2();
cloned.select2().val(null).trigger('change');

0

很多答案都是解决方案的混合体,对我来说问题在于元素ID不唯一。

当您克隆具有ID的元素时,请确保将其设置为唯一值,以使select2实例独立,否则初始化克隆将销毁先前的实例。

element.attr('id', element.attr('id')+Math.random());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接