Execute javascript after page load is complete [duplicate] - javascript

This question already has answers here:
How to make JavaScript execute after page load?
(25 answers)
Closed 2 years ago.
I have an html page with some pre-rendered content and some yet un-rendered content. I want to display the pre-rendered content immediately, and then begin rendering the rest of the content. I am not using jQuery.
See the following snippet. I have tried this various ways, including injecting my script before the closing body tag and providing my script to populate the DOM as a callback to window.onload, document.body.onload, and document.addEventListener('DOMContentLoaded'). In every case, the page does not display the pre-rendered content until the rest of the content is rendered.
<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
for (var i = 0; i < 500; i++)
main.innerText += new Date();
</script>
</body>
</html>
<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
document.body.onload = function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
};
</script>
</body>
</html>
<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
window.onload = function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
};
</script>
</body>
</html>
<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
document.addEventListener('DOMContentLoaded', function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
});
</script>
</body>
</html>
One case that has worked is window.setTimeout with 0 timeout. However, this simply defers the function until there is nothing left to do. Is this the best practice, here?
<html><head></head>
<body>
<header>What it is, my doge?</header>
<div id="main"></div>
<script>
var main = document.getElementById('main');
window.setTimeout(function() {
for (var i = 0; i < 500; i++)
main.innerText += new Date();
}, 0);
</script>
</body>
</html>

In terms of a best practice, there isn't one. In terms of a good, common, and acceptable practices, there are a handful. You've hit one:
setTimeout(function() { }, 1);
In this case, the function is executed within the browser's minimum timeout period after all other in-line processing ends.
Similarly, if you want to ensure your function runs shortly after some condition is true, use an interval:
var readyCheck = setInterval(function() {
if (readyCondition) {
/* do stuff */
clearInterval(readyCheck);
}
}, 1);
I've been using a similar, but more generalized solution in my own work. I define a helper function in the header:
var upon = function(test, fn) {
if (typeof(test) == 'function' && test()) {
fn();
} else if (typeof(test) == 'string' && window[test]) {
fn();
} else {
setTimeout(function() { upon(test, fn); }, 50);
}
}; // upon()
... and I trigger other functionality when dependencies are resolved:
upon(function() { return MyNS.Thingy; }, function() {
// stuff that depends on MyNS.Thingy
});
upon(function() { return document.readyState == 'complete';}, function() {
// stuff that depends on a fully rendered document
});
Or, if you want a more authoritative good practice, follow Google's example. Create an external async script and inject it before your first header script:
var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true;
s.src = '/path/to/script.js';
var header_scripts = document.getElementsByTagName('script')[0];
header_scripts.parentNode.insertBefore(s, header_scripts);
Google's solution theoretically works on all browsers (IE < 10?) to get an external script executing as soon as possible without interfering with document loading.
If you want an authoritative common practice, check the source for jQuery's onready solution.

Depending on your browser requirements you can use the async tag and import your script after content loads. This probably accomplishes the same thing as setTimeout(func, 0), but perhaps it's a little less hacky.
See http://plnkr.co/edit/7DlNWNHnyX5s6UE8AFiU?p=preview
html:
...
<body>
<h1 id="main">Hello Plunker!</h1>
<script async src="script.js"></script>
</body>
...
script.js:
for(var i=0; i<500; ++i) {
document.getElementById('main').innerText += new Date();
}

I've used this to effect before:
var everythingLoaded = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
clearInterval(everythingLoaded);
init(); // this is the function that gets called when everything is loaded
}
}, 10);

I think what you want to do is use an onload event on the tag.
This way first the "What it is, my doge?" message will appear while the javascript is processed.
I also set a timeout inside the loop, so you can see better the lines being added.
<html>
<head>
<script>
myFunction = function() {
for (var i = 1000; i > 0; i--) {
setTimeout(function() {
main.innerText += new Date();
}, 100);
}
};
</script>
</head>
<body onload="myFunction()">
<header>What it is, my doge?</header>
<div id="main"></div>
</body>
</html>

Related

How to call a function in external script file from HTML

