Jquery document ready with function declaration? - javascript

I want to know why the below code works differently when according to the documentation it should do the same thing.
http://learn.jquery.com/using-jquery-core/document-ready/
First example:
<script>
$( document ).ready(function() {
document.write("And what?");
});
</script>
It actually overwrites everything on the page and return only "And What?"....
Second example:
<script>
$( document ).ready(test());
function test() {
document.write("And what?");
}
</script>
It actually returns the content of the page with "And what?" at the end of it, so it does append the text but why?!
What are the difference between those two functions and how to get the same example with Yahoo YUI?

document ready and document write are not the same thing:
document.ready is a jQuery event that will be triggered after your DOM finish to load.
document.write is a native function of JavaScript that will override all the content of your page by the value you send as argument.
The difference between the 2 codes you show is that in the first one you are sending a function as param and in the second one you are sending the result of function as param because you are calling test when you include the braces.
So with your codes the problem is that in 1 you call the function after DOM is ready and in 2 you exec the function at the time you call it.
To have same result in both code you should to remove braces when you send test function as param in the second example:
<script>
$( document ).ready(test);
function test() {
document.write("And what?");
}
</script>
Besides this little different the 2 results that you are getting are because is the "strange" way that document.write works. Check out the documentation which explains why this happens.

If you call document.write() after the document has finished loading, then the browser will clear your current page and start a new blank page. That is how it is written to work. So this:
<script>
$( document ).ready(function() {
document.write("And what?");
});
</script>
will always clear the page and start a new one with only "And What?" in it.
Your second code example would generate the same result if you didn't mistakenly call the test function before $(document).ready() fires. If you did this:
<script>
$( document ).ready(test);
function test() {
document.write("And what?");
}
</script>
You would get the same result as above.
Instead, when you do this:
<script>
$( document ).ready(test());
function test() {
document.write("And what?");
}
</script>
You're calling test() immediately (it is not waiting for the doc to be ready) and then passing it's return value (which is undefined) to $(document).ready().
To pass a function reference so it can be called LATER, you pass only the function's name without parens after it. If you put parens after the name, you are instructing the JS interpret to execute the function right now and pass the return result instead. If you pass only the function's name, you are passing a function reference that the function can then call later.

Related

Why does 'jQuery' have to be passed into this function (see last line of code)?

