jQuery.Ready fires during unload - any way to prevent this? - javascript

I have a page that loads some external scripts via defer:
<script src="externalPlugin.js" defer></script>
I then have some code in jquery.ready that calls stuff from that script
$(function() {
$.externalPlugin();
});
So far so good, it works 99.9% of the time.
The problem
If a user navigates away from the page (hits "refresh", or just quickly navigates to another page) while the externalScript is still loading/executing - jQuery.ready still gets called (!) and obviously throws this error: $.externalPlugin is not a function or similar.
How do I fight this?
I tried adding an beforeunload handler that removes the ready binding
window.addEventListener("beforeunload",function() { $(document).unbind("ready"); });
But it does not work.
This is not a big issue (after all the user is navigating AWAY so he doesn't care about any errors), but still that's interesting behavior.
update
Yep, I know that I can wait the definition or even use <script defer onload='whatever()'> but I was wondering if there's a "global" way to fix this universally - by not calling .ready if the page is being unloaded... If not - I'd say this is actually a bug that has to be reported to jQuery team, eh?

If you have to initiate the script on your main page in dom ready, remove the defer attribute of the script :
<script src="externalPlugin.js"></script>
You can either wait the function définition :
function wait(fn, delay)
{
var i = setInterval(function(){
if(fn() && typeof fn() == "function")
{
clearInterval(i);
fn()();
}
}, delay);
}
$(document).ready(function(){
wait(function(){ return $.externalPlugin }, 100);
});

Wait till script loaded
$(function() {
waitPlugin();
});
function waitPlugin(){
if( $.externalPlugin == null ) {
setTimeout(waitPlugin,1000);
return;
}
$.externalPlugin();
}
But I would reorganize the code some way.

Related

addEventListener is Not Working as Expected (Inner HTML is not Populating) [duplicate]

I need to execute some JavaScript code when the page has fully loaded. This includes things like images.
I know you can check if the DOM is ready, but I don’t know if this is the same as when the page is fully loaded.
That's called load. It came waaaaay before DOM ready was around, and DOM ready was actually created for the exact reason that load waited on images.
window.addEventListener('load', function () {
alert("It's loaded!")
})
For completeness sake, you might also want to bind it to DOMContentLoaded, which is now widely supported
document.addEventListener("DOMContentLoaded", function(event){
// your code here
});
More info: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Usually you can use window.onload, but you may notice that recent browsers don't fire window.onload when you use the back/forward history buttons.
Some people suggest weird contortions to work around this problem, but really if you just make a window.onunload handler (even one that doesn't do anything), this caching behavior will be disabled in all browsers. The MDN documents this "feature" pretty well, but for some reason there are still people using setInterval and other weird hacks.
Some versions of Opera have a bug that can be worked around by adding the following somewhere in your page:
<script>history.navigationMode = 'compatible';</script>
If you're just trying to get a javascript function called once per-view (and not necessarily after the DOM is finished loading), you can do something like this:
<img src="javascript:location.href='javascript:yourFunction();';">
For example, I use this trick to preload a very large file into the cache on a loading screen:
<img src="bigfile"
onload="this.location.href='javascript:location.href=\'javascript:doredir();\';';doredir();">
Try this it Only Run After Entire Page Has Loaded
By Javascript
window.onload = function(){
// code goes here
};
By Jquery
$(window).bind("load", function() {
// code goes here
});
Try this code
document.onreadystatechange = function () {
if (document.readyState == "complete") {
initApplication();
}
}
visit https://developer.mozilla.org/en-US/docs/DOM/document.readyState for more details
Javascript using the onLoad() event, will wait for the page to be loaded before executing.
<body onload="somecode();" >
If you're using the jQuery framework's document ready function the code will load as soon as the DOM is loaded and before the page contents are loaded:
$(document).ready(function() {
// jQuery code goes here
});
the window.onload event will fire when everything is loaded, including images etc.
You would want to check the DOM ready status if you wanted your js code to execute as early as possible, but you still need to access DOM elements.
You may want to use window.onload, as the docs indicate that it's not fired until both the DOM is ready and ALL of the other assets in the page (images, etc.) are loaded.
In modern browsers with modern javascript (>= 2015) you can add type="module" to your script tag, and everything inside that script will execute after whole page loads. e.g:
<script type="module">
alert("runs after") // Whole page loads before this line execute
</script>
<script>
alert("runs before")
</script>
also older browsers will understand nomodule attribute. Something like this:
<script nomodule>
alert("tuns after")
</script>
For more information you can visit javascript.info.
And here's a way to do it with PrototypeJS:
Event.observe(window, 'load', function(event) {
// Do stuff
});
The onload property of the GlobalEventHandlers mixin is an event
handler for the load event of a Window, XMLHttpRequest, element,
etc., which fires when the resource has loaded.
So basically javascript already has onload method on window which get executed which page fully loaded including images...
You can do something:
var spinner = true;
window.onload = function() {
//whatever you like to do now, for example hide the spinner in this case
spinner = false;
};
Completing the answers from #Matchu and #abSiddique.
This:
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
});
Is the same as this but using the onload event handler property:
window.onload = (event) => {
console.log('page is fully loaded');
};
Source:
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
Live example here:
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event#live_example
If you need to use many onload use $(window).load instead (jQuery):
$(window).load(function() {
//code
});
2019 update: This is was the answer that worked for me. As I needed multiple ajax requests to fire and return data first to count the list items.
$(document).ajaxComplete(function(){
alert("Everything is ready now!");
});

