Stimulus Discourse

New lifecycle callback for Turbolinks


I’m currently using Turbolinks along with Stimulus, and I think it would be useful to have a new lifecycle method that gets called once and is not called again for Turbolinks visits. This is helpful for “higher-order controller” that manage state for the entire browsing session. This is simply an optimization, because without Turbolinks, everything will be reloaded again on every page load anyways.


Does the initialize callback not handle this? Is it being called on Turbolinks visits?

Am I reading this wrong?


From what I’m seeing on my console logging, it goes through the entire lifecycle for every turbolinks visit:

initialize => connect => disconnect

Also, interestingly, when you navigate back and turbolinks loads from cache and then replaces the cache with the freshly fetched page, you’ll see:

initialize => connect => disconnect => initialize => connect => disconnect


I have exact the same problem - if i’m getting this well, initialize should be called just once but it gets called for each visit.

So, when i have a controller on /foo and i call Turbolinks.visit('/foo'), initialize() of this controller gets called twice - once for page load and second for Turbolinks.visit


Ok if anyone needs that: to make it call initialize just once, you need to:

  1. add data-turbolinks-permanent attribute to the element
  2. set an unique id attribute for that element




I’m using Stimulus as a wrapper around datatables. For me, adding data-turbolinks-permanent did not solve the problem.

Instead, I check whether we’re dealing with the preview and don’t attempt to mount the plugin if so:

  if (!document.documentElement.hasAttribute("data-turbolinks-preview")) {
    document.addEventListener("turbolinks:before-cache", () => this.datatableUnmount(), { once: true })