Stimulus Discourse

New lifecycle callback for Turbolinks


#1

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.


#2

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

Am I reading this wrong? https://stimulusjs.org/handbook/managing-state#lifecycle-callbacks-explained


#3

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


#4

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


#5

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

#6

See: https://discourse.stimulusjs.org/t/controller-initialized-twice-when-visiting-from-a-turbolinks-page/17/3:


#7

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")) {
    this.datatableMount()
    document.addEventListener("turbolinks:before-cache", () => this.datatableUnmount(), { once: true })
}