Skip to content
Advertisement

Rails 7 JavaScript event listeners stop working after browser back?

I have rails 7 app where I’m trying to build a search bar using either tom-select or slim-select. My issue reproduces no matter which library I’m using therefore it must be the issue on my rails side.

app/views/cities/index.html.erb

JavaScript

and this is my js controller (in this case I’m using tom-select) app/javascript/controllers/ts/search_controller.js

JavaScript

app/controllers/cities_controller.rb

JavaScript

Problem Repro:

  1. Open cities index and click on the search bar.
  2. Dropdown opens up, I can type, and select a suggestion. Once selected, suggestion appears in the search bar with an ‘x’ clicking which will remove the it from the search bar.
  3. I add any amount of search tokens, 1-N.
  4. Click “Search” -> Seeing the results page.
  5. Click the back button in the browser (or swipe back on a phone)

Expected behavior: The search bar is exactly as it was before the search. clicking on ‘x’ removes the token. clicking on the Search bar allows entering the search query and adding more tokens.

Actual behavior: I can see the tokens, but clicking anything but the ‘Search’ button, does nothing. I can see the same behavior across multiple demos like this one and this one.

How can i make the JS work after coming back?

Advertisement

Answer

JavaScript

When browser “back button” is used Turbo Drive does a restoration visit and displays a cached copy of the page. This copy is saved just before visiting another page. Any attached javascript behavior is lost, we only get html.

When Stimulus connects to [data-controller=ts–search] the select element is modified by TomSelect from this:

JavaScript

to this:

JavaScript

When clicking another link, this modified html is saved to cache and later is restored when using browser back navigation. Then Stimulus connects again, however, TomSelect skips .tomselected elements to avoid appending .ts-wrapper again. It looks the same because html and styles are loaded, but no javascript behavior is attached.

We can get a bit more context by turning on Stimulus debug logging:

JavaScript

If the page with the search form is cached and we navigate to it by clicking a link:

JavaScript

When using browser back navigation:

JavaScript

One more thing happens when navigating away from our form (by clicking away, browser back or browser forward):

JavaScript

Before the page is cached by Turbo, Stimulus calls disconnect() in our search controller. We can restore the original select here, before turbo caches the page. This way TomSelect can be reapplied on the cached page.

JavaScript

https://turbo.hotwired.dev/handbook/drive#restoration-visits

https://turbo.hotwired.dev/handbook/building#understanding-caching

https://stimulus.hotwired.dev/reference/lifecycle-callbacks#disconnection

https://tom-select.js.org/docs/api/#destroy

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement