If you use Alpine.js and Turbolinks together, there may be times where you want an Alpine-powered element to do something when the Turbolinks turbolinks:load event fires. Unfortunately, the following code doesn't work:
<div
x-data="{}"
x-on:turbolinks:load="console.log('Turbolinks load event should fire')"
></div>
The x-on shorthand syntax (@) doesn't work either:
<div
x-data="{}"
@turbolinks:load="console.log('Turbolinks load event should fire')"
></div>
What's going on here? Well, according to Alpine's docs for the x-on directive:
x-oncan only listen for events with lower case names, as HTML attributes are case-insensitive. Writingx-on:CLICKwill listen for an event namedclick.Alternatively, you can use
x-bindto attach anx-ondirective to an element in javascript code (where case will be preserved).
It seems that Alpine's x-on directive and @ shorthand don't work with anything except lowercase characters. The colon in turbolinks:load seems to be the cause of our problem. We can use Alpine's x-bind directive to work around this, which preserves both the case and characters of the bound attributes:
<div
x-data="{}"
x-bind:x-on:turbolinks:load="console.log('Turbolinks load event fired')"
></div>
Using x-bind with the x-on shorthand also works:
<div
x-data="{}"
x-bind:@turbolinks:load="console.log('Turbolinks load event fired')"
></div>
You can now execute code when Turbolinks completes a page transition.
An alternative solution
Conversely, it might be better to use x-init with Alpine's $nextTick() magic function, which will execute only after the page has finished loading. If you're familiar with React.js, this is similar to useEffect(..., []).
<div
x-data="{}"
x-init="$nextTick(() => console.log('The new page has loaded')"
></div>
This solution is nice because it isn't tightly-coupled to Turbolinks. If you removed Turbolinks from your site, the x-init code would continue to fire when a new page is loaded.
Top comments (1)
Thanks for this post! Here are my workarounds:
[Note]
x-data