问题
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