Why does the location of $(document).ready() matter? - javascript

I thought that script within $(document).ready(...) would always execute after the DOM is loaded. Hence, it wouldn't matter if a $(document.ready(...) went in the head or in the body. However, the code below does not generate "apples" on the screen like I want it to. If I locate the giveApples() function at the bottom of the page though, it works.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(document).ready(giveApples());
function giveApples() {
$("#appleTree").html("apples");
}
</script>
</head>
<body>
<div id="appleTree"></div>
</body>
<script>
//$(document).ready(giveApples());
</script>
</html>
Can anyone please correct my misconceptions about DOM, page loading, Script-tag location, (document).ready(), or anything else that is causing this problem? I'm still quite new to web programming.

That's because you're not actually binding an event handler to the ready event. You're calling giveApples right away and passing its return value (undefined) as event handler to bind (which silently fails). You need to pass the function to .ready(), not call it!
$(document).ready(giveApples);
Note the missing parentheses.

And it does not. The problem is that you're not passing giveApples as argument, but its returned value, since you are calling it (because of the ()). To make it work, don't put the parenthesis:
$(document).ready(giveApples);
By your current code, the value that is being passed to $(document).ready is undefined, since giveApples doesn't return any value.
You could also do:
$(document).ready(function(){
giveApples(); //However, if you access the 'this' keyword inside the giveApples function, it will point to 'window', and not 'document'
});
You can see what I explained above if you alert these two values:
alert(giveApples); //Shows the giveApples function body, properly
alert(giveApples()); //Shows undefined, since giveApples is being called and does not return any value
Its the same when you use DOM events (onload, onclick, etc). You do this way:
window.onload = myFunction;
And not:
window.onload = myFunction();

You're missing a function
With this syntax:
$(document).ready(giveApples());
you are passing the result of giveApples as the code to be executed at document ready. Also, at the time it is called, this function isn't declared yet.
Correct syntax
This would work:
$(document).ready(function() {
giveApples();
});
As would:
$(document).ready(giveApples);

To answer your titular question since others have identified the source of your problem with the code which is not related to the position of document.ready()...
It doesn't really matter. It is just a standard convention that a lot of people follow.
A lot of people are also proponents of putting the <script> tag as the last element in the <body> tag also.
Proof: See? It's controversial. I even got a downvote. =)

You can put the srcipt wherever you want to put it.The html will execute from up to down.Yes,$(document).ready(...) would always execute after the DOM is loaded.But in your code,you have put the Function outside the $(document).ready.That means it will execute when DOM is loading.Maybe you can do like this:$(document).ready(function giveApples(){$("#appleTree").html("apples");}).
If you want to learn JQuery,I will give you a link and I am new,too.It's very amazing.So have fun.
30-days-to-learn-jquery
w3school

Related

Access HTML element later in document through JavaScript

I am just starting out with JavaScript and I have a simple code that sends a value to an element with id p. I am currently declaring this function in a <script> in the <head> element of my document.
function writeP(resultSet) {
document.getElementById('p').innerHTML = resultSet.length;
};
writeP(results);
When I have this listed within the <head> element and run the webpage, firebug throws this error at me: TypeError: document.getElementById(...) is null.
However, if I move the code block into a <script> tag beneath the element and then reload the webpage, no problems and the script works as it should. Is there any reason for this, and a way I could make this work so I wouldn't have to define my functions beneath the element or include a onload on my body element?
Thanks for your help
Reason is that by the time your launch js code, DOM is not yet prepared, and JS can't find such element in DOM.
You can use window.onload (docs on W3schools) trigger to fire your functions after all elements are ready. It's same as having onload property on body element, but is more clear, as you can define it in your js code, not in html.
JS evaluates syncronically. Therefore, it does matter WHEN you declare the function. In this case, you're declaring it before the element actually exists.
Second, when you declare a function with that syntax, it does get eval'd inmediately. If you declared, instead
var writeP=function(resultSet) {
document.getElementById('p').innerHTML = resultSet.length;
};
you could save just the call to the end of the Doc, and leave the declaration at the beggining.
However, I would advise you to read a few jQuery tutorials to learn easier ways to deal with dom manipulation. Nobody runs raw JS for that task anymore.
jQuery includes an useful call to document ready event, which will save you a lot of headaches and is -IMHO- more efficient than the onload event. In this case, you would include the jQuery library somewhere in your code
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
and then add
<script>
jQuery(document).ready(function() {
var writeP=function(resultSet) {
jQuery('#p').html(resultSet.length);
};
writeP(resultSet);
});
</script>
just about anywhere in your document or an external js file, as it suits you.

when has a function to be in $(document).ready()

