I am a little confused by the following block of code. I will comment next to each line what I think it means. If someone could help me clarify any misunderstandings I have or confirm that I am in fact interpreting it correctly, I would very much appreciate that.
Here is this code in context: http://jsfiddle.net/MddHtt13/EMBZr/1/
if(!window.onload) { // If the window is not loaded then...
window.onload = function() { //Assign an anonymous function to the onload event
onLoad(); //Which, upon execution of the onload event execute the onLoad function
};
}
else { //This is probably the most confusing part
var oldWindowLoadFunction = window.onload; //Else if the window is loaded, assign the onload event to the variable oldWindowLoadFunction
window.onload = function() { //Then upon completion of the onload event, assign an anonymous function
oldWindowLoadFunction(); //which then re-executes the onload event
onLoad(); //and then executes the onLoad function
};
}
The first thing I don't understand is the exclamation point next to window.onload
if(!window.onload)
Why would I need to specify if the window is not yet loaded? Wouldn't I only want to attach the onLoad() function to the onload event so that upon completion it fires? Say with something like:
window.onload = onLoad();
Why the extra steps? Why the if/else statement?
Secondly, why in the second half of the code block do I need to reload the page only to reattach the onLoad() function again? That sort of brings me back to what I just asked. Why does it have to be more complicated that simply writing:
window.onload = onLoad();
Ofcourse when I change the code to be a simple statement, like the one above, it doesn't actually work. However, I still don't completely understand the necessity of each part of the code block in question.
If someone could walk me through this in detail it would be extremely helpful.
Edit:
Thanks to the help of the folks below I replaced all of this code with one simple statement:
window.addEventListener('load', onLoad);
The ! is a boolean inversion: if not window.onload is null or undefined, or in plainer English, if the variable named onload in the object named window is not null or undefined.
The logic basically says, if there is no onload function install mine. If there is an onload function install a new wrapper function which calls the existing function and then calls mine.
None of the code "reloads" the page. You are confusing the assignment of the onload handler with loading the page.
What the function is doing is adding onload functionality to a window object which may already have onload functionality by chaining added function to the original, but only if that's necessary.
In today's world, it's all redundant, since you can just add an event listener to a list of functions to be executed for the onload event.
if (!window.onload)
This is checking to see if window.onload is not null or undefined. If window.onload is already defined elsewhere then you might not want to replace it with your onLoad() function.
Your block of code basically checks to see if window.onload is defined elsewhere. If it isn't, assign onLoad() to window.onload. If it does, execute the existing window.onload and then call your onLoad() function as well.
Related
I'm facing a weird issue. The console.log() outside the onload function works, but the console.log() inside doesn't work... Would it mean that my page never fully loads ? I had a look at the developer tools of Chrome and it shows me that the page is loaded, so I don't really understand... (here is a screen of the devtool)
Here is my code:
console.log("hello1");
window.onload = function()
{
console.log("hello2");
};
(I'm using this in a WordPress website, but I don't think it changes anything)
Thanks in advance,
ArbreMojo.
Some other code is probably assigning another function value to the window.onload method, so it basically overrides your assignment.
Instead of window.onload = function you can do:
window.addEventListener('load', function() {
console.log('loaded')
})
which allows attaching an arbitrary number of handlers for that event. This ensures nothing can override your callback function.
See: EventTarget.addEventListener for more info.
I have observed a strange behavior while learning jQuery and Javascript. When I call a variable that is defined inside the $(document).ready, from outside these tags it appears undefined, even when I define it as a global variable,
For example:
$(document).ready(function() {
myVar = "test";
});
alert(typeof(myVar));
//Results "undefined"
If I call the same variable inside the document.ready tags it works as expected
$(document).ready(function() {
myVar = "test";
alert(typeof(myVar));
//Results "String"
});
The result is same even after using window prefix.
$(document).ready(function() {
window.myVar = "test";
});
alert(typeof(window.myVar));
//Results "undefined"
I understand about the variable scopes but why even global variables aren't working this way. I am so confused.
The code inside the "ready" handler will not run until the DOM has been fully built. The code outside the handler will run as soon as it is encountered. Thus, your alert() runs before the code in the handler runs, so the outcome makes perfect sense: the global variable has not yet been initialized, so its value is undefined.
You can see the sequence of execution clearly by putting alert() (or, better, console.log()) calls inside the "ready" handler:
$(document).ready(function() {
console.log("In the 'ready' handler");
});
console.log("Outside the 'ready' handler");
When that runs, you'll see the "Outside" message logged first.
Because the alert() is executed before your document is perfectly ready.. You may try even by declaring the variable before $(document).ready() still it will return undefined..
The $(document).ready() gets fired after the page is fully loaded
When the script tag is fully loaded the alert gets executed.
So
Script tag is loaded => Execute alert
Continue loading page
Page completly loaded => fire $(document).ready
You var is getting set
The alert gets executed before your var is set
The other answers are correct but it is probably important to also note the $(document).ready(...) is also hiding your variable from the global scope. You could declare your variable then update it within the function
var myVar;
$(document).ready(function() {
myVar = "test";
});
console.log(myVar) // test
The execution plan it's like
//this statement shall fix the driver, not run it
$(document).ready(function() {//-->this it's an event handler waiting to be fired when content is fully loaded
myVar = "test";//-->myVar won't exists until this event is triggered
});
//this execute the alert function but myVar not exist yet
alert(typeof(myVar));
$(document).ready() is like to assign an event who will execute after the content is loaded, which means alert(myVar) will run before the lambda execution which was set as the content-loaded event. I hope you'll understand me.
Sorry if this may be deemed a slight duplicate, however I couldn't find an answer that helped me understand why myFunc() is firing on page load and not when I click el1 or el2. How can I make the following code behave as expected?
function myFunc(param){
//yadayada
}
el1.onclick = myFunc('string1');
el2.onclick = myFunc('string2');
Thanks.
document.getElementById('el1').onclick = function() { myFunc('string1'); };
document.getElementById('el2').onclick = function() { myFunc('string2'); };
You need to get the elements on the page first and then assign a function to them, otherwise the parser will execute them onload because it thinks that myFunc() is returning a value to be assigned to onclick as opposed to the actual function myFunc().
In the following code, the function writeMessage is called without parenthesis. However it works fine but Is it a correct way of function calling in javaScript or its better to use parenthesis along with writeMessage().
window.onload = writeMessage;
function writeMessage()
{
document.write("Hello World");
}
window.onload = writeMessage; is not a call - it's an assignment. You assign the writeMessage function as the onload field of the window object. The actual call is performed (internally) as window.onload() which is equivalent to writeMessage() in your case.
In the following code, the function writeMessage is called without parenthesis.
Actually, it isn't. The code
window.onload = writeMessage;
does not call the function. It assigns the function to the onload property of window. Part of the process of loading the page in browsers is to fire the function assigned to that property (if any) once the loading process is complete.
If you wrote
window.onload = writeMessage();
what you'd be doing is calling writeMessage and assigning the result of the call to window.onload, just like x = foo();.
Note that the code you've actually quoted, which executes a document.write when the page loads, will wipe out the page that just loaded and replace it with the text "Hello world", because when you call document.write after the page load is complete, it implies document.open, which clears the page. (Try it here; source code here.) In modern web pages and apps, you almost never use document.write, but in the rare cases where you do, it must be in code that runs as the page is being loaded (e.g., not later).
the () is used to EXECUTE the function
when you write
window.onload = writeMessage;
you actually set a delegate ( pointer to a function to be executed) for which - when the onload event will occour.
That's correct already.
You don't need parenthesis because you're just storing the function in window.onload, not calling it yourself.
I'm experiencing difficulties trying to invoke document.ready( function() {}) in my unit tests. Suppose I have multiple of them in my javascript file, and one of them called inside a named function i.e.
function myFunction() {
$(document).ready(function() {
//...
});
}
How do I actually invoke them in my unit tests so I can actually test them? I'm using JsTestDriver to unit test my javascripts.
Thanks.
If it's a unit test, I'm guessing you check the function outputs when given certain inputs?
Here's my opinion:
You should prepare for the case where document.ready is called and the case where it isn't.
So your unit test should run each function twice - once to simulate a pre-ready call and one to simulate a post-ready call. That is, you should have one run-through where anything that happens on document.ready DOES run, and one run-through where it's just ignored (presumably to be called later on in the lifecycle).
EDIT:
Just reread the question and understood it a bit more. You could just override $(document).ready to do what you want it to (which is NOT to wait for the DOMLoaded event to fire, but instead to run the functions immediately). This snippet will replace the $(document).ready function with a function that does exactly that. It should run before any unit tests.
var postReady = true; // or false to ignore the function calls.
jQuery.fn.ready = function(fn)
{
if(postReady && fn) fn();
}
Example test case:
<html><head><title>whatever</title>
<script type="text/javascript" src="/JS/jquery-1.3.2.js"></script>
<script type="text/javascript">
var postReady = true; // or false to ignore the function calls.
jQuery.fn.ready = function(fn)
{
alert("We stole ready!");
if(postReady && fn) fn();
}
$(document).ready(function()
{
alert("The function is called.");
});
</script>
</head><body></body>
</html>
You know document.ready... works so just start with calling the functions within it. Ideally, if you just have an init function called by the ready function then you call one function, it does what you need, and you can continue with your tests.
You can take unit testing too far, in this case you need to ask yourself what you are testing, and why. The JQuery document.ready function works, and work well (you know this because it's been tested by many many people).
I would assume the trick would be to, instead of creating an anonymous function, naming one, and using it.
//So instead of this...
$(document).ready(function() {...});
//Do the following
$(document).ready(my_function);
Then you just test my_function and make sure that it is working. Make sure that you test the functions in the order their going to be loaded for an accurate test.
I suggest you to refactor the code. Even if you find a way to call it, it will be hard to understand for other developers.
Also (IMHO, I am not quite sure) you have to call the ready handlers even after the pages ready event was triggered, because if you "install" the ready() handler, if the document.ready event was already trigger, jquery calls that handler immediately (so it never loses that event, even if your code added a handler too late - that is, way after document.ready was still done).
Couldn't you just create a user my_on_read() event ? Or something the like?
Well, in the end, please just take care of ready() events and handlers that will be installed after the document.ready() is already done :)
Part of the answer to this question can be found here.
Below is the sample code to answer this question based on the above answer:
myFunction();
$.readyList[1]();
The index assumes that there is only 1 document.ready function in the source file. Index 0 refers to something else which I believe is info on the browser.