All threads / Infinite Scroll in Rails with Stimulus.js Discussion

Ask A Question

Notifications

You鈥檙e not receiving notifications from this thread.

Infinite Scroll in Rails with Stimulus.js Discussion

This is super slick. I wonder how easily one could append the query parameter in the URL to reflect the current page? Could History.replaceState() handle the job?

Should be pretty easy. Once the AJAX request succeeds, you can update the URL with a pushState. I would imagine you'd want pushState so you don't clobber the previous URL and it would keep the history as if you clicked each link. 馃憤

Reply

This rocks, coupled it with my MessagesController for Group Chats to reduce some of the load for the larger chats with lots of messages.

Reply

So excited to see this episode. Saw it pop up on your Github a while back, and was excited to see the video.

Reply
Reply

Thanks @excid3, very neat :-) One comment though, as capturing scroll events like this is usually quite CPU-intensive, wouldn't it be better to use an IntersectionObserver? (https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)

also see: https://m.signalvnoise.com/how-to-back-to-top-button-without-scroll-events/

I bet this could be a great way to improve that. 馃憤

Reply

Great episode. And a nice introduction to Stimulus.js to boot. One small comment, you may want to wrap the pagination area in a "display: none;" so it doesn't flash on the screen and isn't present when you hit the bottom.

Yup, definitely want to hide that navigation if you're using this for real. :)

Reply

For anyone implementing infinite scrolling behavior, I recommend checking out the method used by https://infinite-scroll.com

Instead of using JSON it uses regular HTML pages like you're already used to. No need to modify the controller or create a separate view template. Instead, they fetch the full http://localhost:3000/?page=2 (or whatever), but only use the content inside <div data-target="infinite-scroll.entries"> and append that to the existing div.

I thought it was a clever approach that feels very familiar as it reminds me of Turbolinks. There's very little setup and easy to maintain. With proper caching any performance hit is likely negligible.

I can see the strategy being used with only a slight modification of the code presented in the video.

Reply

So useful! I'm using this on my current project now..

Reply

Good tutorial Chris!
at 10:25 I am getting bellow error from console.log
Any idea why this is happening, please?

Error invoking action "[email protected]>infinite-scroll#scroll"
TypeError: "this.paginationTarget.querySelector(...) is null"
scroll infinite_scroll_controller.js:9
invokeWithEvent binding.js:52
handleEvent binding.js:29
handleEvent event_listener.js:30

infinite_scroll_controller.js

import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["entries", "pagination"]

scroll() {

let url = this.paginationTarget.querySelector("a[rel='next']").href

var body = document.body,

html = document.documentElement
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)

if (window.pageYOffset >= height - window.innerHeight - 100) {
this.loadMore(url)
}

}

loadMore(url) {

    Rails.ajax({
  type: 'GET',
  url: url,
  dataType: 'json',
  success: (data) => {

console.log(data)
}
})

}
}

index.html.erb

Reply

Thank you Chris, I just implemented infinite scroll on my web site.

When I open the page for the first time, I get this error "MediaController#index is missing a template for this request format and variant. request.formats: ["text/html", "text/html"] request.variant: []"

But when I refresh the page, It works right away. I couldn't find out the reason. Could you please help me. Thanks

Reply

I'm trying to implement a reverse-direction infinite scroll (infinite scroll up) using the refactored code. Everything seems to be working so far except that the scroll bar is jumping to the top of the prepend rather than staying at the same scroll position. I tried to implement the suggestions at the below link but with no luck. Any suggestions?

https://stackoverflow.com/questions/5688362/how-to-prevent-scrolling-on-prepend

Reply

I don't get the pageYOffset on my console when I test. They are no errors displayed.

scroll(){
console.log(window.pageYOffset);
}
}

div data-controller="infinite" data-action="[email protected]>infinte#scroll"

my stimulus controller is infinite_controller.js

Reply

This is awesome Chris! I noticed that on mobile browsers the scroll handler is called multiple times, resulting in multiple network requests and several duplicate pages being loaded and appended. If anyone else runs into this, adding a simple loading state to the controller can fix this:

export default class extends Controller {
  static targets = ['entries', 'pagination'];

  initialize() {
    this.loading = false;
  }

  scroll() {
    const nextPage = this.paginationTarget.querySelector("a[rel='next']");

    if (nextPage == null) return;

    const url = nextPage.href;
    const body = document.body;
    const html = document.documentElement;
    const height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);

    if (window.pageYOffset >= height - window.innerHeight - 500) {
      if (this.loading) return;

      this.loadMore(url);
    }
  }

  loadMore(url) {
    this.loading = true;

    Rails.ajax({
      type: 'GET',
      url,
      dataType: 'json',
      success: data => {
        this.entriesTarget.insertAdjacentHTML('beforeend', data.entries);
        this.paginationTarget.innerHTML = data.pagination;
        this.loading = false;
      }
    });
  }
}

Just create a global this.loading variable on initialize and set to true in the loadMore method, then set to false after a successful load and voila!

Reply

I'm having trouble migrating my Pagy pagination from Turbolinks to Turbo!

I posted about it here: https://discuss.hotwire.dev/t/pagy-infinite-scroll-and-get-post-requests/2853.

If anybody can help me, that'd be much appreciated. Thank you!

Reply
Join the discussion

Want to stay up-to-date with Ruby on Rails?

Join 48,387+ developers who get early access to new tutorials, screencasts, articles, and more.

    We care about the protection of your data. Read our Privacy Policy.

    logo Created with Sketch.

    Ruby on Rails tutorials, guides, and screencasts for web developers learning Ruby, Rails, Javascript, Turbolinks, Stimulus.js, Vue.js, and more. Icons by Icons8

    © 2021 GoRails, LLC. All rights reserved.