On a page eg .../something/jonas.dk there is a button when clicked goes to .../something/frank.dk but the page doesn't reload. I am trying to run a javascript code on .../something/frank.dk
if (window.location.href.indexOf("frank") != -1) {
(function () {
//Check ready state
function ready() {
console.info("DOM loaded");
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", ready);
} else {
ready();
}
// my code goes here
setTimeout(run, 1000);
ready();
})();
}
The code works fine when I manually reload the page, but how do I get the code to execute when the url changes?
(I only work with vanilla javascript 'cos we don't use jQuery at my job.)
I am using ipinfo.io to detect the visitors country and then reload the page with an appended querystring based on that. When the page loads I would like to do something after DOMContentLoaded.
DOMContentLoaded is called fine if I don't reload the page, but I would like it to work with the reload. How do I achieve that?
Sample code below:
jQuery.getJSON('https://ipinfo.io', function(data){
if(data){
if(data.country){
if(data.country.toLowerCase()=='us')
{
window.location.replace(window.location.href+"?location=us");
}
}
}
});
//works when page is not reloaded
document.addEventListener("DOMContentLoaded",
function() {
doSomething...
});
You have a race condition here: based on your description it is likely that the getJSON command is "racing" with the DOMContentLoaded event. If getJSON is successful before your DOM is ready, then it will redirect the page and stop all script execution on the page.
To avoid that, try moving getJSON into the DOMContentLoaded callback.
document.addEventListener("DOMContentLoaded", function() {
jQuery.getJSON('https://ipinfo.io', function(data) {
if (data) {
if (data.country) {
if (data.country.toLowerCase() == 'us') {
window.location.replace(window.location.href + "?location=us");
}
}
}
});
// Other logic here
});
On a side note, you can avoid triple nesting by combining the three if statements (and remember to use strict comparison whenever possible, ===):
jQuery.getJSON('https://ipinfo.io', function(data) {
if (data && data.country && data.country.toLowerCase() === 'us') {
window.location.replace(window.location.href + "?location=us");
}
}
I am using PhantomJS to take a screenshot of a page every five minutes, and it works correctly most of the time. The problem is that sometimes the page I am taking a screenshot of fails to load the AngularJS library, and then, it can't build the page after that. So I am trying to figure out how to load a local copy in its place. Here is what I have been trying...
var page = require('webpage').create(),system = require('system');
var home = 'https://smartway.tn.gov/traffic/';
page.open(home, function (status) {
if(status === "success"){
page.injectJs('angular.js');
window.setTimeout((function() {
page.evaluate(function () {
/*stuff*/
});
}), 2000);
}
});
So angular.js is the name of my local copy of what the site would normally download. The site calls the script at the end of the body with several other scripts, and I am trying to find the best way to include it. I am wondering if it needs to be included by replacing the script tag in the html so it can be loaded in sequence, but I am not sure how to do that.
Thanks
It is problematic to reload a single JavaScript file when it failed, particularly when it is the framework. There are probably many scripts which depend on it. When the core framework is not loaded, those scripts will stop executing, because the angular reference cannot be resolved.
You could inject a local version of angular, but then you would have to go over all the other scripts which reference angular and "reload" them by either downloading and evaling them in order or putting them into the page as script elements. I advise against it, because it is probably very error prone.
You should just reload the page if angular does not exist after page load (callback of page.open). Since the same problem may occurr during reload, this has to be done recursively:
function open(countDown, done){
if (countDown === 0) {
done("ERROR: not loaded");
return;
}
page.open(home, function (status) {
if(status === "success"){
var angularExists = page.evaluate(function () {
return !!angular;
});
if (angularExists){
done();
} else {
open(countDown - 1, done);
}
} else {
open(countDown - 1, done);
}
});
}
open(5, function(err){
if(err) {
console.log(err);
} else {
page.render(target);
}
});
You can also try the page.reload() function instead of a page.open().
The other possiblity is to always inject the local version when the page loading began and stop any request for the remote version of the script:
page.onLoadStarted = function() {
page.injectJs('angular.js');
};
page.onResourceRequested = function(requestData, networkRequest) {
var match = requestData.url.match(/angular\.min\.js/g);
if (match != null) {
networkRequest.abort();
}
};
page.open(home, function (status) {
if(status === "success"){
window.setTimeout((function() {
page.evaluate(function () {
/*stuff*/
});
}), 2000);
}
});
This version works entirely without reloading.
I want to fire and event when the DOM has completely loaded. I checked out document.readyState but it's not an event. I want to fire it when the readyState is complete. How do I do that?
Some easy googling point me to this code:
// alternative to DOMContentLoaded
document.onreadystatechange = function () {
if (document.readyState == "complete") {
initApplication();
}
}
And to this link
Handle the window.load event.
This will only fire when all external resources (including images) have loaded.
Taken from another post, however, you could do it like this:
var alreadyrunflag = 0; //flag to indicate whether target function has already been run
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function() {
alreadyrunflag = 1;
// perform what you need to
}, false);
} else if (document.all && !window.opera) {
var contentloadtag = document.getElementById("contentloadtag");
contentloadtag.onreadystatechange = function() {
if (this.readyState == "complete") {
alreadyrunflag = 1;
// perform what you need to
}
}
}
//fallback
window.onload = function() {
setTimeout(function() {
if (!alreadyrunflag) {
// perform what you need to
}
}, 0);
}
This checks that the DOM is fully loaded, however, if it isn't, it falls back to onload. You can obviously manipulate this though.
Also, if JQuery is an option, you can achieve the same effect by using just one simple function:
$(document).ready(function() {
// Handler for .ready() called.
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js"></script>
You can do it like this:
function startupApplication(anyFunction) {
document.onreadystatechange = function () {
document.onreadystatechange = () =>
document.readyState === "complete" ? anyFunction() : undefined;
};
}
startupApplication(() => {
// Put your code here ...
});
See my FiddleJS with comments and logs for education purposes: click here
For anyone already using the jQuery library the ready function can be used to handle this.
Otherwise the solution from #Neal will achieve the same functionality without needing to add an additional dependency.
What is the non-jQuery equivalent of $(document).ready()?
This works perfectly, from ECMA. The snippet is all you need, but if you want to dig more and explore other options check this detailed explanation.
document.addEventListener("DOMContentLoaded", function() {
// code...
});
The window.onload doesn't equal to JQuery $(document).ready because $(document).ready waits only to the DOM tree while window.onload check all elements including external assets and images.
EDIT: Added IE8 and older equivalent, thanks to Jan Derk's observation. You may read the source of this code on MDN:
// alternative to DOMContentLoaded
document.onreadystatechange = function () {
if (document.readyState == "interactive") {
// Initialize your application or run some code.
}
}
There are other options apart from "interactive". See the MDN docs for details.
Now that it's 2018 here's a quick and simple method.
This will add an event listener, but if it already fired we'll check that the dom is in a ready state or that it's complete. This can fire before or after sub-resources have finished loading (images, stylesheets, frames, etc).
function domReady(fn) {
// If we're early to the party
document.addEventListener("DOMContentLoaded", fn);
// If late; I mean on time.
if (document.readyState === "interactive" || document.readyState === "complete" ) {
fn();
}
}
domReady(() => console.log("DOM is ready, come and get it!"));
Additional Readings
https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Checking whether loading is already complete
https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Update
Here's some quick utility helpers using standard ES6 Import & Export I wrote that include TypeScript as well. Maybe I can get around to making these a quick library that can be installed into projects as a dependency.
JavaScript
export const domReady = (callBack) => {
if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', callBack);
}
else {
callBack();
}
}
export const windowReady = (callBack) => {
if (document.readyState === 'complete') {
callBack();
}
else {
window.addEventListener('load', callBack);
}
}
TypeScript
export const domReady = (callBack: () => void) => {
if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', callBack);
}
else {
callBack();
}
}
export const windowReady = (callBack: () => void) => {
if (document.readyState === 'complete') {
callBack();
}
else {
window.addEventListener('load', callBack);
}
}
Promises
export const domReady = new Promise(resolve => {
if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', resolve);
}
else {
resolve();
}
});
export const windowReady = new Promise(resolve => {
if (document.readyState === 'complete') {
resolve();
}
else {
window.addEventListener('load', resolve);
}
});
A little thing I put together
domready.js
(function(exports, d) {
function domReady(fn, context) {
function onReady(event) {
d.removeEventListener("DOMContentLoaded", onReady);
fn.call(context || exports, event);
}
function onReadyIe(event) {
if (d.readyState === "complete") {
d.detachEvent("onreadystatechange", onReadyIe);
fn.call(context || exports, event);
}
}
d.addEventListener && d.addEventListener("DOMContentLoaded", onReady) ||
d.attachEvent && d.attachEvent("onreadystatechange", onReadyIe);
}
exports.domReady = domReady;
})(window, document);
How to use it
<script src="domready.js"></script>
<script>
domReady(function(event) {
alert("dom is ready!");
});
</script>
You can also change the context in which the callback runs by passing a second argument
function init(event) {
alert("check the console");
this.log(event);
}
domReady(init, console);
There is a standards based replacement
DOMContentLoaded that is supported by over 90%+ of browsers, but not
IE8 (So below code use by JQuery for browser support)
document.addEventListener("DOMContentLoaded", function(event) {
//do work
});
jQuery's native function is much more complicated than just window.onload, as depicted below.
function bindReady(){
if ( readyBound ) return;
readyBound = true;
// Mozilla, Opera and webkit nightlies currently support this event
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", function(){
document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
jQuery.ready();
}, false );
// If IE event model is used
} else if ( document.attachEvent ) {
// ensure firing before onload,
// maybe late but safe also for iframes
document.attachEvent("onreadystatechange", function(){
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", arguments.callee );
jQuery.ready();
}
});
// If IE and not an iframe
// continually check to see if the document is ready
if ( document.documentElement.doScroll && window == window.top ) (function(){
if ( jQuery.isReady ) return;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
// and execute any waiting functions
jQuery.ready();
})();
}
// A fallback to window.onload, that will always work
jQuery.event.add( window, "load", jQuery.ready );
}
According to http://youmightnotneedjquery.com/#ready a nice replacement that still works with IE8 is
function ready(fn) {
if (document.readyState != 'loading') {
fn();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', fn);
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState != 'loading')
fn();
});
}
}
// test
window.ready(function() {
alert('it works');
});
improvements: Personally I would also check if the type of fn is a function.
And as #elliottregan suggested remove the event listener after use.
function ready(fn) {
if (typeof fn !== 'function') {
throw new Error('Argument passed to ready should be a function');
}
if (document.readyState != 'loading') {
fn();
} else if (document.addEventListener) {
document.addEventListener('DOMContentLoaded', fn, {
once: true // A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
});
} else {
document.attachEvent('onreadystatechange', function() {
if (document.readyState != 'loading')
fn();
});
}
}
// tests
try {
window.ready(5);
} catch (ex) {
console.log(ex.message);
}
window.ready(function() {
alert('it works');
});
The reason I answer this question late is because I was searching for this answer but could not find it here. And I think this is the best solution.
This does not answer the question nor does it show any non-jQuery code. See # sospedra's answer below.
The nice thing about $(document).ready() is that it fires before window.onload. The load function waits until everything is loaded, including external assets and images. $(document).ready, however, fires when the DOM tree is complete and can be manipulated. If you want to acheive DOM ready, without jQuery, you might check into this library. Someone extracted just the ready part from jQuery. Its nice and small and you might find it useful:
domready at Google Code
The easiest way in recent browsers would be to use the appropriate GlobalEventHandlers, onDOMContentLoaded, onload, onloadeddata (...)
onDOMContentLoaded = (function(){ console.log("DOM ready!") })()
onload = (function(){ console.log("Page fully loaded!") })()
onloadeddata = (function(){ console.log("Data loaded!") })()
The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
The function used is an IIFE, very useful on this case, as it trigger itself when ready:
https://en.wikipedia.org/wiki/Immediately-invoked_function_expression
It is obviously more appropriate to place it at the end of any scripts.
In ES6, we can also write it as an arrow function:
onload = (() => { console.log("ES6 page fully loaded!") })()
The best is to use the DOM elements, we can wait for any variable to be ready, that trigger an arrowed IIFE.
The behavior will be the same, but with less memory impact.
footer = (() => { console.log("Footer loaded!") })()
<div id="footer">
In plain vanilla JavaScript, with no libraries? It's an error. $ is simply an identifier, and is undefined unless you define it.
jQuery defines $ as it's own "everything object" (also known as jQuery so you can use it without conflicting with other libraries). If you're not using jQuery (or some other library that defines it), then $ will not be defined.
Or are you asking what the equivalent is in plain JavaScript? In that case, you probably want window.onload, which isn't exactly equivalent, but is the quickest and easiest way to get close to the same effect in vanilla JavaScript.
The body onLoad could be an alternative too:
<html>
<head><title>Body onLoad Exmaple</title>
<script type="text/javascript">
function window_onload() {
//do something
}
</script>
</head>
<body onLoad="window_onload()">
</body>
</html>