Idea: only make request if element is visible
Use case:
Utilizing responsive principles, different elements of my page are hidden/shown depending on the screen size. As render_async works now, my page fetches all the elements at page load time, even the ones that are currently not being shown (perhaps they are only shown on small screens, for example). Obviously this is not ideal for performance reasons.
At least for the jQuery case, we could use the elem.is(':visible') pseudo-selector (as per https://stackoverflow.com/questions/178325/how-do-i-check-if-an-element-is-hidden-in-jquery) to determine whether the element is visible, and only fetch the async partial if it is (not sure about the non-jQuery case).
What if the user loads the page full-screen, and then shrinks the window? Perhaps there is a way to handle this case as well, but I haven't done the research.
Just putting this here as a feeler for now. What do you think?
Sounds like a great idea. We could add some lazy_load flag to render_async which will do a request only when it's visible.
I love the idea, if you want to submit a PR I'd be more than glad to help out :)
When things calm down a bit, I might give this one a try. Good to get some validation that it would be useful for others as well.
Maybe using this library? Might be pretty quick and painless, but is a dependency so perhaps a conditional gem install or something to signify they only add this dependency if they wish to do these types of "is visible" render_async calls?
https://github.com/creativelive/appear
Suggestion - because we have the "refresh" event which can refresh the partial, a simple flag to inhibit the initial load of the partial would allow the developer more flexibility.
Eg.
= render_async user_comments_path(user), container_id: "user_comments", replace_container: false, lazy: true
would set up the plumbing, then later the user could fire the refresh event to load/refresh the container...
$("#user_comments").trigger("refresh");
We can do this even with the toggle functionality
Basically, you should be able to do the following:
<%= render_async user_comments_path(user),
container_id: "user_comments",
toggle: { selector: "#user_comments", event: "load-me" } %>
And, then you can do:
const callbackToCallOnElementVisible = () => { // I got it to work by passing this callback to the IntersectionObserver
$("#user_comments").trigger("load-me");
}
WDYT about this, @vanboom?
Yes - this makes sense. I might be misunderstanding the toggle feature. If we do not specify interval the toggle event would not cause it to poll? (In many cases we want to delay loading, but cause the partial to refresh based upon the user clicking a refresh button or some other ajax event.)
If we do not specify interval the toggle event would not cause it to poll?
Yes, the toggle feature can be used without polling. I tried what I suggested above and it works. It might be worth to add it to the docs as an example.
Yes, this works great. I was able to use the jquery.appear plugin to detect the appearance of the element, then trigger the render-async toggle event...
$("#user_comments").appear({container: "body"});
$("#user_comments").on("appear", function(event, $all_appeared_elements){ $("#user_comments").trigger("load-me"); });
I actually put this code into a global function called render_async_on_appear(selector) to make it easy to call from anywhere in the app. Thanks for the tips on how to use the trigger functionality to achieve this!