【问题标题】:Cocoon gem, how to call the after-insert callback on rendered associationCocoon gem,如何调用渲染关联的插入后回调
【发布时间】:2017-11-02 05:59:31
【问题描述】:

我正在使用Cocoon gem 构建一个嵌套表单,其中一个 field_for 包含另一个 field_for。层次结构如下所示:

  • 信函形式
    • 卡 field_for
      • 按钮 field_for

每个卡片条目都是使用 link_to_add_association 链接添加的。我使用插入后回调来允许用户单击创建的卡片以显示包含按钮字段的弹出窗口(用于 UX 目的)。

我的插入后回调示例:

$('#carousel-stage-ul')
      .on('cocoon:after-insert', function(e, insertedItem) {

        insertedItem.find('#add-card-button, .new_button_card').click(function() {
          $('#black-background')[0].style.display = "block";
          insertedItem.find('.add-button-card-modal').css('display', 'block');
        });

        insertedItem.find('#delete_new_card_button').click(function() {
          $('#black-background')[0].style.display = "none";
          insertedItem.find('.add-button-card-modal').css("display", "none");

          $firstIn = insertedItem.find('.add-button-card-modal input[type=text]').eq(0);
          $secondIn = insertedItem.find('.add-button-card-modal input[type=text]').eq(1);

          $firstIn.val("");
          $secondIn.val("");

          $buttonForm = $.parseHTML('<div id="add-card-button" class="add-button">+ Add Button</div>')
          insertedItem.find('#new_card_button').replaceWith($buttonForm[0]);

          insertedItem.find('#add-card-button, .new_button_card').click(function() {
            $('#black-background')[0].style.display = "block";
            insertedItem.find('.add-button-card-modal').css('display', 'block');
          });
        });
            })
      .on('cocoon:after-remove', function(e, insertedItem) {
        ...

_card_fields.html.erb 部分渲染按钮:

<% f.object.buttons.build %>
  <%= f.fields_for :buttons do |button_card_fields| %>
      <%= render 'button_fields', f: button_card_fields %>
  <% end %>

_button_fields.html.erb 部分:

<div class="add-button-card-modal">
  <h4>Add New Button</h4>
  <label>Button Text</label>
  <%= f.text_field :button_text, :maxlength => 20, placeholder: "Enter the text to display on the button..." %>
  <br><br>
  <label>Button URL</label>
  <%= f.text_field :button_url, placeholder: "Paste URL..." %>
  <div class="nav-popups-buttons">
    <button type="button" id="validate_new_card_button" class="small-cta2">Add Button</button>
    <p class="remove-link" id="delete_new_card_button">Remove Button</p>
  </div>
</div>

这是为卡片轮播中的一张卡片呈现的 HTML,以便更好地理解我的 insert-after 回调:

<div class="connected-carousels" style="display: block;">
                  <div class="stage">
                      <div class="carousel carousel-stage" data-jcarousel="true">
                          <ul id="carousel-stage-ul" style="left: 0px; top: 0px;">


                          <li class="carousel-slide">
  <div id="card-messenger">
    <div class="DIV_1b">
      <div class="DIV_2b">
        <div class="DIV_3">
          <a class="A_4"></a>
          <div class="DIV_5" style="">
          </div>
        </div>
        <div class="DIV_6">
          <div class="DIV_7">
            <div class="DIV_8">
              <div class="DIV_9">
                <div class="DIV_10">
                </div>
                <div class="DIV_11">
                  <input maxlength="80" size="0" placeholder="Enter title..." type="text" name="letter[cards_attributes][1509602161650][title]" id="letter_cards_attributes_1509602161650_title">
                </div>
              </div>
              <div class="DIV_12">
                <div class="DIV_14">
                  <input maxlength="80" size="0" placeholder="Enter subtitle..." type="text" name="letter[cards_attributes][1509602161650][subtitle]" id="letter_cards_attributes_1509602161650_subtitle">
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div id="add-card-button" class="add-button" style="width: 308.203px;">+ Add Button</div>
      <div id="DIV_19" class="card-share-button" style="display:none;">
        <a id="A_20">Share</a>
      </div>
      <div id="DIV_19" class="input-card-share-button">
        <div id="add-share-card-button" class="add-button" style="padding: 0!important;">+ Add Share</div>
      </div>
      <input value="false" id="hidden-share-field" type="hidden" name="letter[cards_attributes][1509602161650][button_share]">
    </div>
  </div>

    <div class="add-button-card-modal">
      <h4>Add New Button</h4>
      <label>Button Text</label>
      <input maxlength="20" placeholder="Enter the text to display on the button..." size="20" type="text" name="letter[cards_attributes][1509602161650][buttons_attributes][0][button_text]" id="letter_cards_attributes_1509602161650_buttons_attributes_0_button_text">
      <br><br>
      <label>Button URL</label>
      <input placeholder="Paste URL..." type="text" name="letter[cards_attributes][1509602161650][buttons_attributes][0][button_url]" id="letter_cards_attributes_1509602161650_buttons_attributes_0_button_url">
      <div class="nav-popups-buttons">
        <button type="button" id="validate_new_card_button" class="small-cta2">Add Button</button>
        <p class="remove-link" id="delete_new_card_button">Remove Button</p>
      </div>
    </div>
  <div class="modal-image">
    <div id="display_image_upload">
      <label>Upload Image</label>
      <input id="image-input" class="inputBox_upload_image" type="file" name="letter[cards_attributes][1509602161650][image_url]"><div class="progress"><div class="bar"></div></div>
    </div>
    <label id="or">OR</label>
    <div id="display_image_url">
      <label>Paste Image Url</label>
      <input id="image-input" class="inputBox_image" type="text" name="letter[cards_attributes][1509602161650][remote_image_url]">
    </div>
    <div class="nav-popups-buttons">
      <button type="button" id="validate_image" class="small-cta2">Add Image</button>
      <p class="remove-link" id="delete_new_card_image">Remove Image</p>
    </div>
  </div>
  <div>
    <input type="hidden" name="letter[cards_attributes][1509602161650][_destroy]" id="letter_cards_attributes_1509602161650__destroy" value="false"><a class="remove-link remove_fields dynamic" data-wrapper-class="carousel-slide" href="#">Remove Card</a>
  </div>
</li></ul>
                        </div>
                        <a href="#" class="prev prev-stage inactive" data-jcarouselcontrol="true"><span>‹</span></a>
                        <a href="#" class="next next-stage inactive" data-jcarouselcontrol="true"><span>›</span></a>
                    </div>
              <div class="navigation">
                  <a href="#" class="prev prev-navigation inactive" data-jcarouselcontrol="true">‹</a>
                  <a href="#" class="next next-navigation inactive" data-jcarouselcontrol="true">›</a>
                  <div class="carousel carousel-navigation" data-jcarousel="true">
                    <ul id="carousel-navigation-ul" style="left: 0px; top: 0px;"><li data-jcarouselcontrol="true" class="active"><img alt="botletter" class="carousel-ico" src="/assets/icon-cards-0178dc5a1fb2811909dcd1d1fcef121baa165e46d49973dff5fdea12090631fa.png"></li></ul>
                  </div>
              </div>
              <div>
                <a id="add-card-button-bis" data-association-insertion-node="#carousel-stage-ul" data-association-insertion-method="append" class="add_fields" data-association="card" data-associations="cards" data-association-insertion-template="<li class=&quot;carousel-slide&quot;>
  <div id=&quot;card-messenger&quot;>
    <div class=&quot;DIV_1b&quot;>
      <div class=&quot;DIV_2b&quot;>
        <div class=&quot;DIV_3&quot;>
          <a class=&quot;A_4&quot;></a>
          <div class=&quot;DIV_5&quot; style=&quot;&quot;>
          </div>
        </div>
        <div class=&quot;DIV_6&quot;>
          <div class=&quot;DIV_7&quot;>
            <div class=&quot;DIV_8&quot;>
              <div class=&quot;DIV_9&quot;>
                <div class=&quot;DIV_10&quot;>
                </div>
                <div class=&quot;DIV_11&quot;>
                  <input maxlength=&quot;80&quot; size=&quot;0&quot; placeholder=&quot;Enter title...&quot; type=&quot;text&quot; name=&quot;letter[cards_attributes][new_cards][title]&quot; id=&quot;letter_cards_attributes_new_cards_title&quot; />
                </div>
              </div>
              <div class=&quot;DIV_12&quot;>
                <div class=&quot;DIV_14&quot;>
                  <input maxlength=&quot;80&quot; size=&quot;0&quot; placeholder=&quot;Enter subtitle...&quot; type=&quot;text&quot; name=&quot;letter[cards_attributes][new_cards][subtitle]&quot; id=&quot;letter_cards_attributes_new_cards_subtitle&quot; />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div id=&quot;add-card-button&quot; class=&quot;add-button&quot; style=&quot;width: 308.203px;&quot;>+ Add Button</div>
      <div id=&quot;DIV_19&quot; class=&quot;card-share-button&quot; style=&quot;display:none;&quot;>
        <a id=&quot;A_20&quot;>Share</a>
      </div>
      <div id=&quot;DIV_19&quot; class=&quot;input-card-share-button&quot;>
        <div id=&quot;add-share-card-button&quot; class=&quot;add-button&quot; style=&quot;padding: 0!important;&quot;>+ Add Share</div>
      </div>
      <input value=&quot;false&quot; id=&quot;hidden-share-field&quot; type=&quot;hidden&quot; name=&quot;letter[cards_attributes][new_cards][button_share]&quot; />
    </div>
  </div>

    <div class=&quot;add-button-card-modal&quot;>
      <h4>Add New Button</h4>
      <label>Button Text</label>
      <input maxlength=&quot;20&quot; placeholder=&quot;Enter the text to display on the button...&quot; size=&quot;20&quot; type=&quot;text&quot; name=&quot;letter[cards_attributes][new_cards][buttons_attributes][0][button_text]&quot; id=&quot;letter_cards_attributes_new_cards_buttons_attributes_0_button_text&quot; />
      <br><br>
      <label>Button URL</label>
      <input placeholder=&quot;Paste URL...&quot; type=&quot;text&quot; name=&quot;letter[cards_attributes][new_cards][buttons_attributes][0][button_url]&quot; id=&quot;letter_cards_attributes_new_cards_buttons_attributes_0_button_url&quot; />
      <div class=&quot;nav-popups-buttons&quot;>
        <button type=&quot;button&quot; id=&quot;validate_new_card_button&quot; class=&quot;small-cta2&quot;>Add Button</button>
        <p class=&quot;remove-link&quot; id=&quot;delete_new_card_button&quot;>Remove Button</p>
      </div>
    </div>
  <div class=&quot;modal-image&quot;>
    <div id=&quot;display_image_upload&quot;>
      <label>Upload Image</label>
      <input id=&quot;image-input&quot; class=&quot;inputBox_upload_image&quot; type=&quot;file&quot; name=&quot;letter[cards_attributes][new_cards][image_url]&quot; />
    </div>
    <label id=&quot;or&quot;>OR</label>
    <div id=&quot;display_image_url&quot;>
      <label>Paste Image Url</label>
      <input id=&quot;image-input&quot; class=&quot;inputBox_image&quot; type=&quot;text&quot; name=&quot;letter[cards_attributes][new_cards][remote_image_url]&quot; />
    </div>
    <div class=&quot;nav-popups-buttons&quot;>
      <button type=&quot;button&quot; id=&quot;validate_image&quot; class=&quot;small-cta2&quot;>Add Image</button>
      <p class=&quot;remove-link&quot; id=&quot;delete_new_card_image&quot;>Remove Image</p>
    </div>
  </div>
  <div>
    <input type=&quot;hidden&quot; name=&quot;letter[cards_attributes][new_cards][_destroy]&quot; id=&quot;letter_cards_attributes_new_cards__destroy&quot; value=&quot;false&quot; /><a class=&quot;remove-link remove_fields dynamic&quot; data-wrapper-class=&quot;carousel-slide&quot; href=&quot;#&quot;>Remove Card</a>
  </div>
</li>
" href="#" style="display: block;">+ Add Card</a>
              </div>
            </div>

它看起来像这样:

除了创建操作引发错误或加载编辑视图时,一切正常。在这两种情况下,已经创建的卡片被渲染,但插入后的回调没有被调用。因此,我无法显示我的按钮弹出窗口...

有没有办法在编辑视图/错误视图中调用渲染关联的插入后回调?

【问题讨论】:

    标签: jquery ruby-on-rails cocoon-gem


    【解决方案1】:

    如果我理解正确,您希望 after-insert 回调中的内容也适用于服务器呈现的 html。从某种意义上说,这很奇怪,因为恕我直言,这实际上是我首先要做的:)

    因此,不要附加点击事件,而是始终(动态地)处理它们。请注意 id-elements 只允许在一个页面中使用一次(正确的 html,否则会导致很多错误),所以我用类替换了所有这些,因为它们似乎在重复。

    所以做一些类似的事情

    $(document).on('click', '.add-card-button, .new-button-card'), function() {
      $('#black-background')[0].style.display = "block";
      $(this).nearest('.add-button-card-modal').css('display', 'block');
    }) 
    

    有人可能想知道为什么你不像普通人那样使用普通的模态库:P

    第二次点击处理程序,虽然稍微复杂一点,但实际上会以同样的方式解决,因此不再需要 after-insert 处理程序。

    类似

    $(document).on('click', '.delete-card-button', function() {
      ...
    })
    

    【讨论】:

      【解决方案2】:

      你真的不应该使用 jquery 来修复这样的编辑代码......这是一个症状,而不是问题......如果关系和 .builds 设置正确,编辑将正常工作并自动加载所有内容 - rails 所做的是生成表单的 hmtl。

      在您实际尝试使用 jquery hack 修复您的代码之前 - 我建议您构建一个没有弹出窗口的页面......所有这些都只是一团糟。如果嵌套模型适用于您当前的关系,那么请着手实现一系列复杂的弹出窗口。如果它不起作用 - 问题是您在模型中的关系或您的控制器使用 .build

      的方式

      也就是说,您正在寻找的答案可以在 jquery 中采用两种形式:

      1. 一般情况 - 您使用 $( document ).ready() 来检测何时一切就绪,以触发包含对 cocoon.jsafter-insert 回调的调用的函数。
      2. 具体 - 由于您可能知道包含按钮 field_for 的名称或 css 元素,因此您首先创建一个选择器来跟踪 field_for 周围的 css ...在您的情况下可能是 connected-carousels。您这样做是为了让 jquery 不会在您的 dom 周围徘徊并意外更改其他部分。然后,您使用 jquery .on() 将按钮所属类型的所有 dom 元素分配给触发的触发器。

      【讨论】:

      • 谢谢 Mirv,我会试试这个。我确实建立了一个没有弹出窗口的页面,并且一切正常......只是我的自定义 Jquery 不起作用,这在编辑案例中是有意义的。
      • 我到家了,终于可以打开你的链接了……我想我现在对其他一些东西的理解更好了。您可以测试的另一件事通常是茧具有回调传播问题...检查我一起通过的 jquery 故障排除列表github.com/nathanvda/cocoon/wiki/… ...特别是 stopPropagation() 可能是一个很好的测试调用...因为它有助于挂起(这会干扰您的后插入挂钩)...我仍然猜测您有 2 个问题,因为您从未发布过您的 rails 控制台对对象的调查结果
      • 我做了所有的测试,一切正常。同样,我认为正常的 Cocoon 在渲染字段时不会调用插入后回调。此功能旨在在有人单击 link_to_add_association 链接时起作用。在这种情况下,没有点击,现有记录只是呈现。我想我将不得不编写自定义 jquery...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-18
      相关资源
      最近更新 更多