I just don't get it. I searched and searched but for this I just can't figure out what's "right".
There are three examples.
1) Fiddle 1.0
Here we have html with onlick="function" and the javascript function right there as well which works fine
<span class="classic one" onclick="someFunction(this,'one')">CLICK HERE</span>
<script type="text/javascript">
function someFunction(obj,nr) {
var string = $(obj).attr('class');
$('.result').text( string );
}
</script>
2) Fiddle 2.0
Then when I move the function to the script section (kind of move it to the .js file) I get an error "ReferenceError: someFunction is not defined"
THIS IS WHERE THE QUESTION BEGINS
3) Fiddle 3
So now I have a function in document ready calling with .on(click which always works fine. This function is calling another function which is outside the docuemnt.ready() and also works fine.
So the question. When do I have to define the functions where AND WHY so it always works?
Thank you!
All the code from Example 3) looks like this:
<div class="result">result</div>
<span class="classic one" onclick="someFunction(this,'one')">CLICK HERE</span>
<span class="classic two" onclick="someFunction(this,'two')">CLICK HERE</span>
<span class="classic three" onclick="someFunction(this,'three')">CLICK HERE</span>
<span class="classic four" onclick="someFunction(this,'four')">CLICK HERE</span>
<div class="ready">ready</div>
<span class="callOtherFunction">Call other function</span>
<script type="text/javascript">
$(document).ready(function(){
$('.ready').text( 'dom is ready' );
function someFunction(obj,nr) {
var string = $(obj).attr('class');
$('.result').text( string );
}
$( "span.callOtherFunction" ).on({
click: function() {
$(this).css("color","red");
$(this).addClass("xyz");
otherFunctionCallingFunction($(this));
}
});
});
function otherFunctionCallingFunction($me) {
$('.callOtherFunction').append( ' --> ' + $me.attr('class') );
}
</script>
A lot of what you're seeing is because of jsFiddle's very surprising default setting, which is to wrap the code in the script pane in an onload handler. So your code is wrapped in a function and no longer at global scope (which is where functions need to be if you use onclick-style attributes). You can change this with the drop-down box on the left (the second one, under the list of libraries and scripts). Change it to "no wrap" to have unwrapped code.
You're not (by far!) the first to be bit by this surprising default.
Answering your main question:
when has a function to be in $(document).ready()
If you control where the script tags loading your script go, you basically never have to use ready; instead, just make sure your script tags are at the end of the HTML, just before the closing </body>.
You can use ready, of course. The reason for doing so is to make sure that all the DOM elements have been created before your code runs. But if you put your script tag at the end, that's already true. You can still define your functions outside of the ready handler (if you want them to be globals), but if you're using ready, you would call them from the ready handler so the elements exist.
FWIW, I would avoid using onclick-style attributes for hooking up event handlers, primarily because they require you to create global functions. I prefer to avoid creating any global symbols when I can avoid it.
The general form I'd recommend:
<!-- ...your page markup here... -->
<script src="any_libraries_you_need_if_you_are_not_combining.js"></script>
<script src="your_script.js"></script>
</body>
</html>
where your script looks like this:
(function($) { // A scoping function that wraps everything
// Hook up event handlers here. You can use `$` for jQuery, even if
// you've used noConflict, because we have a private `$` symbol (see
// the `$` argument above)
// The body of your code goes here
})(jQuery); // <== Note how we're passing the jQuery reference in
// and immediately executing the scoping function
Here's a complete example: Live Copy
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Script Placement Example</title>
</head>
<body>
<input type="button" class="hello-button" value="Click me">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>
// This would be in a file, rather than inline
(function($) {
// Hook up handlers
$(".hello-button").click(sayHello);
// Body of the code
function sayHello() {
$("<p>Hello!</p>").appendTo(document.body);
}
})(jQuery);
</script>
</body>
</html>
In JavaScript, scope is handled on a per-function basis. Anything in scope of a function can access other things in scope of that function and things in a wider scope.
Defining a variable with var inside a function will limit the scope of that variable to the function.
Defining a function with a function declaration inside another function will limit the scope of the defined function to the container function.
When you use ready, you pass a function to it. Anything defined in that function is, of course, scoped to that function. Since it is scoped to that function, it is not a global. Your onclick attribute isn't defined in the scope of that function, it can only access globals. This is why you get a reference error.
Avoid globals. They make things hard to maintain. Avoid onclick attributes, they usually depend on globals.
You need to use ready if you want code to run after the DOM has been fully constructed. This is useful if you want to bind event handlers to elements in it with JS (e.g. with jQuery.on). Do this rather then using onclick attributes.

executing javascript function from HTML without event

