Turbolinks making JavaScript not fire causing dropdowns to only work on refresh

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Turbolinks making JavaScript not fire causing dropdowns to only work on refresh



I have a notification dropdown menu being fired by adding a CSS class via Javascript. However, I am certain that Turbolinks is causing it to not work properly, as it seems to only work on refresh.



There is a data-turbolinks="true" in the <body> tag of the document. If I change this to false I get normal operation.


data-turbolinks="true"


<body>


false



If I put the data-turbolinks="false" in the <div> tag of the specific links it still does not work properly.


data-turbolinks="false"


<div>



So I am thinking I will have to change the JaveScript so it is not affected by the Turbolinks. However, I am not sure how to go about this. This is for a Laravel 5.6 app.


/*--------------------------------------------------*/
/* Notification Dropdowns
/*--------------------------------------------------*/
$(".header-notifications").each(function()
var userMenu = $(this);
var userMenuTrigger = $(this).find('.header-notifications-trigger a');

$(userMenuTrigger).on('click', function(event)
event.preventDefault();

if ( $(this).closest(".header-notifications").is(".active") )
close_user_dropdown();
else
close_user_dropdown();
userMenu.addClass('active');

);
);

// Closing function
function close_user_dropdown()
$('.header-notifications').removeClass("active");


// Closes notification dropdown on click outside the conatainer
var mouse_is_inside = false;

$( ".header-notifications" ).on( "mouseenter", function()
mouse_is_inside=true;
);
$( ".header-notifications" ).on( "mouseleave", function()
mouse_is_inside=false;
);

$("body").mouseup(function()
if(! mouse_is_inside) close_user_dropdown();
);

// Close with ESC
$(document).keyup(function(e)
if (e.keyCode == 27)
close_user_dropdown();

);





How is this script included in a page? Is it part of a main JS file in the <head>? Is it run on turbolinks:load or $(document).ready?
– Dom Christie
Aug 12 at 16:37


<head>


turbolinks:load





It's in a custom.js file that's called in the <head> of the page. How do I tell if it's ran on turbolinks:load or $(document).ready?
– inputchip
Aug 13 at 2:45



custom.js


<head>


turbolinks:load


$(document).ready





Code is run on turbolinks:load or $(document).ready if you have wrapped you code in a function that is executed on either of those events e.g. $(document).on('turbolinks:load', function () CODE ). From your response, I guess it is not, so I'm a little confused as to how this is working in the first place! Oh well, hope my answer helps :)
– Dom Christie
Aug 13 at 8:52


turbolinks:load


$(document).ready


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




1 Answer
1



I think the issue is that the script only selects the elements on the first page load, rather than on every page load. For example, calling $(".header-notifications") will attempt to find all the elements with a class of .header-notifications, however this is only run once, so when a new page is loaded with Turbolinks , the body gets replaced, and those selected elements no longer exist. Scripts are not executed again until a full page load, and so this script is only run once—.header-notifications elements are never reselected.


$(".header-notifications")


.header-notifications


body


.header-notifications



To fix this, the Turbolinks README recommends using event delegation:



When possible, avoid using the turbolinks:load event to add other event listeners directly to elements on the page body. Instead, consider using event delegation to register event listeners once on document or window.



So you add your event listeners to the document or window, then choose which elements it should run on with a selector, e.g.:


$(document).on(
"click", ".header-notifications-trigger a", function (event) …
)



This means that any time a .header-notifications-trigger a element is added to the page, the click event handler will be fired.


.header-notifications-trigger a



With that in mind, you may wish to update your script to something like:


/*--------------------------------------------------*/
/* Notification Dropdowns
/*--------------------------------------------------*/

// For convenience and to prevent unnecessary $() calls
var doc = $(document);

doc.on("click", ".header-notifications-trigger a", function (event)
event.preventDefault();

var user_menu = $(this).closest(".header-notifications");

if (user_menu.is(".active"))
close_user_dropdown();
else
close_user_dropdown();
user_menu.addClass('active');

);

// Closing function
function close_user_dropdown()
$('.header-notifications').removeClass("active");


// Closes notification dropdown on click outside the container
var mouse_is_inside = false;

doc.on("mouseenter", ".header-notifications", function()
mouse_is_inside = true;
);

doc.on("mouseleave", ".header-notifications", function()
mouse_is_inside = false;
);

doc.on("mouseup", function()
if(!mouse_is_inside) close_user_dropdown();
);

// Close with ESC
doc.on("keyup", function(e)
if (e.keyCode == 27)
close_user_dropdown();

);





Thank you so much!!
– inputchip
Aug 13 at 18:16





This solution solved the issue with the dropdown menus. But for some reason, my images are now only showing on the first visit (or refresh). Any ideas? I'm guessing it has to do with the event delegation, as it is now affecting the whole document.
– inputchip
Aug 14 at 6:06






Event delegation shouldn't affect image loading. How are you loading the images? Are you seeing any errors in the JS console?
– Dom Christie
Aug 14 at 8:20





I just noticed I was having this error before I put in your updated script. This issue is still related to turbolinks, but I will start a new thread to discuss this issue. If you have any ideas, I would love to hear them! stackoverflow.com/questions/51850497/…
– inputchip
Aug 14 at 22:20






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard