After watching @chrismccord’s excellent “The Road To LiveView 1.0” keynote, the upcoming infinite scroll features with :limit on streamed collections looked like exactly what I needed to simplify the implementation of something I’m working on. I introduced LiveView to this project a while before it was even available on Hex, so I’m happy enough to depend on main to get the new features before 0.19 gets released.
However, my phx-viewport-top and phx-viewport-bottom events don’t seem to be triggering. Apart from switching my phoenix_live_view dependency to use github and adding those attributes to an element that has phx-update="stream", is there another step that I’m missing?
This is what’s in my template, with some irrelevant things removed or renamed:
Are you sure you’re on latest main? I didn’t merge the viewport branch stuff until recently.
Pretty sure – I only switched to tracking main and ran mix deps.get yesterday (I noticed that the branch was merged a few days ago). I can see Hooks.InfiniteScroll in app.js, so it looks like it’s compiling the right assets.
I’ll try creating a clean app and see if that works, and work from there. There’s almost certainly something obvious I’m missing!
Update – the test liveview that worked in a new app didn’t when I dropped it into the old one, so I suspected it was something to do with the asset-building process. The old app is still using Webpack, along with an ancient version of node.js and what seems like far too many npm packages, and when I tried installing esbuild instead the events suddenly started getting through OK. Time to bite the bullet and finally switch, I guess (it had been left as-is up to now to avoid figuring out how to get sass, bootstrap etc working with esbuild).
Thanks @fceruti, that definitely looks like it’s related to the issue I was having. My liveview was inside a grid layout, which ended up with the immediate parent appearing to have a height big enough to fit its content, with the scrolling happening further up the dom. I think the culprit was actually a footer which is a LiveComponent, with the generated phx-root div somehow confusing things. I ended up reworking the layout, and rendering the <footer> element in the layout instead of the component, and eventually managed to end up with the phx-update="stream" element having 100% height and the scroll events reaching the hook correctly.
My assumption that Webpack was somehow to blame was a complete red herring, but on the plus side I now have a nice clean asset build with esbuild, dart-sass and phoenix-copy, and a much cleaner node_modules directory! Somewhat reminiscent of when I migrated the same app from brunch to webpack, and from bootstrap 4 to 5 a few years ago, only to find that the thing that was actually causing brunch to fail had been a missing semicolon in a config file somewhere .
I’m also experiencing a similar issue with our application, where we’ve chosen to style our <body> tag as overflow-hidden, breaking the scroll behavior on the window object. Being able to specify a phx-viewport-container with a string that works with document.querySelector fixes the issue. @chrismccord , would you be open to a Pull Request allowing an optional phx-viewport-container attribute to be specified? The default would still use the window object.
Thanks @fceruti for the nudge in the right direction - I’d fought with LV’s InfiniteScroll hook myself for a while before arriving at the same conclusion: it doesn’t work unless the scrolling container is at the window root. This is a pretty severe limitation of the hook implementation; I’ve done the same as you and vendored the LV hook into our own code, and modified it so that it finds the nearest scrollable parent container as per your example.
@chrismccord I’d add another vote for a PR to the hook - I’d be happy to submit my implementation; it’s a pretty minimal diff.
My implementation is pretty much the same as yours, but the reason I didn’t create a PR, or shared it beyond the core idea, was that I saw/smelled some edge cases that I wouldn’t be using and didn’t make time for them, but should be covered in the framework’s solution. So thanks for taking responsability on this.
I believe that if the scroll container is very small in height, you’ll start to see the limitations of your current implementation of scrolltop. My intuition is that it should receive the scroll container as a parameter. Probably it’s neighbor functions should receive similar treatment.
I’m also curious how it would behave in a long article page, as a small sidebar ticker, (maybe a widget for stock prices). In all of my use cases the lists are always visible.
Another consideration I’m not so sure about, is how supported by browsers is getComputedStyle, when it was added, and does it match Phoenix browser support (is there such a thing?). In my cases, my users use reasonably new browsers, so I don’t care about legacy support.
Good points - I’m certain this solution isn’t perfect, but it will allow the hook to be used in more cases than at present. These additional use cases will very likely highlight other shortcomings, which can then be addressed.
We’ve had our own InfiniteScroll hook implemented for some time using IntersectionObserver, which makes the hook significantly less complicated - I’m unsure why the LiveView hook doesn’t leverage this; my intuition says that it would avoid some of the issues you allude to.
I didn’t leverage this or support other containers because it is significantly more complicated with all the edge cases and browsers. But if we get a solid contribution that works across browsers and isn’t over complex, I’m all for it!
My care-level is pretty low here, but I wanted to bring it up.
Regardless, thanks all for this work! I’m happy to do some testing though have no cycles to do any dev work.