Rails - 在选项卡之间同步按钮单击

Man*_*nos 6 javascript ruby forms jquery ruby-on-rails

我有一个带bootstrap-tabs的视图.选项卡是动态生成的.

<%= form_with(:id => 'my-form', model: [:admin, @island], local: true) do |form| %>
  <div class="tab-content bg-light" id="tabs-from-locales-content">

    <%= available_locales.each_with_index do |locale, i| %>
      <div
      class="tab-pane fade <%= 'show active' if i == 0 %>"
      id="<%= locale.downcase %>"
      role="tabpanel"
      aria-labelledby="<%= locale.downcase %>-tab">
        <%= render partial: 'island_form', locals: {counter: i, locale: locale, f: form} %>
      </div>
    <% end %>

  </div>

...
...
Run Code Online (Sandbox Code Playgroud)

选项卡表示应用程序的每个可用本地化.表单的模型包含两个嵌套属性.这些属性1 to many与模型有关系.因此,用户可以从表单中添加多个这些.他们的字段可以动态生成:

(为简单起见,我只在问题中包含一个.这是部分的_island_form.html.erb一部分.)

<div class="form-group ports-div">
  <%= f.label :port %> </br>
  <%= f.fields_for :ports do |builder| %>

    <%= render 'port_fields', f: builder %>

  <% end %>
  <%= link_to_add_fields t('form.add_port'), f, :ports %>
</div>

<div class="form-group">
  <%= f.label :airport %> </br>
  <%= f.fields_for :airports do |builder| %>

    <%= render 'airport_fields', f: builder %>

  <% end %>
  <%= link_to_add_fields t('form.add_airport'), f, :airports %>
</div>
Run Code Online (Sandbox Code Playgroud)

port_fields部分:

<fieldset>
  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>
  <%= f.hidden_field :_destroy %>
  <%= link_to t('form.remove'), '#', class: 'remove_fields' %>
</fieldset>
Run Code Online (Sandbox Code Playgroud)

link_to_add_fieldshelper方法:

  def link_to_add_fields(name, f, association)
    # Builds an instance of the association record.
    new_object = f.object.send(association).klass.new
    # Grabbing ruby's object id.
    id = new_object.object_id
    fields = f.fields_for(association, new_object, child_index: id) do |builder|
      render(association.to_s.singularize + '_fields', f: builder)
    end
    link_to(name, '#', class: 'add_fields', data: { id: id, fields: fields.gsub('\n', '') })
  end
Run Code Online (Sandbox Code Playgroud)

我想要实现的是在可用选项卡之间同步这些字段的添加和删除.因此,当用户单击Add field第一个选项卡时,所有其他选项卡将遵循此操作.字段删除相同.

我按钮的相关js文件Add如下所示.我曾尝试之间有许多组合trigger,triggerHandler而且stopPropagation,虽然大多数我得到时代StackOverflow exception和字段添加只对我点击标签add按钮.

(因为我传递的是一个类(.add_fields)selector不应该附加到所有带有类的元素.add_fields?)

form.on('click', '.add_fields', function (event, param) {
    event.stopPropagation();
    event.preventDefault();

    var time = new Date().getTime();
    var regexp = new RegExp($(this).data('id'), 'g');
    $(this).before($(this).data('fields').replace(regexp, time));

    $('.tab-pane').each(function (index) {

        $('.add_fields').trigger("click", ["custom_click"]);
        console.log('Tab - ' + index);
    })
});
Run Code Online (Sandbox Code Playgroud)

编辑

我正在使用该代码:

    $('.ports-div').each(function (index) {

        $(this).find('.add_fields').each(function () {
            this.click();
        })
    });
Run Code Online (Sandbox Code Playgroud)

虽然,在所有选项卡中,但是添加了1个字段6字段.我添加了ports-div包含所有相关元素的div.

Phi*_*hil 1

完全重写...

正如您所看到的,问题是您的单击事件处理程序正在触发所有选项卡窗格的单击,包括您当前正在处理的选项卡窗格。您也不只是单击循环中的单个项目,而是单击所有与“.add_fields”匹配的项目。然后,这会导致再次递归地处理点击。

为了防止这种情况,我建议调用一个函数来直接添加字段,而不是触发单击。如果在您的情况下触发点击是最简单的,请考虑以下示例,它大致可以完成您想要的操作,而不会出现递归错误。

https://jsfiddle.net/3ftf0j8e/1/

虚拟 HTML

<a class="add_fields" id='1'>link 1</a>    
<a class="add_fields" id='2'>link 2</a>    
<a class="add_fields" id='3'>link 3</a>    
<a class="add_fields" id='4'>link 4</a>
Run Code Online (Sandbox Code Playgroud)

JavaScript 示例

$(document).on('click', '.add_fields', function (event, param) {
    event.preventDefault();


    var clicked_id = $(this).attr('id');
    console.log('clicked id:' + clicked_id);

    $(this).addClass('done');
    $(this).addClass('clicked');
    // Just click items that have not been clicked
    var els = $('.add_fields').not('.clicked');
    console.log(els);    
    els.trigger("click");

    setTimeout(function(){
      if($('.add_fields').length == $('.add_fields.done').length)
        $('.add_fields').removeClass('clicked');
    })

});
Run Code Online (Sandbox Code Playgroud)

CSS

a.clicked {
  background-color: yellow;
}

a.done {
  color: red;
}
Run Code Online (Sandbox Code Playgroud)

正如您现在所看到的,每个都只触发一次。最后的 setTimeout 允许在清除单击的类之前更新 DOM。