Event listener after all resources loaded and all scripts executed [duplicate]

I need to execute some JavaScript code when the page has fully loaded. This includes things like images.
I know you can check if the DOM is ready, but I don’t know if this is the same as when the page is fully loaded.
That's called load. It came waaaaay before DOM ready was around, and DOM ready was actually created for the exact reason that load waited on images.
window.addEventListener('load', function () {
alert("It's loaded!")
})
For completeness sake, you might also want to bind it to DOMContentLoaded, which is now widely supported
document.addEventListener("DOMContentLoaded", function(event){
// your code here
});
More info: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Usually you can use window.onload, but you may notice that recent browsers don't fire window.onload when you use the back/forward history buttons.
Some people suggest weird contortions to work around this problem, but really if you just make a window.onunload handler (even one that doesn't do anything), this caching behavior will be disabled in all browsers. The MDN documents this "feature" pretty well, but for some reason there are still people using setInterval and other weird hacks.
Some versions of Opera have a bug that can be worked around by adding the following somewhere in your page:
<script>history.navigationMode = 'compatible';</script>
If you're just trying to get a javascript function called once per-view (and not necessarily after the DOM is finished loading), you can do something like this:
<img src="javascript:location.href='javascript:yourFunction();';">
For example, I use this trick to preload a very large file into the cache on a loading screen:
<img src="bigfile"
onload="this.location.href='javascript:location.href=\'javascript:doredir();\';';doredir();">
Try this it Only Run After Entire Page Has Loaded
By Javascript
window.onload = function(){
// code goes here
};
By Jquery
$(window).bind("load", function() {
// code goes here
});
Try this code
document.onreadystatechange = function () {
if (document.readyState == "complete") {
initApplication();
}
}
visit https://developer.mozilla.org/en-US/docs/DOM/document.readyState for more details
Javascript using the onLoad() event, will wait for the page to be loaded before executing.
<body onload="somecode();" >
If you're using the jQuery framework's document ready function the code will load as soon as the DOM is loaded and before the page contents are loaded:
$(document).ready(function() {
// jQuery code goes here
});
the window.onload event will fire when everything is loaded, including images etc.
You would want to check the DOM ready status if you wanted your js code to execute as early as possible, but you still need to access DOM elements.
You may want to use window.onload, as the docs indicate that it's not fired until both the DOM is ready and ALL of the other assets in the page (images, etc.) are loaded.
In modern browsers with modern javascript (>= 2015) you can add type="module" to your script tag, and everything inside that script will execute after whole page loads. e.g:
<script type="module">
alert("runs after") // Whole page loads before this line execute
</script>
<script>
alert("runs before")
</script>
also older browsers will understand nomodule attribute. Something like this:
<script nomodule>
alert("tuns after")
</script>
For more information you can visit javascript.info.
And here's a way to do it with PrototypeJS:
Event.observe(window, 'load', function(event) {
// Do stuff
});
The onload property of the GlobalEventHandlers mixin is an event
handler for the load event of a Window, XMLHttpRequest, element,
etc., which fires when the resource has loaded.
So basically javascript already has onload method on window which get executed which page fully loaded including images...
You can do something:
var spinner = true;
window.onload = function() {
//whatever you like to do now, for example hide the spinner in this case
spinner = false;
};
Completing the answers from #Matchu and #abSiddique.
This:
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
});
Is the same as this but using the onload event handler property:
window.onload = (event) => {
console.log('page is fully loaded');
};
Source:
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
Live example here:
https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event#live_example
If you need to use many onload use $(window).load instead (jQuery):
$(window).load(function() {
//code
});
2019 update: This is was the answer that worked for me. As I needed multiple ajax requests to fire and return data first to count the list items.
$(document).ajaxComplete(function(){
alert("Everything is ready now!");
});

