【问题标题】:Select2 with ajax gets initialized several times with Rails turbolinks events使用 ajax 的 Select2 被 Rails turbolinks 事件初始化了几次
【发布时间】:2016-07-29 14:33:15
【问题描述】:

我正在使用 Rails 4.2.6 开发 Ruby On Rails 应用程序。我将 Turbolinks 与 jquery.turbolinks 一起使用(抱歉,由于我是该网站的新手,所以我无法发布这些元素的链接)。我的问题很简单,但我无法解决。这里是: 我有一个通过 AJAX 获取的表单

<div class="card-footer">
  <a class="btn btn-sm btn-primary-outline" data-remote="true"  href="/profiles/Mke5kA/positions/new"><i class="fa fa-plus"></i> Nouvelle expérience professionnelle</a>
  <div id="new_position_form"></div>
</div>

表单包含通过 AJAX 获取数据的 Select2 元素

= simple_form_for [profile, position], remote: true, html: {id: 'positionForm', class: 'm-b-1'} do |f|
  = f.input :company_id, as: :select, input_html: {:'data-behaviour' => 'company-select2', :'data-kind' => 'company'}
  = f.input :title
  = f.input :summary
  - location = f.object.build_location
  = f.simple_fields_for :location do |l|
    = render 'locations/fields', l: l, city: position.city
  = render "profiles/shared/date_fields", f: f, model: position
  = f.input :skill_list, as: :select, input_html: {multiple: true, :data => {:behaviour => 'acts-as-taggable', :'taggable-context' => 'skills'}}
  %button.btn.btn-primary{:type => "submit"}= icon('check-square-o', 'Enregistrer')
  = link_to icon('remove', 'Annuler'), 'javascript:void(0)', 
        data: {:'lgnk-behaviour' => "remove-form", :'lgnk-target' => "#positionForm" }, class: 'btn btn-secondary'
  • Select2 元素目前在 Rails Trubolinks 事件“page:load page:update”时“激活”,但我也尝试过“page:change”
  • 获取表单时:select2 元素正常(正确激活):

当我尝试输入使用 AJAX 获取数据的 Select2 时出现我的问题:所有 select2 都重复:

这是我如何初始化 Select2:

var loc_tag = function() {
  $('[data-behaviour="acts-as-taggable"]').not('.select2-hidden-accessible').each (function (index, element) {
    if ($(element).data('value')) {
      var options = $(element).data('value').split(', ');
      $.each(options, function(key, tag){
        $(element).append($('<option selected></option>').val(tag).text(tag));
      });
    }

    $(element).select2({
      ajax: {
        url: "/tags?context="+$(element).data('taggable-context'),
        dataType: 'json',
        headers: {
         "Accept": "application/json"
        },
       delay: 250,
       data: function (params) {
         return {
           q: params.term, // search term
           page: params.page
         };
       },
       processResults: function (data, page) {
         return {
           results: data
         };
      },
      cache: true
    },
    escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
    minimumInputLength: 2,
    tags: true,
    language: "fr",
    theme: "bootstrap",
    width: "100%",
    placeholder: 'Mots clés...'
    });
  });

};
$(document).on('page:load page:update', loc_tag);

我希望 Select2 元素只初始化一次(在获取表单时),而不是在 AJAX 响应它们获取数据时。我已经在取消 Select2 的元素上尝试了 jQuery.not(".select2-hiden-accessible") (select2-hidden-accessible 是 Select2 添加到初始化的 Select2 元素的类),但它不起作用。

非常感谢您的帮助!

