Select2 with ajax gets initialized several times with Rails turbolinks events

牧云@^-^@ 提交于 2019-12-08 23:19:52

问题


I am a developing a Ruby On Rails app using Rails 4.2.6. I am using Turbolinks alongside jquery.turbolinks (sorry I could'nt post the links to those elements as I am a newbie on the site). My problem is very simple but I just can't solve it. Here it is: I have a form fetched through 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>

The form contains Select2 elements that get their data through AJAX

= 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'
  • The Select2 elements are "activated" currently upon Rails Trubolinks events "page:load page:update", but I have also tried "page:change"
  • When the form is fetched: the select2 elements are fine (activated correctly):

My problem appears when I try typing in the Select2 that are using AJAX to get the data: all the select2s are duplicated:

Here is how I get the Select2 initialized:

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);

I want the Select2 elements to get initialized only once (when the form is fetched) and not upon AJAX responses on them getting their data. I have tried jQuery.not(".select2-hiden-accessible") on the elements unsing Select2 (select2-hidden-accessible being the class Select2 adds to an initialized Select2 element) but it does not work.

Many thanks for your kind help!


回答1:


When using Turbolinks 5 and select2, the select2 object is no longer attached (see below for test) to the <select> when using the back button to return to a page. A new select2 object is created and attached after going back but it was unusable.

jack's answer didn't work for me because when the new select2 object is added, the <select> still has class='select2-hidden-accessible' which, among other things, sets width: 1px !important. When the new select2 object is created it's basically invisible.

The key for me was to destroy all select2 objects before TL caches the page. Here is the solution that worked for me:

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

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

More Detail

I believe this is the correct approach given the Turbolinks documentation (emphasis mine):

Preparing the Page to be Cached

Listen for the turbolinks:before-cache event if you need to prepare the document before Turbolinks caches it. You can use this event to reset forms, collapse expanded UI elements, or tear down any third-party widgets so the page is ready to be displayed again.

Testing select2 Existance

To test if the select2 object is attached to the <select> you can execute the following in the console:

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



回答2:


I have the same problem and I found that when you press the back button both the select and the select2 elements are rendered but they are not bound together so when you re-initialize it with $('select).select2() it creates another brand new select2 element next to it.

So here's what I did before initializing the select2:

If the select is not a select2 (i.e. $(el).data('select2') == undefined) but there is already a select2 element next to it, then remove it.

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



回答3:


I had the same issue and I solved by doing:

// init.js (you can pass an container instead of using document

$( document ).on('turbolinks:load', function() {
  $( document ).find('select').not('.select2-hidden-accessible').select2();
});

And now I don't have those duplicated selects :)




回答4:


Nothing here worked for me.

I was able to get around this altogether by not caching the page with the select.

I use this on the top of the page with select: <% provide(:no_cache, true) %>

I use this on application.html.erb:

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


来源:https://stackoverflow.com/questions/36497723/select2-with-ajax-gets-initialized-several-times-with-rails-turbolinks-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!