Calling a Javascript function at the end of a 'setInterval'

Before posting this I've browsed some existing topics but couldn't get anything helpful, I tried some things to fix this but it failed.
I'm developing a website, and today I wanted to code a basic dark mode switch in Javascript :
<script type="text/javascript">
function switchWhite() {
document.getElementById("body").className = "";
document.getElementById("menubar").className = "navbar navbar-expand-lg navbar-light bg-light";
}
function switchDark() {
document.getElementById("body").className = "dark";
document.getElementById("menubar").className = "navbar navbar-expand-lg navbar-dark bg-dark";
}
function triggerSwitch() {
if ( document.getElementById("body").className.match("dark") ) {
switchWhite();
} else {
switchDark();
}
}
</script>
<button onclick="triggerSwitch()">Switch Mode</button>
This works just fine but there is an auto-refresh on the website, which is triggered every 30 seconds and which refreshes only specific blocs (like menubar) :
<script>
setInterval(function()
{
$(document).ready(function() {
$("#menubar_refresh").load(document.URL + " #menubar");
});
}, 30000);
</script>
Which also works fine, but I cannot mix these two features because once I switch to dark mode theme, after 30 seconds (when the auto-refresh is triggered), it gets back to light mode (the original state of the page).
Though is this normal, so I tried to put the dark mode back right after the bloc refreshes, like this :
<script>
setInterval(function()
{
$(document).ready(function() {
$("#menubar_refresh").load(document.URL + " #menubar");
});
switchDark(); // here
}, 30000);
</script>
It simply doesn't work, the bloc (and only this bloc, not the whole page) still gets back to the original state (light).
I've noticed that it switches to dark mode for a few milliseconds, and gets back to the original state.
I thought that the switchDark(); call is executed at first, even before the whole function finishes, in a way that the dark mode is set and then the bloc is refreshed.
So I tried setting a variable to block the execution of switchDark(); call before everything else finished executing, but the result is the same, which makes me think that my hypothesis is wrong.
Could you please help me to figure out what the problem is here ?
I can add more code snippets if you need them.
Thanks a lot
load() is asynchronous so you need to modify any new content in the complete callback.
Something like:
$("#menubar_refresh").load(document.URL + " #menubar", switchDark);
Or more verbose version:
$("#menubar_refresh").load(document.URL + " #menubar", function(){
// new content now exists
// add logic as to which theme method to call
if(isDark){
switchDark();
}
});
So, I'm in agreement with the answer by #charlietfl. But there is a flaw in your code due to misunderstanding and misinterpretation of javascript's event handler asynchronous nature.
The code in question is this:
<script>
setInterval(function() {
$(document).ready(function() {
$("#menubar_refresh").load(document.URL + " #menubar"); });
switchDark(); // here
},
30000);
</script>
You are using $(document).ready inadvertently as an if statement not as an event handler. Apparently, your code says after 30secs, if the document is ready, refresh the document and switch to a dark theme. But actually, your code means after 30secs, attach the ready state change handler to document. In this handler, asynchronously refresh the page and [immediately] switch to a dark theme.
Now, here lies your problem:
Though there is practically one, there is no 'absolute' guarantee that the document will be ready after 30secs. Consequently, your code setup isn't one that actually executes after 30secs.
There is no practical and absolute guarantee that the page will refresh completely before switchDark() executes. Why? The code for refreshing is asynchronous. Consequently, your switchDark() function almost never executes as you expect it to (though it always executes) since you expect it to use code from the newly loaded page.
A better and more meaningful code setup is to include setInterval inside $(document).ready handler and use a callback with the load() method for any code you want executed after the load() method.
<script>
$(document).ready(function() {
setInterval(function() {
$("#menubar_refresh").load(document.URL + " #menubar", function() {
switchDark(); // here
});
}, 30000);
});
</script>

