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

Javascript not executing #9

Closed
coffeebite opened this issue Feb 12, 2016 · 27 comments

Comments

Projects
None yet
@coffeebite
Copy link

commented Feb 12, 2016

After upgrading to Turbolinks 5, the javascript in the new page is no longer executing. (Only the javascript in the original fully loaded page is executing). Has javascript execution in turbolinks 5 changed?

@svesely

This comment has been minimized.

Copy link

commented Feb 15, 2016

@coffeebite It looks like the event names have changed from a 'page' namespace to 'turbolinks'

See if $(document).on('turbolinks:visit',function(){...} works for you.

More info: https://github.com/turbolinks/turbolinks/tree/docs#observing-navigation-events

@packagethief

This comment has been minimized.

Copy link
Member

commented Feb 16, 2016

@svesely is correct – event names have changed. However, I don't think turbolinks:render is the best event to listen to if you want to attach behavior after the page loads.

In most cases you'll only need to listen for turbolinks:load. It fires once on the initial page load in response to DOMContentLoaded, and again on every Turbolinks visit, whether it’s triggered by clicking a link, clicking the "back" or "forward" buttons, or by calling Turbolinks.visit().

In Turbolinks Classic it's likely you're doing something like this:

$(document).on "ready page:load", ->
  # Install behavior, bind event listeners, etc.

In Turbolinks 5 this becomes simply:

$(document).on "turbolinks:load", ->
  # Install behavior, bind event listeners, etc.

Note that Turbolinks caches each page immediately before it's replaced. If you've made changes to the DOM on turbolinks:load, they'll be reflected in the cache. If these changes are non-idempotent, you'll need to ensure you're not applying them again when a cached page is loaded. For example, you might uninstall behavior and unwind non-idempotent changes on turbolinks:before-cache (your chance to prepare your DOM for cache storage), or you might use data- attributes to denote elements have already been transformed.

@coffeebite

This comment has been minimized.

Copy link
Author

commented Feb 16, 2016

Thanks guys. What I was referring to was this:

In the past, I could have a script tag in the middle of the body like this:

<script type="text/javascript">
  alert("Hello");
</script>

And it would execute when the page loaded via turbolinks. Now not any more.

@packagethief

This comment has been minimized.

Copy link
Member

commented Feb 16, 2016

Hi @coffeebite. Ah, yes. I understand now. Unfortunately Turbolinks 5 doesn't yet support script tag execution. It's on our list of missing features and we intend to add it before the final release.

@coffeebite

This comment has been minimized.

Copy link
Author

commented Feb 16, 2016

Thanks.

@packagethief

This comment has been minimized.

Copy link
Member

commented Feb 17, 2016

@coffeebite, I wondered if you wouldn't mind elaborating a bit on your need for inline script execution. The main reason for its omission is that we haven't needed it at Basecamp. Thinking now about implementing it, a few questions come up as to how it should behave. Real-world examples, if you have them, would be helpful.

Thanks!

@aaronvb

This comment has been minimized.

Copy link

commented Feb 18, 2016

@packagethief This is an old example but might still be relevant: turbolinks/turbolinks-classic#173

<script type="text/javascript">
  window.foo = <%= @foo.to_json %>;
</script>
@coffeebite

This comment has been minimized.

Copy link
Author

commented Feb 18, 2016

@packagethief

We have a page where we rotate between different embedded content (say between youtube embed, flickr embed etc).

Some of these embeds e.g. a twitter widget, are just plain old javascript.

Here is an example page

http://padlet.com/demo_simon/goqx5gh33b/wish/4046565

@packagethief

This comment has been minimized.

Copy link
Member

commented Feb 18, 2016

Thanks @aaronvb and @coffeebite. Exactly the kind of examples I was looking for.

@connorshea

This comment has been minimized.

Copy link

commented Mar 3, 2016

@packagethief I believe react-rails needs it in order to work.

@nanaya

This comment has been minimized.

Copy link
Contributor

commented Mar 3, 2016

For simple cases, I wonder if adding an event listener doing something like this during turbolinks:render will work...

@chaodoze

This comment has been minimized.

Copy link

commented Mar 15, 2016

+1 for executing <script> tags. Have a use case to render maps (e.g. google or leaflet), which require <script> tags

@u007

This comment has been minimized.

Copy link

commented Mar 22, 2016

also we need jquery on ready to load too for new / not yet cached pages?

@wimleers

This comment has been minimized.

Copy link

commented Mar 23, 2016

Even new <script> tags referencing external scripts in the <head> of the page are not executed. So this problem is not limited to inline scripts or scripts in <body>.

Let's say I'm currently on /a and navigate to /b. /b contains some JS that did not exist on /a.

/a:

<head>
<script src="foo.js">
</head>

/b:

<head>
<script src="foo.js">
<script src="bar.js">
</head>

When navigating from /a to /b, Turbolinks correctly ends up with this in the DOM:

<head>
<script src="foo.js">
<script src="bar.js">
</head>

… but bar.js is never fetched, let alone executed.

Is this expected? Or perhaps this is a problem on my side?

@aaronvb

This comment has been minimized.

Copy link

commented Mar 23, 2016

@wimleers In the docs it states Turbolinks will reload the body and merge head, which I assume by design shouldn't reload anything in head unless you reload the page. By adding data-turbolinks-track="reload" to your script tag, Turbolinks will reload the page if it detects a change.

I ran into this issue while using a content_for yield in head.

@wimleers

This comment has been minimized.

Copy link

commented Mar 23, 2016

@aaronvb I'm not talking about reloading, I'm talking about loading at all. i.e. if different pages have different sets of scripts. Is this so uncommon in the Rails world?

(I'm coming at this from the Drupal world.)

@nateberkopec

This comment has been minimized.

Copy link
Contributor

commented Mar 23, 2016

@wimleers No, that isn't uncommon. I think it's a valid use case.

@aaronvb

This comment has been minimized.

Copy link

commented Mar 23, 2016

@wimleers Sorry, when I said reloading I meant reloading any sources in head including old and new. So in your case the new JS source wont be loaded.

During rendering, Turbolinks replaces the current <body> element outright and merges the contents of the<head> element. - https://github.com/turbolinks/turbolinks#navigating-with-turbolinks

Also check out https://github.com/turbolinks/turbolinks#reloading-when-assets-change - this is how I got it to at least load the new JS source when the page changes.

@sstephenson

This comment has been minimized.

Copy link
Contributor

commented Mar 23, 2016

You’re not missing anything—we currently don’t load or evaluate any <script> tags beyond the ones processed by the browser on the initial page load.

We’re working on a general solution and will have one ready for the 5.0.0 release.

@wimleers

This comment has been minimized.

Copy link

commented Mar 23, 2016

Ok, cool :)

@u007

This comment has been minimized.

Copy link

commented Mar 24, 2016

@u007

This comment has been minimized.

Copy link

commented Mar 25, 2016

i made a work around,
but this does not detect any new js being added to force a reload.
maybe you may add this functionality.

my admin layout call this:
EZB.init();

So i only add jQuery(document).on('ready'),
and the rest is handled by my coffeescript:

EZB.turbolink_loaded = false
EZB.init = ->
  if EZB.turbolink_loaded
    return
  jQuery(document).on('turbolinks:load', (e)->
    EZB.render_init()
  )
  document.addEventListener("turbolinks:request-start", (event)=>
    xhr = event.data.xhr
    xhr.setRequestHeader("X-Request-Turbo", 1)
  )
  return

EZB.render_init = ->
  console.log('render init')
  //todo your other scripting such as bootstrap tabs, selectize or select2 scripts
  if EZB.turbolink_loaded
    # not 1st time, loaded via turbo link
    $('script').each((e)->
      dom = $(this)
      # console.log('src', dom.attr('src'))
      if (!dom.attr('src'))
        content = this.innerHTML
        # console.log('evaluating', content)
        eval(content)

    )
  else
    EZB.turbolink_loaded = true

by using this method, jquery on ready will not be called inside render_init, but its called naturally the first page it load / when page refreshes.
when turbolink open another page or back button is pressed, turbolink_loaded is set, therefore all plain scripts will be executed. perhaps someone can further improve it by getting only script within the body to execute, and leave those in header (assumed not changed) as ignored.

@attenzione

This comment has been minimized.

Copy link

commented Mar 31, 2016

changing line below to { html: @response, ... } will fix issue unless you have cache enabled.
btw i don't understand why there is snapshot?
https://github.com/turbolinks/turbolinks/blob/master/src/turbolinks/visit.coffee#L75

@sstephenson

This comment has been minimized.

Copy link
Contributor

commented Mar 31, 2016

@attenzione I do not recommend making that change. The html option is only intended for rendering error responses.

@sstephenson

This comment has been minimized.

Copy link
Contributor

commented Mar 31, 2016

We’re tracking development over in #65, for anyone who is interested in following along.

@attenzione

This comment has been minimized.

Copy link

commented Mar 31, 2016

Off course I'll wait release, I just experimenting 😊

@sstephenson

This comment has been minimized.

Copy link
Contributor

commented Apr 1, 2016

Script element support is now available in Turbolinks 5.0.0.beta4.

@sstephenson sstephenson closed this Apr 1, 2016

acamino added a commit to acamino/hippocrates that referenced this issue Jul 14, 2017

Fix: Make JS plays nicely with Turbolinks
JavaScript was no executing when the page loads, it requires refreshing
the page to load the scripts. This commit changes the listener `ready`
to `turbolinks:load`.

turbolinks/turbolinks#9 (comment)

@0sc 0sc referenced this issue Sep 29, 2017

Merged

fix map display bug #4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.