Source: http://blog.tomasjansson.com/creating-custom-unobtrusive-file-extension-validation-in-asp-net-mvc-3-and-jquery
$(function () {
jQuery.validator.unobtrusive.adapters.add('fileextensions', ['fileextensions'], function (options) {
var params = {
fileextensions: options.params.fileextensions.split(',')
};
options.rules['fileextensions'] = params;
if (options.message) {
options.messages['fileextensions'] = options.message;
}
});
jQuery.validator.addMethod("fileextensions", function (value, element, param) {
var extension = getFileExtension(value);
var validExtension = $.inArray(extension, param.fileextensions) !== -1;
return validExtension;
});
function getFileExtension(fileName) {
var extension = (/[.]/.exec(fileName)) ? /[^.]+$/.exec(fileName) : undefined;
if (extension != undefined) {
return extension[0];
}
return extension;
};
} (jQuery));
Wouldn't jQuery already be available inside this function, why would it be passed in at the end there? I don't get this and I've seen it a few times before, never had to use it so, was curious what's going on here.
Passing it in isn't doing anything. That syntax isn't right since the function, as it's used there, is a callback and not IIFE.
Only reason I could think to do that would be if no conflict mode is used. Even then the syntax is still not correct.
Read More: jQuery.noConflict
We pass jQuery or other jQuery Control variable ($, jQuery, jq, jQ, jQ1101) to the module or plugin because in the DOM, We can have multiple version of jQuery loaded or we can have other libraries which uses $ as control variable. Such as PrototypeJS or Zepto
By passing jQuery Control variable we ensure that we have right control variable for our module and internally we just use $ as jQuery variable.
Please see this example.
<html>
<head>
<title>StackOverflow 19257741</title>
<script type="text/javascript" src="http://zeptojs.com/zepto.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
</head>
<body>
<div id="content">
<!-- Other HTML Tags -->
</div>
</body>
<script type="text/javascript">
//Change jQuery Control because you have other library loadded or you have multiple jQuery loaded.
var jQ1101 = jQuery.noConflict(true);
//Now, you can not access jQuery by $ or jQuery
//This module have to have jQuery to do DOM Manipulation
var module = (function ($, zepto) {
var i = 0, //private ivar for module use only.
_init = function () {
var me = this;
//TODO: Module can init or do something here...
return me;
},
_fill = function (selector) {
//We can use $ here as jQuery Control
$(selector).css({ "backgroundColor": "#000000", "width": "100%", height: "100%" });
//Wait for 2 seconds
window.setTimeout(function() {
//Not select dom with zepto
zepto(selector).css({ "backgroundColor": "#777777", "width": "100%", height: "100%" });
}, 2000);
};
return {
init: _init,
fill: _fill
};
})(jQ1101, $); //We have to pass the current Control for jQuery so, module can use library for internal function.
//Call module then call fill method by passing variable
module.init().fill("#content");
//Two different Library
console.log(jQ1101.fn.jquery); //jQuery 1.10.1
console.log($); //Zepto
</script>
<html>
The code in that blog post is valid JavaScript syntax and will execute, but it doesn't do what the author probably expected. The $(function...) call looks like an attempt to run that function on DOM ready in the usual manner, but that's not what happens.
Let's deconstruct the code. First, strip out all the code in the function and add some logging:
console.log( 'before' );
$( function () {
console.log( 'DOM ready' );
} (jQuery) );
console.log( 'after' );
This is (perhaps surprisingly) valid JavaScript and will log:
before
DOM ready
after
But here's the problem: If you put that script in a web page, you really want it to log:
before
after
DOM ready
After all, you're running the script before the DOM is ready, expecting the function to be run later, after the DOM becomes ready. That's the whole point of using the $() call.
What went wrong? To make it more clear, let's break out the inner function as a separate named function:
console.log( 'before' );
function ready() {
console.log( 'DOM ready' );
}
$( ready(jQuery) );
console.log( 'after' );
And one more change to make it completely step-by-step:
console.log( 'before' );
function ready() {
console.log( 'DOM ready' );
}
var result = ready( jQuery );
$( result );
console.log( 'after' );
Each of these versions has exactly the same semantics and runs in the same order.
Now it should be clear what happened. We're calling the ready function immediately and passing its return value into the $() call. The ready function doesn't return any value, so that value is undefined.
The last line, then, is the equivalent of:
$( undefined );
And that call simply returns an empty jQuery object ([]).
The culprit, of course, is that (jQuery) at the end. Adding that is what caused the function to be called immediately, instead of passing a reference to the function into the $() call. And the presence of jQuery inside the parentheses is meaningless: this ready function doesn't expect any arguments, so that is ignored. It would be the same thing if () appeared there.
It's very much like a common error you see with setTimeout() and similar calls:
// Oops - calls doStuff immediately, not after one second
setTimeout( doStuff(), 1000 );
This raises the question: why didn't this code run into a problem since it doesn't doesn't work as expected? Well, the function does get called either way - the only difference is when it's run.
So two possible reasons why it didn't cause a problem.
This block of code may have been placed at the end of the <body> as is popular practice these days. In that case the DOM would probably be ready-enough when the code is run. DOM elements are created in order as the <body> is loaded, and if you put a <script> tag after a particular DOM element, that DOM element will indeed be available when that script is run.
The code may not require the DOM to be ready. Looking at the validator code in the blog post, it does look like setup code that doesn't do anything with the DOM when it's first run. If so, then as long as the jQuery.validator plugin is already loaded, then it wouldn't make any difference if this code runs immediately or later when the full DOM is ready.

Jquery syntax when calling methods

This code:
<script type="text/javascript">
someMethod1();
$(function () {
someMethod2();
});
</script>
What is the difference between these two callings? When do we do the first call, and when do we do the second call? What is the order of the method execution?
someMethod1();
This might be called before or after document is ready and it does not require jQuery. If this is at the end of your page it will be called when all control are ready but if it is in middle then it will know only controls that got rendered.
$(function () {
someMethod2();
});
This is call always after the document gets ready and all the controls are ready/rendered. This requires jQuery. You can read more about ready here. This will also help you understand the other function call.
someMethod1 is executed immediately
someMethod2 waits for the whole page to load,
including external javascript files (other scripts, or from other sites), CSS
and other resources before executing the code.
$(function () {
//run after page loads
});
Method2 sometimes comes in the form of
$(document).ready(function() {
// Handler for .ready() called.
});
For more info: http://api.jquery.com/ready/
The statements in the script block are executed in the order in which they occur. If we number the lines and insert an extra line break or two to make it easier to talk about:
1 someMethod1();
2
3 $(
4 function () {
5 someMethod2();
6 }
7 );
Line 1, someMethod1() is executed first.
Then line 3, $() is executed, where the parameter to $() is an anonymous function defined on lines 4 to 6. The $() function schedules that anonymous function to be executed later in response to the document ready event. That is, the anonymous function is not executed at that time.
Finally, when the document is ready, the anonymous function from lines 4 to 6 is executed which means line 5 someMethod2() occurs.

How can I block the execution of a script until another one is loaded?

