Haseeb Ahmad
Haseeb Ahmad

Reputation: 8730

Rails js script code not working while screen back due to Turbolinks

In my rails app there is a JS script in partial view

 const f2s = window.document.createElement("script");
   f2s.defer = true;
   (f2s.src = "https://face2.oktium.com/face2widget.js"),
   (f2s.onload = function () {
   new window.Oktium(face2params).init();
   new window.Oktium(face2paramsMobile).init();
 }),
 document.head.appendChild(f2s);

it works fine when page load for first but when comes again from back or another page which have same code its not working. How can I work that with turbolinks?

Upvotes: 0

Views: 1350

Answers (3)

Niko
Niko

Reputation: 1

Bit of a repetition of what others have suggested, but I just wanted to stress that it was the wrapping of the functionality needed for the partial/view including variable declarations that worked for me. Initially I used the following in the erb which worked with some exceptions.

<div id="cart-counter" data-turbo-permanent>1 item</div>

This kind of worked but when user clicked button type submit on other pages, it broke again.

Tried many things, and as others have described, the following worked: wrapped the script I needed for that view with :

document.addEventListener("turbo:load", ()=>{
  // functionality 
}

Upvotes: 0

mechnicov
mechnicov

Reputation: 15248

From turbolinks docs

Working with Script Elements

Your browser automatically loads and evaluates any <script> elements present on the initial page load.

When you navigate to a new page, Turbolinks looks for any <script> elements in the new page’s <head> which aren’t present on the current page. Then it appends them to the current <head> where they’re loaded and evaluated by the browser. You can use this to load additional JavaScript files on-demand.

Turbolinks evaluates <script> elements in a page’s <body> each time it renders the page. You can use inline body scripts to set up per-page JavaScript state or bootstrap client-side models. To install behavior, or to perform more complex operations when the page changes, avoid script elements and use the turbolinks:load event instead.

Annotate <script> elements with data-turbolinks-eval="false" if you do not want Turbolinks to evaluate them after rendering. Note that this annotation will not prevent your browser from evaluating scripts on the initial page load.

Loading Your Application’s JavaScript Bundle

Always make sure to load your application’s JavaScript bundle using <script> elements in the <head> of your document. Otherwise, Turbolinks will reload the bundle with every page change.

<head>
  ...
  <script src="/application-cbd3cd4.js" defer></script>
</head>

If you have traditionally placed application scripts at the end of <body> for performance reasons, consider using the <script defer> attribute instead. It has widespread browser support and allows you to keep your scripts in <head> for Turbolinks compatibility.

You should also consider configuring your asset packaging system to fingerprint each script so it has a new URL when its contents change. Then you can use the data-turbolinks-track attribute to force a full page reload when you deploy a new JavaScript bundle.

You can wrap your JS script inside such handler inside script tag in the head

<script defer>
  document.addEventListener('turbolinks:load', () => {
    // your code here
  })
</script>

Also in Rails there is mechanism how to add some tags dynamically, you can add in the <head> in layout/application

<%= yield(:face2) %>

And then in your specific view

<% content_for(:face2) do %>
  <script defer src="https://face2.oktium.com/face2widget.js" data-turbolinks-eval="false"></script>

  <script>
    document.addEventListener('turbolinks:load', () => {
      new window.Oktium(face2params).init()
      new window.Oktium(face2paramsMobile).init()
    })
  </script>
<% end %>

Upvotes: 3

anonymus_rex
anonymus_rex

Reputation: 579

You should wrap your JS code inside

$(document).on('turbolinks:load', function() {
  ...
}

Upvotes: 0

Related Questions