Simple Polling With Turbo Frames

A simple trick to let Turbo keep refreshing your views

Jonathan Greenberg
By Jonathan Greenberg
December 12, 2023

One cool feature that comes with Turbo are Eager Loaded Frames. By simply adding a src attributes to your turbo frame Turbo will make an asynchronous request to the given url when the turbo frame is rendered on the page. This simple feature while powerful in itself can be the jumping off point for many other useful features. In this blog post we will show a way to create a simple self-polling frame with the assistance of a Stimulus controller.

The use case for this feature is having a part of your page that needs to regularly poll the server for updates and perhaps terminates after a certain result has been attained. To achieve our goal we are going to manipulate the complete attribute that Turbo adds to the frame as the final step in the lifecycle while making the src url request. While the complete attribute is mentioned in the documentation it is not advertised that if you remove the attribute the request will be made again!

Here is some sample code to illustrate how this might work:

  <%%= turbo_frame_tag(
    'import-results',
    src: admin_import_path(import),
    data: {
      controller: 'polling',
    }
  ) %>

and here is the Stimulus controller:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["finished"]
  connect() {
    this.interval = setInterval(() => {
      this.element.removeAttribute('complete')
    },
    1000)
  }

  finishedTargetConnected() {
    clearInterval(this.interval)
  }
}

As soon as the stimulus controller connects to the page an interval is establish that removes the complete attribute from our turbo_frame every second. The result from the request just needs to be sure to wrap its content in a turbo_frame with the matching id (i.e.import-results) and we are polling!

To end polling we can simply use another little Stimulus trick by adding:

 <div data-polling-target="finished"></div>

into our turbo_frame content and through the power of target callbacks fueled under the covers by MutationObserver we get our polling interval to terminate.

So there you have it: simple polling with a Turbo frame backed by a Stimulus controller with just a few lines of code.

If you’re looking for a team to help you discover the right thing to build and help you build it, get in touch.