【问题标题】:Initialising select2 created dynamically初始化动态创建的 select2
【发布时间】:2015-07-10 10:20:43
【问题描述】:

我有一个 select2 下拉菜单,为此我提供了一个匹配器功能。它在初始页面加载时初始化如下:

jQuery(document).ready(function() {
    jQuery(".my_select2").select2({
        matcher: function(term, text) {...}
    });
});

这可以在初始页面加载时找到。

现在,我有额外的下拉菜单(select 动态创建的元素(通过 AJAX 引入,即 jQuery(match).load(url)。这些额外的下拉菜单不会被初始化为 select2 小部件,这是可以理解的,即使它们匹配原来的 select2 选择器。

那么,我如何告诉 jQuery 将这些动态创建的 select 元素视为需要初始化的 select2 项?我可以在匹配元素上设置某种“监视”,以便每次将匹配元素添加到页面时都会启动 select2 初始化?

我记得live() 前段时间在 jQuery 中被引入,如果我理解正确的话,它支持在创建之前匹配元素。我从未使用过该功能,现在它似乎已被弃用。但这确实是我正在寻找的那种东西。

这是一个WordPress插件,目前使用jQuery v1.11.2。

【问题讨论】:

  • 这意味着 jQuery 在没有帮助器的情况下无法监视正在创建的项目。或者arrive.js 是为了在根本不使用 jQuery 时让事情变得更容易而创建的?
  • 如果在将选择项添加到 DOM 后无法触发 select2,则必须像第一条评论一样使用 dom 变异观察器
  • 谢谢,我现在采用这种方法 - 在将新的选择列表添加到 DOM 时显式触发 select2。这意味着列表有两个初始化位置,但我已将所有初始化代码移至函数以将重复降至最低。我认为我的第一个想法是新元素的初始化可以自动化,有点乐观。它可以完成,如 juna-c 的回答所示,但它确实依赖于一些更现代的浏览器中的功能,在这个应用程序中假设/强制最终用户是不合理的(商店 - 所有客户都很重要)。

标签: jquery jquery-select2


【解决方案1】:

您可以尝试使用 DOMNodeInserted 并查找 select 或您分配给他们的类

Demo

$('body').on('DOMNodeInserted', 'select', function () {
    $(this).select2();
});

更新

DOMNodeInserted

已弃用 此功能已从 Web 标准中删除。尽管某些浏览器可能仍然支持它,但它正在被删除。尽可能避免使用它并更新现有代码;

建议的方法类似于MutationObserver

$(function() {
  $("button").on("click", function() {
    $("#dynamic-container").append($("<select><option>test</option><select/>"));
  });

  // select the target node
  var target = document.getElementById('dynamic-container');

  if (target) {
    // create an observer instance
    var observer = new MutationObserver(function(mutations) {
      //loop through the detected mutations(added controls)
      mutations.forEach(function(mutation) {
      //addedNodes contains all detected new controls
        if (mutation && mutation.addedNodes) {
          mutation.addedNodes.forEach(function(elm) {
          //only apply select2 to select elements
            if (elm && elm.nodeName === "SELECT") {
              $(elm).select2();
            }
          });
        }
      });
    }); 
    
    // pass in the target node, as well as the observer options
    observer.observe(target, {
      childList: true
    });

    // later, you can stop observing
    //observer.disconnect();
  }
});
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><link href="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js"></script>


<button>Add new select</button>
  <div id="dynamic-container">

  </div>

【讨论】:

  • 谢谢,效果很好。我确实想尝试避免一些重复 - select2 下拉菜单在两个不同的地方初始化。我有一个匹配器,下拉菜单上有一个.on('change', ...) 触发器,所以这两个地方也需要初始化。我将看看如何在一个地方定义初始化。
  • 我会接受这个作为答案,因为它确实有效,所以解决了最初的问题,即使我已经改变了我的整个方法作为答案的结果。建议的github.com/uzairfarooq/arrive 包将其包装起来以使其更易于使用(即更抽象)。谢谢大家。
  • @Jason 只是为了说明问题。 arrive.js 不包装 DOMNodeInserted api。它在内部使用新的MutationObserver api。 DOMNodeInserted api 是deprecated,应该避免使用。
  • 不工作,我在谷歌浏览器中测试过。甚至演示都无法正常工作。
  • 在谷歌浏览器中为我工作
【解决方案2】:

我最近遇到了类似的情况,但以非常常见的方式进行:

$(document).ready(function() {

 //function to initialize select2
  function initializeSelect2(selectElementObj) {
    selectElementObj.select2({
      width: "80%",
      tags: true
    });
  }


 //onload: call the above function 
  $(".select-to-select2").each(function() {
    initializeSelect2($(this));
  });

 //dynamically added selects

  $(".add-new-select").on("click", function() {
    var newSelect = $("<select class='select-to-select2'  multiple><option>option 1</option><option>option 2</option></select>");
    $(".select-container").append(newSelect);
    initializeSelect2(newSelect);
  });


});
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/css/select2.css" rel="stylesheet" />

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/js/select2.min.js"></script>
<div class="select-container">
  <select class='select-to-select2' multiple>
    <option value='1'>option1</option>
    <option value='2'>option2</option>
  </select>

  <select class='select-to-select2' multiple>
    <option value='1'>option1</option>
    <option value='2'>option2</option>
  </select>

</div>
<div>
  <button class="add-new-select">Add New Select</button>
</div>

如果是 .load 函数,则在 load 函数的回调中找到所有要初始化的选择元素,并在每个选择元素上调用 initializeSelect2。

我希望这对正在寻找简单解决方案的人有所帮助。

【讨论】:

  • 感谢@Roshan 我已使用您的代码获取 select2。我被卡住了,问题是只有一个 selct2 正在工作,其他选择没有得到 select2 initializeSelect2
  • 您是否将 select-to-select2 类添加到 select 元素中?
  • @ankitsuthar 我正在使用 jQuery clone() 复制 select 元素,而 Select2 只在第一个元素上工作,就像你说的那样。我发现您不必在要克隆的元素上应用 Select2,而只需对克隆的元素应用 Select2。在已应用 Select2 的情况下克隆 select 会产生不可靠的结果。
  • 我在远程 select2.js 和 dropzone.js 中使用了这个,只需要准备好文档中的函数。谢谢我的朋友
【解决方案3】:

对我有用

<div id="somediv">
    <select class="component">
    ...
    </select>
</div>



<script>
    $(document).on('click', '#addComponent', function () {

        $('#somediv').append(data); //data is my new select
        $('.component:last').select2();
    });
</script>

【讨论】:

  • 这其实很简洁。我正在考虑使用“MutationObserver”,但您的解决方案很有效。
【解决方案4】:

我也遇到过同样的问题,但是在摸索了几天之后,我找到了一个解决方案,但是如果您期望获得良好的性能,那就不好了。

所以当第一次加载 DOM 时,无论加载什么选择项都将具有 select2 功能,对于动态生成的字段,select2 功能将不可用,因为 select2 脚本已经加载。

因此,要使 select2 工作,请在单击时动态重新加载脚本。

function reload(id) {
    $(id).on("click", function () {
        $("head").append($("<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/css/select2.css' type='text/css' media='screen' />"));
        $.getScript("https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js", function () {
            $.getScript("https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/js/select2.min.js", function () { 
                $('select').select2();
            })
        })
    })
}

这样做的目的是将 select2 功能添加到 $。

【讨论】:

    【解决方案5】:

    类似于上面的答案:

    function initSelect2(element){
      element.select2({   });
    }
    
    // Dynamic add 
    $('button[data-id="add-item"]').on('click', function(){
       // Add element
       obj.addItem();
       // Add Select2 to element
       initSelect2($('element'));
    });
    

    【讨论】:

      【解决方案6】:

      我解决了这个类似于 roshan 的解决方案,但没有在函数中传递选择对象。这是用于 ajax 调用的表输出。

      $(document).ready(function() {
      
              function initSelect2() {
                  $("[id^='DDAlertFreq']").select2({
                      minimumResultsForSearch: Infinity,
                      allowClear: false,
                      theme: "bootstrap"
                  });
              };
      
      //define the dropdown and set to variable    
      var DDAlertFrequency = '<select id="DDAlertFreq" ><option value="Fifteen_Minutes">15 Minutes</option><option value="Thirty_Minutes">30 Minutes</option><option value="Hour">Hour</option><option value="Two_Hours">2 Hours</option><option value="Three_Hours">3 Hours</option><option value="Four_Hours">4 Hours</option><option value="Six_Hours">6 Hours</option><option value="Eight_Hours">8 Hours</option><option value="Twelve_Hours">12 Hours</option><option value="Day">Day</option></select>'
      
      function RetrieveUserAlerts(uid) {
                      $.ajax({
                          url: 'SavedSearches.asmx/LoadUserAlerts',
                          dataType: 'json',
                          method: 'post',
                          data: { userid: uid },
                          success: function (data) {
                              var tbl = $("#tblAlerts > tbody");
                              tbl.empty();
                              $.each(data, function () {
                                  userAlert.alert_idx = this['alert_idx'];
                                  userAlert.Name = this['Name'];
                                  userAlert.price_alert_low = this['price_alert_low'];
                                  userAlert.alert_frequency = this['alert_frequency'];
                                  userAlert.alert_max_per_day = this['alert_max_per_day'];
                                  userAlert.alert_to_email = this['alert_to_email'];
                                  userAlert.alert_to_sms = this['alert_to_sms'];
                                  userAlert.active = this['active'];
                                  userAlert.alert_start_date = moment(this['alert_start_date']).format("MM/DD/YY");
                                  userAlert.alert_end_date = moment(this['alert_end_date']).format("MM/DD/YY");
                                  userAlert.OpenSectionID = this['OpenSectionID'];
      // modify the dropdown to assign unique id and match selection
                                  var selectAlert = DDAlertFrequency.replace("DDAlertFreq", "DDAlertFreq_" + userAlert.alert_idx).replace('"' + userAlert.alert_frequency + '"', '"' + userAlert.alert_frequency + '" selected');
                                  var tblRow = '<tr><td>'
                                      + userAlert.Name
                                   + '</td><td>'
                                  + '<input id="txtPriceAlertLow_' + userAlert.alert_idx + '" type="text" class="form-control" value="' + userAlert.price_alert_low + '"/>'
                                   + '</td><td>'
                                  + '<input id="chkAlertToEmail_' + userAlert.alert_idx + '" type="checkbox" ' + ((userAlert.alert_to_email == true) ? "checked" : "") + ' />'
                                   + '</td><td>'
                                  + '<input id="chkAlertToEmail_' + userAlert.alert_idx + '" type="checkbox" ' + ((userAlert.alert_to_sms == true) ? "checked" : "") + ' />'
                                   + '</td><td>'
                                  + selectAlert //modified Select2 dropdown
                                   + '</td><td>'
                                   + '<input id="txtMaxPerDay_' + userAlert.alert_idx + '" type="text" class="form-control" value="' + userAlert.alert_max_per_day + '"/>'
                                   + '</td><td>'
                                  + userAlert.alert_start_date
                                   + '</td><td>'
                                  + userAlert.alert_end_date
                                   + '</td><td>'
                                 + '<input id="chkActive_' + userAlert.alert_idx + '" type="checkbox" ' + ((userAlert.active == true) ? "checked" : "") + ' />'
                                   + '</td><tr>'
                                  tbl.append(tblRow);
                                  initSelect2(); //call the function to initialize all Select2 dropdowns created
                              });
                          },
                          error: function (err) {
                              console.log('Error (RetrieveUserAlerts): ' + JSON.stringify(err, null, 2));
                          }
                      });
                  };
      

      很抱歉留下无关紧要的东西 - 我评论了感兴趣的领域。 希望这对其他人有帮助!

      【讨论】:

        猜你喜欢
        • 2016-01-04
        • 1970-01-01
        • 1970-01-01
        • 2017-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多