Rails:-location.Href not working in project

I am a newbie on javascript and was implementing a loader in the project..
I have used the below code for the implementation of loader but it is not working:-
var url = "http://localhost:3500/#!/Movies";
<script>
$(function(){ //Loader implementation
if (location.href==url){
$(window).ready(function(){
$('#loadIndicator1').fadeOut(1000);
return false;
});
}
});
</script>
I am calling the loadindicator in the code as:-
<ul>
<li id="loadIndicator1" style="position:absolute ;top:50%;left:50%;z-index:99999;"></li>
</ul>
I am not very sure why this is giving an issue.I am using jquery-1.8.3.min.js and jqueryui-1.10.2.js
Also when I hover on location..I get unresolved variable location.Please help me with this.
use
if (window.location.href==url)
instead of
if (location.href==url)
var url = "http://localhost:3500/#!/Movies";
$(function(){
if (location.href==url){
$(window).load(function(){
$('#loadIndicator1').fadeIn(1000);
});
}
});
this will show your loader once the webpage is fully downloaded
use $('#loadIndicator1').fadeOut(1000); to hide the loader once the content is loaded.
Ignoring window ready, using only document ready
$(function() {
if (window.location.href === url){
// $(window).ready(function(){
$('#loadIndicator1').fadeOut(1000);
return false;
// });
}
});
You should remove the part I have commented out. The problem is, you attached an event handler to document ready, and if your are on a specific URL, you attach an event handler to window ready, but that event was already fired, and it won't be fired again.
Using window load after document ready
Another possible solution:
$(function() {
if (window.location.href === url){
$(window).load(function(){
$('#loadIndicator1').fadeOut(1000);
return false;
});
}
});
The window load event fires later, than document ready - though this should be tested.
Ignoring document ready, using only window load
Third time is a charm, another solution which may be the best, simply ignore the document ready event, and only use the window load:
$(window).load(function () {
if (window.location.href === url) {
$('#loadIndicator1').fadeOut(1000);
return false;
}
});
This case though the loader only appears if everything is loaded on the page, so maybe this is not what you want -- in this case use the first option.

jQuery on the bottom, wait execution script on <head> until it is loaded

I saw similar question here in SO, where someone wants to do the same thing. The different case is that I have this lightweight script that listens for event bubbling to the top of the document root that I intentionally want to put on the top of the page and I dont want to wrap it inside $(document).ready(). It looks something like this:
<html>
<head>
<script>
document.documentElement.onclick = function (e) {
//$.ajax call using jQuery. Possible that jQuery is not loaded when page is not completely loaded
}
</script>
</head>
And then near the bottom of the page I include jQuery like this:
<body>
<script src="./jQuery.js"></script>
</body>
</html>
As you can see on the <head> when I'm making an ajax call to somewhere using $.ajax, it's possible that jQuery is not yet loaded, so that it may throw $ is undefined error when someone clicks on something on DOM, and jQuery is not loaded yet. My workaround is probably to use settimeout hoping that jquery will be loaded sometime later and the code is working like this:
if (typeof $ === 'undefined'){
setTimeout(doAJAXJquery, 50);
}else{
$.ajax(//blablabla) //jQuery loaded and ready to use!!
}
But it's a really dirty hack. How am I supposed to know when jQuery is finished loading? that 50ms i put there is only an arbitrary value i made up myself. Of course it is still not gonna work if jquery hasn;t been loaded yet and it already passes 50ms.
Is there any better workaround so when jQuery is undefined, it is gonna retry sometime later again, or put a function that executes ajax inside some callback that gets executed when jQuery is ready? thanks.
what about
<head>
<script type="text/javascript">
var init = function(){
document.documentElement.onclick = function (e) {
//$.ajax call using jQuery. Possible that jQuery is not loaded when page is not completely loaded
}
}
</script>
</head>
<body>
<script src="./jQuery.js"></script>
<script type="text/javascript">
init();
</script>
</body>
If you want to execute the list of functions (or events 'fired') waiting for jQuery to load you could create your own 'ready' function :))
var runList = new Array(), timer = setInterval(function(){
if (typeof(jQuery) != 'undefined')
{
clearInterval(timer);
if (runList.length>0) for(var i in runList) runList[i]();
}
}, 50);
runList.push(function(){alert(1);});
runList.push(function(){alert(2);});
var jQuery = 1;

Categories

Resources