I'm trying to call a javascript function in my HTML index file and I can't get it to work.
This is my html file that I'm trying to call a function from.
<div class="main">
<h1 class="header-main" onload="HeaderTyper('Welcome', this)">
<noscript>no javascript</noscript>
</h1>
</div>
<script type="text/javascript" src="script.js"></script>
And this is the script.
function HeaderTyper(message, element){
var i = 0;
var speed = 50;
if (i < message.length) {
element.innerHTML += message.charAt(i);
//play keystroke sound
i++;
setTimeout(HeaderTyper, speed);
}
}
I'm trying to get a typewriter effect style header. I'm planning to add some keystroke sounds, but first I need to figure out how to actually type it out in the header tag. The code won't type out the message I'm passing in argument. What did I do wrong ? Thank you for any help.
After the HTML page ends (As #johannchopin explained), import the file and then add an event listener (as #aaronburrows explained).
<body>
<div class="main">
<h1 class="header-main">
<noscript>no javascript</noscript>
</h1>
</div>
</body>
</html>
<script type="text/javascript" src="script.js"></script>
<script>
let h1 = document.querySelector('.header-main');
h1.addEventListener('load', HeaderTyper("Welcome", h1, false));
</script>
Also, I fixed the function, it was missing the parameters.
function HeaderTyper(message, element, i) {
var speed = 50;
if (i < message.length) {
console.log(message.charAt(i))
element.innerHTML += message.charAt(i);
//play keystroke sound
setTimeout(function(){ HeaderTyper(message,element,++i)}, speed);
}
}
You're attempting to bind a function call before it is loaded into the browser. Remove the onload from the HTML and add an event listener to the script.
According to this solution, The onload event can only be used on the document(body) itself. Best way to achieve this is to call the function in a <script> tag just before the </body> closing tag:
<div class="main">
<h1 class="header-main">
<noscript>no javascript</noscript>
</h1>
</div>
<script>
function HeaderTyper(message) {
var i = 0;
var speed = 50;
var element = document.querySelector('.header-main');
if (i < message.length) {
element.innerHTML += message.charAt(i);
//play keystroke sound
i++;
setTimeout(HeaderTyper, speed);
}
}
HeaderTyper('Welcome');
</script>
Ok, hi there.
function HeaderTyper(message, element){
alert('script loaded') //<---
var i = 0;
I put this line at the beginning of the script to make sure it works. And it's not.
Why?
Because you just made your function but doesn't call it.
First way to solve this - put ur function in the "script" of HTML doc. And call it after, like
<script>
function HeaderTyper(message) {
let i = 0
let speed = 50
let element = document.querySelector('.header-main')
if (i < message.length) {
element.innerHTML += message.charAt(i)
i += 1
setTimeout(HeaderTyper, speed)
}
}
HeaderTyper('Welcome') //<---
</script>
Second way - put HeaderTyper() at the end of script.js file, so the function start, but you need to make a link for "message" and "element".
setTimeout(HeaderTyper, speed);
}
}
HeaderTyper(someMessage, someElement) //<---

Problem with local progress bar code while it works properly on CodePen? [duplicate]

I'm trying to run a simple few lines of code using an index.html file and a script.js file, nothing else.
In the HTML file, I have doctype html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="javascript/script.js"></script>
</head>
<body>
<div id="content1">This is content 1 </div>
<div id="content2">This is content 2 </div>
<div id="content3">This is content 3 </div>
</body>
</html>
And for my javascript section i have:
var elems = $("div");
if (elems.length) {
var keep = Math.floor(Math.random() * elems.length);
for (var i = 0; i < elems.length; ++i) {
if (i !== keep) {
$(elems[i]).hide();
}
}
}
When I run this in CodePen, or even on the code editor on this website, it works fine. But it doesn't work when I use the files on my desktop (index.html, script.js I do believe the folder structure is correct (script.js is in the javascript folder.)
Thank you all
Move your script tag just before the closing of the body tag:
<script src="javascript/script.js"></script>
</body>
This way the DOM will be available when your script runs.
If you prefer to keep your script in the head part, then wrap your code in a DOMContentLoaded event handler:
document.addEventListener("DOMContentLoaded", function() {
var elems = $("div");
if (elems.length) {
var keep = Math.floor(Math.random() * elems.length);
for (var i = 0; i < elems.length; ++i) {
if (i !== keep) {
$(elems[i]).hide();
}
}
}
});
... so to have your code run when the DOM is ready.
You did not tag your question with jquery, but as you seem to use it, you can use this shorter code for doing essentially the same as above:
$(function() {
var $elems = $("div").hide(),
$elems.eq(Math.floor(Math.random() * $elems.length)).show();
});
wrap your code in this function to execute it if the document is ready.
$(document).ready(function (){
// your code goes here
});

