Specific page script in head doesn't get called first time I navigate on page. Code organization doubts

384 Views Asked by At

I'm using Turbolinks for the first time and not with Rails (I'm using Django).

REPRODUCTION

https://glitch.com/edit/#!/join/dc628a17-3ccd-47b4-9921-8fb332aaebb1

SOURCE CODE

  1. index.html:

    <html>
    <head>
      <script defer src="/js/index.js"></script>
    </head>
    <body>
      Text and NO <script></script>!
    </body>
    </html>
    
  2. about.html:

    <html>
    <head>
      <script defer src="/js/index.js"></script>
      <script defer src="/js/about.js"></script>
    </head>
    <body>
      Text and NO <script></script>!
    </body>
    </html>
    
  3. index.js:

    import Turbolinks from 'turbolinks'
    
    Turbolinks.start()
    
  4. about.js:

    function drawChart() {
      console.log("I will drawChart() here")
    }
    
    // drawChart() <--- this is commented on purpose here, with this it works!
    
    document.addEventListener('turbolinks:load', drawChart)
    

THE PROBLEM

If I start from page /index and then navigate by link to /about nothing happens!

If I now go back to /index I can see in console the log: I will drawChart() here. So the listener is working.

If I start (refresh on) from /about instead it print in console the message so the listener turbolinks:load is running the function drawChart() on refresh.

WHAT I EXPECT AND WHAT I DID

I need the call to the function drawChart() happens in the first navigation to /about too.

So I thought of using a direct call in the file (drawChart(), commented in the source code on this issue as you can see) and it works.

But I think this is not the good way to go, especially because if I go on /about and refresh the page it's called two times!

It seems to me too hacky.

Isn't?

WAHT DO OTHER PEOPLE DO

  1. Same problem but his solution doesn't work for me: https://candland.net/rails/2019/03/13/rails-turbolinks-not-firing-js-on-load.html

THANKS FOR YOUR WORK!

1

There are 1 best solutions below

1
On

I think the problem is that turbolinks:load is being fired before about.js is loaded. When Turbolinks renders a new page it will add any non-existent scripts to the <head> and then trigger lifecycle events e.g. turbolinks:load. In this case, it will not wait for every script to load before triggering turbolinks:load. Here's what's probably happening:

  1. index.html loads with index.js
  2. Navigate to about.html
  3. Turbolinks merges about.js
  4. about.js starts downloading
  5. Turbolinks completes the lifecycle and triggers turbolinks:load
  6. about.js finishes downloading and executes

Because turbolinks:load was already triggered in 5. the callback in about.js won't be called until the next load.

You may want to try including about.js at the bottom of the <body> of about.html. The turbolinks:load listener will not be needed.

Alternatively, try and include your JS in a single file, and perhaps use content of the page to determine when to call drawChart. For example:

import Turbolinks from 'turbolinks'

// about.js content here

Turbolinks.start()

document.addEventListener('turbolinks:load', function () {
  var chart = document.getElementById('chart')
  if (chart) drawChart()
})