I wish to call a javascript function from an HTML page and I do not want it dependent on any event. The function is in a separate .js file since I wish to use it from many web pages. I am also passing variables to it. I've tried this:
HTML:
<script type="text/javascript" src="fp_footer2.js">
footerFunction(1_basic_web_page_with_links, 1bwpwl.html);
</script>
The function in fp_footer2.js:
function footerFunction(path, file) {
document.write("<a href=" + path + "/" + file + " target='_blank'>Link to the original web page for this assignment.</a>");
return;
}
(I have also tried putting the fp_footer2.js file reference in the header, to no avail. I'm not sure if I can put it 'inline' like I did in this example. If not, please let me know.
PS: I know I can do this with a simple 'a href=""' in the HTML itself. I wanted to see if this could work, for my own curiosity.
If a <script> has a src, then the external script replaces the inline script.
You need to use two script elements.
The strings you pass to the function also need to be actual strings and not undefined variables (or properties of undefined variables). String literals must be quoted.
<script src="fp_footer2.js"></script>
<script>
footerFunction("1_basic_web_page_with_links", "1bwpwl.html");
</script>
JavaScript will run while your page is being rendered. A common mistake is to execute a script that tries to access an element further down the page. This fails because the element isn't there when the script runs.
So includes in the <head> will run before any DOM content is available.
If your scripts are dependent on the existence of DOM elements (like a footer!) try to put the script includes after the DOM element. A better solution is to use the document ready event ($(document).ready() in jQuery). Or window.onload.
The difference between documen ready and window onload is that document ready will fire when the DOM has been rendered; so all initial DOM elements will be available. Where as window onload fires after all resources have loaded, like images. window onload is useful if you're doing things with those images. Usually document ready is the right one.
Maybe I misunderstand your question, but you should be able to do something like this:
<script type="text/javascript" src="fp_footer2.js"></script>
<script type="text/javascript">
footerFunction(1_basic_web_page_with_links, 1bwpwl.html);
</script>
Have you tried calling it from a document.ready?
<script type="text/javascript">
$(document).ready(function() {
footerFunction(1_basic_web_page_with_links, 1bwpwl.html);
});
</script>

Mouse Events on JsFiddle not working?

I've got my fiddle here, but I can't understand why it's not calling my function on the 'onmouseout' event.
http://jsfiddle.net/foreyez/Xf6LW/
any ideas?
Works fine, you just needed to put the function in the head (or body after the element is in the DOM) of the document.
jsFiddle example
It's because the functions you create in the JavaScript panel are not global when you have the onLoad option selected. Your JavaScript gets wrapped in a function.
If you do want them to be global you have to either do what j08961 suggested, by changing that dropdown to say no wrap (body or head) will work
The best solution would be to not set your event handlers from HTML, that's bad practice anyway, then you're not relying on global functions or mixing HTML and JS.
<div id="myDiv">
</div>​
document.getElementById('myDiv').onmousemove = function() {
alert('here');
}
Side note: you should have noticed the error in the console saying that myFunc is undefined or something like it.
I think it's cause for jsfiddle, it declares all the javascript AFTER the HTML. The HTML is going to run and look for a myFunc and not find it. Then it's going to load the JS and it won't even run it.
Here you can see the changes : jsfiddle.
make myFunc as a global function;
I searched my code using firebug and got following generated code.
window.addEvent('load', function() {
//window.myFunc makes myFunc as a global function
// It can be accessed from any were inside current window.
window.myFunc = function myFunc(x)
{
alert('yo');
}
// function below is not available gloably.
function myFunct1(){
alert('yo1');
}
});
see jsfiddle

Cannot get declared variables in javascript

Consider a javascript file script.js which contains the code alert(theVar);
Now, i linked the js file to the document like
<script type="text/javascript">
var theVar= 'a alert';
</script>
<script type="text/javascript" src="script.js"></script> //Contains alert(theVar);
The variable theVar is used and i get a alert. This works fine.
When,
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
var theVar= 'a alert';
</script>
is used, i am not getting a alert.
I know the problem is because of the variable, which is declared after loading the js file.
But is there any way to get the variable declared anywhere in the document ?
in script.js do
window.onload = function() { alert ( theVar ) }
Or your favorite library dom ready fn, so it invokes the callback after a certain event instead of immediately.
Though, this really depends on what kind of functionality script.js has, which you have not specified thus far.
The important bit is that code gets executed in the appropriate order. You should delay the call to alert(theVar) until the document gets fully loaded. For instance, you can attach an onload event handler to the window object.
It's also worth noting that calling external *.js files does not affect the way code gets run.
The simple solution:
Move the script.js inclusion to the last row of the body. That way a variable declared at any point in the document can be used.
The technical solution:
Inside script.js, hook on to the window.onload event before doing any evaluating. The result is the same as with the simpler solution, but allows you to keep you script tags in the head (or anywhere for that matter).

Categories

Resources