javascriptruby-on-railsrubyturbolinkshotwire

Rails 7 portfolio webpage seemingly wont load application.js unless reloaded


I took my first step into creating a website with my own two hands to much of my peril (being so new). That being said, I know I'm sloppy so please correct EVERY SINGLE DETAIL you can so I can learn :) Initially, developing with Rails 7 + bootstrap and the usual html/CSS seemed easy. Somewhere along the line, I added a hidden/show animation to elements in my website using the following javascript in assets/javascript/application.js. The problem is that this doesn't work when I navigate to other pages in any way (href, link_to tags etc.) UNLESS I reload the page I just navigated to. I looked into it, the javascript seems to be cached in the browser but not reloaded, I evaluated this with a console log (I believe, I may be wrong however) as the reload caused the it to log, but navigating to the same page did not log. Here is some of the code to mull through, please point any short comings, I'm hungry to be better haha!

import "@hotwired/turbo-rails"
import "controllers"

const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
        console.log(entry)
        if (entry.isIntersecting){
            entry.target.classList.toggle('show', entry.isIntersecting);
        } else {
            entry.target.classList.remove('show');
        }
    });
});

const hiddenElements = document.querySelectorAll('.hidden');
hiddenElements.forEach((el) => observer.observe(el));

The CSS being the following;

.hidden{
    opacity: 0;
    filter: blur(5px);
    transition: opacity, filter 1s;
}
@media(prefers-reduced-motion){
    .hidden{
        transition: none;
    }
}
.show{
    opacity: 1;
    filter: blur(0);
}

And an example of the used HTML being;

<h1 class="hidden" style="text-align:center;font-size:50px;">About me</h1>

As said above, I have inspected the webpage and found the javascript to be present (thanks to rails asset pipeline I believe?). I included a window alert and console log below the shown javascript to see if the application.js is loaded. If the page is navigated to (via link_to or href's), no alert or console log is shown. However, navigating to the page and then reloading causes the javascript to work as intended and the console log/alert shows. I have a suspicion it is to do with my naivety to do with turbo drive & all the Hotwire stuff in Rails that I'd love to understand but do not haha!


Solution

  • When you reload the page everything is loaded for the first time, including application.js, and this part is executed and observers are added:

    const hiddenElements = document.querySelectorAll('.hidden');
    hiddenElements.forEach((el) => observer.observe(el));
    

    When you navigate to other pages, Turbo handles the request and response. Only the <body> of the page is updated, anything that was present in the <head> tag is not reloaded, so application.js is not loaded again, which means you don't have observers.

    To run code again on subsequent visits, you have to listen for Turbo events to know when navigation happens:

    // app/javascript/application.js
    
    console.log("application.js. runs one time only");
    
    document.addEventListener("turbo:load", (event) => {
      console.log("turbo:load. runs every time a page is loaded");
    
      const hiddenElements = document.querySelectorAll(".hidden");
      hiddenElements.forEach((el) => observer.observe(el));
    });
    

    https://turbo.hotwired.dev/reference/events