使用 ajax 的 Select2 被 Rails turbolinks 事件初始化了几次
Posted
技术标签:
【中文标题】使用 ajax 的 Select2 被 Rails turbolinks 事件初始化了几次【英文标题】:Select2 with ajax gets initialized several times with Rails turbolinks events 【发布时间】: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 元素的类),但它不起作用。
非常感谢您的帮助!
【问题讨论】:
【参考方案1】:使用 Turbolinks 5 和 select2 时,使用返回按钮返回页面时,select2
对象不再附加(请参阅下面的测试)到 <select>
。返回后创建并附加了一个新的select2
对象,但它无法使用。
jack 的回答对我不起作用,因为当添加新的 select2
对象时,<select>
仍然具有 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
对象是否附加到<select>
,您可以在控制台中执行以下操作:
('.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】:
我有同样的问题,我发现当你按下后退按钮时,select
和 select2
元素都被渲染,但它们没有绑定在一起,所以当你用 $('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();
【讨论】:
我觉得真的应该是addressed upstream。【参考方案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】:这里没有什么对我有用。
通过不使用选择缓存页面,我能够完全解决这个问题。
我在页面顶部使用这个选择:<% provide(:no_cache, true) %>
我在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 标签中。
【讨论】:
以上是关于使用 ajax 的 Select2 被 Rails turbolinks 事件初始化了几次的主要内容,如果未能解决你的问题,请参考以下文章
示例 - Ruby on Rails 6/7 的 Select2 多个 AJAX 代码(没有 Gem)
带有 select2 的 Rails 5 ask_as_taggable