Suppose I load these scripts from my host webpage :
<script src="http://www.mywebsite.com/widget/widget.js?type=normal" type="text/javascript"></script>
<script src="http://www.mywebsite.com/widget/widget.js?type=rotation" type="text/javascript"></script>
and I'd like to execute the second one only when the first one have finished (totally; it can contain asynch functions).
How can I do it?
You're already doing it right : the scripts are executed in the order of integration in the page, not loading.
EDIT : as MaxArt pointed, this may not be what you're looking for. His answer is a good one.
But generally, you'll want to use javascript usual patterns and event based logic to avoid this kind of problems :
have most of your files define only classes and functions (some of them taking callbacks as parameters)
have a main file launching this and calling the sequence of actions, the asynchronicity being handled via callbacks.
My main code usually looks (a little) like this :
$(window).ready(function() {
var myBigEngine = new BigEngine();
myBigEngine.init(function(){
// do other things, no need to add other layers as user events and ajax message callback will do the rest
});
});
Wrap the whole script in a function, like this:
(function(id) {
var id = setInterval(function() {
if (!window.doneLoading) return;
clearInterval(id);
// The whole script file goes here
...
}, 50);
})();
The setInterval polls the (global, sorry) variable doneLoading. In the first script, you have to set doneLoading to true or any other non-false value when your async function is completely loaded, like at the end of an AJAX request maybe?
Edit: since I'm suggesting to add a global variable to the script, it may as well add a global function. So instead of setting up a setInterval call, wrap the second script inside a function... but like this:
function doneLoading() {
// The whole script file goes here
...
}
In the first script file, at the end of your callback function, just call doneLoading().
Try applying defer="defer" attribute to second <script> declaration like
<script src="http://www.mywebsite.com/widget/widget.js?type=rotation" type="text/javascript" defer="defer" ></script>
you can put second script init function in window.onload event
window.onload = function(){
// call function from second script
}
or with jQuery
$(function(){
// call function from second script
});
you can event add second script with this function
function loadScript(src){
var f=document.createElement('script');
if(f){
f.setAttribute("type","text/javascript");
f.setAttribute("src",src);
document.getElementsByTagName("head")[0].appendChild(f);
}
}

What's the correct way to call JavaScript Function?

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.

Why is function() needed sometimes in JavaScript?

HTML
<button id='hello'>Click Me!</button>
JavaScript (wrong)
$('#hello').click(alert('Hello, World!'));
JavaScript (correct)
$('#hello').click(function() {
alert('Hello, World!');
}
I'm wondering why the first JS code triggers on the event load instead of click. Can anyone tell me why function() { [code] } is needed for the script to work properly?
In this example, I used jQuery events, but this is not specific to it, for example, I need to use it with setTimeout, too.
The click function expects another function as a parameter.
In the first case you would be passing the result of calling alert('hello world');, which is null.
The second is just a shorthand for:
$('#hello').click(callback);
function callback(){
alert('hello world');
}
Because .click() is a handler. The first argument is a function to assign. But if you actually pass the function with arguments then it will call the function (in this case alert) and then pass it's return value.
Writing $('#hello).click( function() { } )` is basically a short hand for writing:
var myfunction = function() {
// code
};
$('#hello').click( myfunction );
As you can see in the long hand way, it's passed as a reference to the function instead of the function's return value.
Your first example says "evaluate
alert('Hello, World!')
right now, and pass the result as an argument to click. "
The second says "Define a function which will do the alert when I call it, and pass that whole function as an argument to click.
The function() { ... } syntax is how you declare an anonymous function in Javascript. jQuery uses lots of these to specify that some action will be performed later, like when an event occurs. You can think of it as delaying the execution of your function until necessary. Without this syntax, whatever code you place there is evaluated immediately, which is not what you want for an event handler.
You might think, "why isn't JavaScript smart enough to know the difference?" Consider this:
function returnCallback(linkId, data) {
return function(e) {
alert('Clicked on ' + linkId + '. Here is some data: ' + data);
// Maybe do some stuff with e, the event parameter
}
}
$('#some-link').click(returnCallback('some-link', 'some-data'));
$('#other-link').click(returnCallback('other-link', 'different-data'));
This is a contrived example, but it illustrates the power of anonymous functions and closures. This works since returnCallback returns a function.
In the first instance, "JavaScript wrong", you're actually calling alert('Hello, World!') at the point that the script is loaded. Now, the reason you pass the .click function a function is because it can call it at any point. Essentially, you're packing code together to be run (or not run at all) at any point when you put it in a function.
$('#hello').click(alert('Hello, World!')); is attempting to run alert('...') and pass its return value to the .click() function which will not work as expected.
This is because JavaScript evaluates everything and during this process your alert is invoked. You can use anonymous function or you can also use your own custom function as implemented below:
<script language="javascript" type="text/javascript">
$("#mybutton").click(clickFired);
function clickFired() {
alert('click fired');
}
</script>
The parameter required for the .click() function is a Function. Therefore $("#hello").click(function { [code] }); is required. Because there's nothing to return by alert().
The click function here assigns a value to the event handler.
With the first ("wrong") code you're assigning a value of alert('Hello, World!') which is itself a function call, so it's going to be immediately evaluated and hence appear at load.
With the second ("correct") code you're now assigning a new anonymous function which is not executed itself, just instantiated at load. Hence this will work as expected later.
somefunction(alert('hello! world'));
this would mean you want to pass to somefunction the return value of alert("hello! world").
jquery click expects a callback that it should fire upon click on the element. so you put it in a function which does not execute unless someone (here jquery) calls it explicitly.

Categories