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-on
can only listen for events with lower case names, as HTML attributes are case-insensitive. Writingx-on:CLICK
will listen for an event namedclick.
Alternatively, you can use
x-bind
to attach anx-on
directive 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