Code works in Codepen, but not with my desktop files

I'm trying to run a simple few lines of code using an index.html file and a script.js file, nothing else.
In the HTML file, I have doctype html:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="javascript/script.js"></script>
</head>
<body>
<div id="content1">This is content 1 </div>
<div id="content2">This is content 2 </div>
<div id="content3">This is content 3 </div>
</body>
</html>
And for my javascript section i have:
var elems = $("div");
if (elems.length) {
var keep = Math.floor(Math.random() * elems.length);
for (var i = 0; i < elems.length; ++i) {
if (i !== keep) {
$(elems[i]).hide();
}
}
}
When I run this in CodePen, or even on the code editor on this website, it works fine. But it doesn't work when I use the files on my desktop (index.html, script.js I do believe the folder structure is correct (script.js is in the javascript folder.)
Thank you all
Move your script tag just before the closing of the body tag:
<script src="javascript/script.js"></script>
</body>
This way the DOM will be available when your script runs.
If you prefer to keep your script in the head part, then wrap your code in a DOMContentLoaded event handler:
document.addEventListener("DOMContentLoaded", function() {
var elems = $("div");
if (elems.length) {
var keep = Math.floor(Math.random() * elems.length);
for (var i = 0; i < elems.length; ++i) {
if (i !== keep) {
$(elems[i]).hide();
}
}
}
});
... so to have your code run when the DOM is ready.
You did not tag your question with jquery, but as you seem to use it, you can use this shorter code for doing essentially the same as above:
$(function() {
var $elems = $("div").hide(),
$elems.eq(Math.floor(Math.random() * $elems.length)).show();
});
wrap your code in this function to execute it if the document is ready.
$(document).ready(function (){
// your code goes here
});

Cordova SQLite plugin only works on first call

I have a cordova app with two pages, the first has a search field and the second displays the results of the first.
The displayResults function
function displayResults(){
var query = localStorage.getItem('search');
var db = window.sqlitePlugin.openDatabase({name:"Store-DB", location: 1});
queryDB(db,query);
}
function queryDB(db,query){
db.transaction(function(tx) {
var queryList = query.split(" ");
var sqlText = "SELECT * FROM DB WHERE item LIKE '%"+queryList[0]+"%'";
for (i = 1; i < queryList.length; i++) {
sqlText += " OR item LIKE '%"+queryList[i]+"%'";
}
tx.executeSql(sqlText, [], querySuccess);
}
);
}
function querySuccess(tx,results) {
var i;
var len = results.rows.length;
//Iterate through the results
for (i = 0; i < len; i++) {
console.log(row);
//Get the current row
var row = results.rows.item(i);
var div = document.createElement("div");
div.style.background = "gray";
div.style.color = "white";
div.innerHTML = row;
document.body.appendChild(div);
}
alert("Finished");
}
Here is the code for the second page:
<link rel="stylesheet" type="text/css" href="css/default.css">
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script src="js/zepto.js" type="text/javascript"></script>
<script src="plugins/com.brodysoft.sqlitePlugin/www/SQLitePlugin.js" type="text/javascript"></script>
<script src="js/code.js" type="text/javascript"></script>
<script type="text/javascript">
function onLoad(){
document.addEventListener("deviceready", onDeviceReady(), false);
}
function onDeviceReady(){
displayResults();
}
</script>
</head>
<body onload="onLoad()">
<div id="taskbar">
Home
<a id="username" class="toolbar_item" style="float:right;" href="#"></a>
</div>
The first time you load this page displayResults works just fine, but if you click the link back to the main page and load the second page again the console prints the error ReferenceError: no "undefined" has no property "openDatabase" in other words, the SQLite plugin isn't loading. But, if I make displayResults fire on a button press instead of onload it works every time. What is the explanation for this peculiar behavior?
It seems that sometimes deviceready-event is either not fired at all or fired too early when there are more event handlers of different libraries in place. The second problem caused that the brodysoft-plugin is not loaded properly and assign to the window-object as window.sqlitePlugin property because one event handler dispatched deviceready-event too early. It turned out setTimeout was the answer as it had been here
You can use the onpageshow event for example
$('#idofyourpage').bind("onpageshow",function(){
//Do something
});

