Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Ajax page transitions (like Rails' Turbo) #1828

Open
maxim opened this issue Feb 14, 2024 · 4 comments
Open

Support for Ajax page transitions (like Rails' Turbo) #1828

maxim opened this issue Feb 14, 2024 · 4 comments
Labels
feature request New feature/change requested

Comments

@maxim
Copy link

maxim commented Feb 14, 2024

I'm not a front-end dev primarily, so I might be wrong, but I'll try my best to be right.

Rails framework has Turbo, which is a way to transition between urls by replacing page body with javascript (ajax), instead of reloading normally. I tried to make it work with Tabler, and got pretty close.

I can add Tabler library as a normal <script src="…">, but the problem is, this script wants to be fully reloaded in order to populate event listeners. Turbo will not reload this script on page transitions. So if a page transition happened, event listeners are lost, and tabler will never re-bind them.

If you're stubborn like me, and you want Tabler to work with Turbo, you can use a turbo hook called "turbo:load", which fires on both initial page load, and turbo transition. In that hook I wrote an ugly hack that removes and adds back the <script> tag each time, so that tabler gets reloaded.

This actually worked, all Tabler features started working with Turbo, yay! But now, bootstrap javascript behavior stopped working. Why? I'm not even requiring bootstrap myself, it's vendored in Tabler.

Well, it seems that Bootstrap adds all event listeners to the document object every time it's loaded, and since Turbo won't replace the document object, event listeners just keep getting added indefinitely. On each page transition I get another set of duplicate event listeners. This is bad in itself, but it really messes with the "toggle" functionality, because now when I, say, expand a navbar, it works, but when I try to collapse it, it collapses and expands again, making it seem like collapse doesn't work, because it seems multiple events toggle it back and forth. (I observed it step-by-step in a debug session.)

Can we make a small change to fix everything?

Describe the solution you'd like

I really hope this is a small change and it does what I think it does. Instead of having all the event-binding code loose in tabler.js, wrap it into a function. And to keep everything working the same way for everyone, just call this function immediately after. That's it.

Like:

function tablerInit {
  // everything that tabler.js does
}

tablerInit();

No behavior changed, but now I can call this function in a turbo hook to repopulate the listeners after page transitions. So now I can remove the ugly hack that re-inserts the <script>, and no longer worry about bootstrap loading repeatedly.

Describe alternatives you've considered

I've explored trying to clear the event listeners myself, but that quickly gets even uglier. I considered completely disabling turbo, but that feels incredibly unsatisfying when the solution seems so close (if I understood it correctly).

Another alternative solution might be for tabler to also attach all events to document, like bootstrap does. (But I don't know enough js to understand the implications of this.) 🤷🏻‍♂️

Would appreciate any feedback. Maybe this function already exists, and I didn't find it?

@BG-Software-BG BG-Software-BG added the feature request New feature/change requested label Feb 19, 2024
@maxim
Copy link
Author

maxim commented Feb 21, 2024

For now, my workaround was to copy most of the javascript init logic from tabler into my own project, and stop using tabler.js, instead depending directly on bootstrap.js. This way I can control all initialization. Thankfully there isn't much js code at all.

@pierredup
Copy link

I wonder if it would be useful to have a MutationObserver that will watch the DOM for changes, and re-registers some of the event listeners on only the changed nodes instead of re-applying the entire JS. Although I'm not sure how that will work with event listeners added to the global document object (maybe de-registering all event listeners and re-adding them when any DOM content changes)

@maxim
Copy link
Author

maxim commented Feb 21, 2024

@pierredup yeah, that sounds perfect. I didn't know about it.

The global document listeners don't need to do anything on mutation, they will just stay intact.

@cavasinf
Copy link

I've already asked about this: #986

For now, my workaround was to copy most of the javascript init logic from tabler into my own project, and stop using tabler.js, instead depending directly on bootstrap.js.

That's what they recommend to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature/change requested
Projects
None yet
Development

No branches or pull requests

4 participants