【问题讨论】:

    标签: javascript ruby-on-rails jquery-select2


    【解决方案1】:

    使用 Turbolinks 5 和 select2 时,使用返回按钮返回页面时,select2 对象不再附加(请参阅下面的测试)到 &lt;select&gt;。返回后创建并附加了一个新的select2 对象,但它无法使用。

    jack 的回答对我不起作用,因为当添加新的 select2 对象时,&lt;select&gt; 仍然具有 class='select2-hidden-accessible',其中设置了 width: 1px !important。当创建新的select2 对象时,它基本上是不可见的。

    对我来说关键是在 TL 缓存页面之前销毁所有 select2 对象。这是对我有用的解决方案:

    $(document).on("turbolinks:before-cache", function() {
      $('.select2-input').select2('destroy');
    });
    
    $(document).on('turbolinks:load', function() {
      $('.select2-input').select2();
    });
    

    更多详情

    鉴于Turbolinks documentation(强调我的),我相信这是正确的方法:

    准备要缓存的页面

    如果需要准备,请监听 turbolinks:before-cache 事件 Turbolinks 缓存它之前的文档。您可以使用此事件 重置表单,折叠展开的 UI 元素,或拆除任何 第三方小部件,以便页面准备好再次显示。

    测试select2 存在

    要测试select2 对象是否附加到&lt;select&gt;,您可以在控制台中执行以下操作:

    ('.select2-input').first().data('select2')
    

    【讨论】:

    • 为我工作!谢谢。它比杰克的更优雅
    • 您可以使用以下命令销毁所有 select2 选择:document.addEventListener('turbolinks:before-cache', function() { $('.select2-hidden-accessible').select2('destroy'); });
    • @Pioz 解决方案避免了额外的检查步骤,效果很好。
    • @Pioz 您的解决方案有效,但需要添加 if($('.select2-input').first().data('select2')) 条件以检查仅当 select2 附加到该输入时才销毁
    【解决方案2】:

    我有同样的问题,我发现当你按下后退按钮时,selectselect2 元素都被渲染,但它们没有绑定在一起,所以当你用 $('select).select2() 重新初始化它时,它会创建旁边是另一个全新的select2 元素。

    这是我在初始化 select2 之前所做的:

    如果select 不是select2(即$(el).data('select2') == undefined)但旁边已经有select2 元素,则将其删除。

    if ($(el).data('select2') == undefined && $(el).next().hasClass('select2-container')) {
      $(el).next().remove();
    }
    $(el).select2();
    

    【讨论】:

    【解决方案3】:

    2021 年更新

    使用turbolinks:before-cache

    document.addEventListener('turbolinks:before-cache', function () {
      // removing the select2 from all selects
      $("select").select2('destroy');
    });
    

    并在turbolinks:load时加载select2:

    document.addEventListener("turbolinks:load", function () {
      // applying select2 to all selects
      $("select").select2({
        theme: 'bootstrap4' // if you want to pass some custom config
      });
    });
    

    当然,您可以创建自定义.select2-binder 类或data-select2-binder 来选择将影响哪个选择。


    我遇到了同样的问题,我通过这样做解决了:

    // init.js (you can pass an container instead of using document
    
    $( document ).on('turbolinks:load', function() {
      $( document ).find('select').not('.select2-hidden-accessible').select2();
    });
    

    现在我没有那些重复的选择:)

    【讨论】:

    • 这确实不会导致重复选择,但是当使用“后退”按钮返回带有 select2 框的页面时,无法再选择选择框。 @jack's 不太优雅,但这里的解决方案更合适。
    【解决方案4】:

    这里没有什么对我有用。

    通过不使用选择缓存页面,我能够完全解决这个问题。

    我在页面顶部使用这个选择:&lt;% provide(:no_cache, true) %&gt;

    我在application.html.erb上使用这个:

    <% if yield(:no_cache) %>
      <meta name="turbolinks-cache-control" content="no-cache">
    <% end %>
    

    【讨论】:

      【解决方案5】:

      它对我有用。即使单击后退、前进或单击其他链接并返回到初始化 select2 的页面,也没有重复。

      document.addEventListener("turbolinks:load", function() {
        $('.select2-container').remove() // this will remove all the select2 containers
        $('.select2-input').select2(); // and this will reinit the select2 again
      })
      

      更新

      我看到了一些很好的建议here 你可以选择其中之一。我选择移动标签中的所有 javascript 而不是将它们放在 body 标签中。

      【讨论】:

        猜你喜欢
        • 2014-06-25
        • 2015-03-06
        • 1970-01-01
        • 1970-01-01
        • 2012-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多