Switch content of DIV with another set DIVs with a timer

I have 3 divs in a html page, 2 divs should be hiddent always but theire content should be displayed in another div and this content should be changed every x seconds. Hows that possible using jquery/javascript?
<div id="contentA">
<!-- Some contents goes here, and it should be hidden -->
</div>
<div id="contentB">
<!-- Some contents goes here, and it should be hidden -->
</div>
<div id="displayArea">
<!-- switch between contentA and contentB on a timer say every 5 seconds -->
</div>
Do not use the .html() function to copy content from one place to another. HTML is a serialisation format designed to carry DOM structures from a server to a client. Once the page is in a DOM structure you should manipulate that DOM structure directly using DOM methods. Using .html() to serialise a DOM node and then recreate it somewhere else risks losing things like event handlers, other hidden data, etc.
On that basis, to copy the current contents of a div into another:
var $contents = $('#contentA').contents().clone(); // copy the source element's contents
$('#displayArea').empty().append($contents); // drop them into the destination
In full:
(function() {
var delay = 3000;
var state = 0;
(function next() {
state = 1 - state;
var src = state ? '#contentA' : '#contentB';
var $contents = $(src).contents().clone();
$('#displayArea').empty().append($contents);
setTimeout(next, delay);
})();
})();
Try this :)
<div id='a' style='display: none;'>this is a</div>
<div id='b' style='display: none;'>this is b</div>
<div id='show'></div>
<script>
$(document).ready(function(){
var count = 0;
var content = '';
var j = setInterval(function () {
count++;
if(count%2===0){
content = $('#a').html();
}else{
content = $('#b').html();
}
$('#show').html(content);
}, 5000);
});
</script>
Try this:
var toggle = false;
$("#displayArea").html($("#contentA").html());
setInterval(function() {
$("#displayArea").html(toggle ? $("#contentA").html() : $("#contentB").html());
toggle = !toggle;
}, 5000);
Working DEMO
I don't know if this is what you need but this script should work:
check = true;
$(document).ready(function(){
setInterval(function(){
if(check) {
check = false;
$('#displayArea').html("a");
}
else {
check = true
$('#displayArea').html("b");
}
}, 5000);
});
function doSlides() {
var msg = messages.shift();
messages.push(msg);
$('#displayArea').html(msg);
};
var messages = [
$('#contentA').find('p').html(),
$('#contentB').find('p').html()
];
Demo:
http://jsfiddle.net/8Ux3L/
Here's one way to do it using setInterval():
var divs = $('div[id^="content"]').hide(),
i = 0;
function cycle() {
$("#displayArea").html(divs.eq(i).html());
i = ++i % divs.length; // increment i, and reset to 0 when it equals divs.length
}
setInterval(cycle, 2000); //Cycle every 2 seconds
Wrapping in a self executing function:
(function cycle() {
$("#displayArea").html(divs.eq(i).html());
i = ++i % divs.length; // increment i, and reset to 0 when it equals divs.length
setTimeout(cycle, 2000);
})();
DEMO
Try following code
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" ></script>
<script>
var divSelected = "A";
function switch1()
{
if (divSelected == "A")
{
$("#displayArea").text($("#contentA").text());
divSelected = "B";
}
else
{
$("#displayArea").text($("#contentB").text());
divSelected = "A";
}
}
$(document).ready(function()
{
var test = setInterval( "switch1()" , 5000);
});
</script>
</head>
<body>
<div id="contentA" style = "display:none;">
Contect A
</div>
<div id="contentB" style = "display:none;">
Content B
</div>
<div id="displayArea">
</div>
</body>
</html>
Use an interval to trigger a function every x seconds, then jQuery replaceWith to swap the divs. If you don't want to replace the actual node but just the contents, then .html() is probably the way to go.

Categories

Resources