Rails, render_async gem: How to use render_async inside a partial that is loaded via ajax

只谈情不闲聊 提交于 2021-01-28 11:21:51

问题


Problem

I'm using the gem "render_async" to render content asynchronously.

When I visit a page like localhost:3000/people, the content gets rendered asynchronously, as expected.

However, the content does not get rendered asynchronously, if it is inside a partial that got loaded via ajax. I don't understand why it isn't working and I don't know how to fix it.

How can I use render_async, if it is inside a partial that got loaded via ajax?

gem render_async: https://github.com/renderedtext/render_async

What works

When I call an index page like localhost:3000/people, render_async works as expected.

Here is the code that works:

people/index.html.erb

<h1>People</h1>
...
    <div class="people">
        <%= render partial: "people/show", collection: people, as: :person %>
    </div>

Inside the people-div, the partial _show.html.erb is being loaded.

people/_show.html.erb

<h1>Person</h1>
...
 <%= render_async render_shared_path(parent_type: "Person", parent_id: person.id), 'data-turbolinks-track': 'reload', error_message: '<p>Sorry, users loading went wrong :(</p>' do %>
      Shared lädt!
 <% end %>

This code works as expected. The render_async loads a partial called _children.html.erb. When a user visits people/index.html.erb, all _children-partials are being loaded asynchronously.

What doesn't work

On people/index.html, when the user presses a button, the people-div is being reloaded via ajax. Here is how the people div is being reloaded:

var people_div = ".people";

$( people_div ).fadeOut( "fast", function() {

    content = $("<%= escape_javascript( render 'people/people', people: @people ) %>")

    $(people_div).replaceWith(function(){
      return $(content).hide().fadeIn("fast");
    });

});

The code that is being reloaded is the same as in people/index. Only the params change.

After the people-div is reloaded, no content gets rendered asynchronously. The _children-partials are not being loaded.There are no messages in the rails console or in web console.

The only thing that is visible is the placeholder: "Shared lädt!".

What might be the problem?

Code

_show.html.erb

    <%= render_async render_shared_path(parent_type: "Person", parent_id: person.id), 'data-turbolinks-track': 'reload', error_message: '<p>Sorry, users loading went wrong :(</p>' do %>
      Shared lädt!
    <% end %>

routes.rb

  #render
  get '/render_shared', to: 'render#render_shared', as: 'render_shared'

render_controller.rb

  def render_shared
    parent_type = params[:parent_type]
    parent_id = params[:parent_id]

    @parent = parent_type.singularize.classify.constantize.find(parent_id)

    render partial: "shared/children"

  end

_children.html.erb

<% parent = parent || @parent %>

<div class="shared-<%=parent.class.name.downcase%>-<%=parent.id%>">
  <p>
    <a class="btn btn-link btn-sm" data-toggle="collapse" href=".address-<%= parent.id %>-<%= parent.class.to_s.downcase %>" role="button" aria-expanded="false" aria-controls="collapseExample">
      <%= fa_icon "address-card" %> Adresse anzeigen
    </a>
  </p>

  <div class="collapse mb-2 address-<%= parent.id %>-<%= parent.class.to_s.downcase %>" >
    <%= render "addresses/show", address: parent.address %>
  </div>

</div>

application.html.erb

  <head>
    <title>MyApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= content_for :render_async %>
  </head>

回答1:


After looking more into this issue, the problem seems to be in the Vanilla JS part of render_async. Vanilla JS doesn't evaluate script tags that come from the parent render_async response.

As a quick fix, I suggest that you try to use jQuery part of render_async, since it does evaluate script tags. You can turn on jQuery by doing:

RenderAsync.configure do |config|
  config.jquery = true # This will render jQuery code, and skip Vanilla JS code
end

Explanation

When you try to render a nested partial, render_async loads JS code inside a script tag that needs to be evaluated to do another request. jQuery has a powerfull method .replaceWith(text) which evaluates any script tags in the text variable. This is not so easy to achieve in plain JS. I'm trying to come up with a solution for this.

If anyone has an idea how to achieve this, you can contribute at this GitHub issue https://github.com/renderedtext/render_async/issues/30




回答2:


I think the problem here is that render_async JavaScript code is not triggered because it relies on DOMContentLoaded or $(document).ready() to be triggered.

In your case, those events are fired before the nested render_async JavaScript code is loaded on the page.

I have plans to improve this logic. I would create a possiblity to perform render_async logic immediately, if the document is ready, or listen for document to be ready and then perform the logic (like the current implementation).

Also, a similar issue has been raised in the issues https://github.com/renderedtext/render_async/issues/70



来源:https://stackoverflow.com/questions/52828240/rails-render-async-gem-how-to-use-render-async-inside-a-partial-that-is-loaded

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