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.
Related
How do I clear out anonymous functions that are set to trigger via a jQuery document.ready() call?
For example:
<script type="text/javascript">
//some code sets a doc ready callback
$(document).ready(function ()
{
alert('ready');
});
//my attempt to prevent the callback from happening
window.onload = null;
$(document).unbind("ready");
</script>
The alert happens regardless of my attempts to circumvent it. Is there any way to do this?
You'd probably get the most appropriate answer if you described what problem you're really trying to solve.
jQuery doesn't have a publicly documented way to undo or block document.ready() handlers. If you control the code, you can use a global variable and a conditional like this:
var skipReady = false;
$(document).ready(function ()
{
if (!skipReady) {
alert('ready');
}
});
// skip the document.ready code, if it hasn't already fired
skipReady = true;
Or, if you want to hack into jQuery a bit (beyond the documented interfaces), you can do this:
$(document).ready(function() {
alert("ready");
});
// stop the ready handler
$.isReady = true;
You can see this last one work here: http://jsfiddle.net/jfriend00/ZjH2k/. This works because jQuery uses the property: $.isReady to keep track of whether it has already fired the ready handlers or not. Setting it to true makes it think it has already fired them so it won't every do it again.
This works:
$(document).bind("ready", function () { alert("hey!"); });
$(document).unbind("ready");
Seems like a bug to me - all other events in jQuery are able to be unbound. Omitting this one is inconsistent.
Not a direct answer as to the omission, but here's some related info from jQuery docs:
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
There is also $(document).bind("ready", handler). This behaves similarly to the ready method but with one exception: If the ready event has already fired and you try to .bind("ready") the bound handler will not be executed. Ready handlers bound this way are executed after any bound by the other three methods above.
$(document).ready() is dependent on the onLoad event which is triggered by the browser meaning you can not prevent it from happening. If the alert() is determined by some condition then I would use an if/else statement to decide whether it is called.
Super old question, but came across the need to do this recently to prevent document.ready code I didn't control from running in certain instances. This can be achieved by proxying jQuery's ready function, rather like a test spy. The following will work:
var ready = $.prototype.ready;
// proxy the ready function
$.prototype.ready = function ( fn, allowed ) {
allowed = allowed || false;
if ( allowed ) {
ready.call( this, fn );
}
};
All calls to $( document ).ready will now be ignored. You can override this behaviour by passing true as the second argument: $( document ).ready( fn, true )
I am currently making use of Simon Willson's addLoadEvent function to add functions that I want to run after the load event. I ran into a problem wherein the the function I passed to the addLoadEvent function referenced a div that had not yet been loaded by the DOM and so my action (showing the div) did not do anything. When I changed to using the jQuery $(document).ready function, the div has been loaded by the DOM and I can execute actions with it (make it show up).
So, a couple questions. Why is my function being executed before the DOM has completed loaded using the above function? Is there a way to delay it? The other alternative that I can think of is passing in a function to a jquery equivalent:
function jqueryAddReadyEvent(myFunc)
{
$(document).ready(function()
{
//execute already existing functions
//add a new function to the ready event
myFunc();
}
}
When I try the above code, I get a javascript error "myFunc is not a function". Is there a way to generically pass in a function to the jquery ready function and have it execute? Equivalent to the following:
$(document).ready(function()
{
funcA();
}
$(document).ready(function()
{
funcB();
}
...//more of the same
Replaced with the following:
jQueryAddReadyEvent(funcA);
jQueryAddReadyEvent(funcB);
You can just do:
$(document).ready(myFunc);
to attach functions to the DOM ready event. Here's the fiddle: http://jsfiddle.net/padtE/
If you will require many functions to be added then I suggest you do the following:
Create an array that will old all the functions you want to call.
Add functions to that array as you please.
In the .ready(function() { ... }) call every function in that array.
You're set.
It looks correct to me. Most likely you are calling it with something not a function.
Btw you can shorten this to:
var jqueryAddReadyEvent = $(document).ready
or just use $(document).ready() directly for the same effect, as it specifically does what you want to do, run functions after the load, and is actually shorter.
$(document).ready(funcA);
$(document).ready(funcB);
function jqueryAddReadyEvent(myFunc) {
$(myFunc);
}
jqueryAddReadyEvent(function() {
alert('hello world');
});
Demo: http://jsfiddle.net/AlienWebguy/UzMLE/
I have multiple document.ready functions on a page and I want a function to be called when all my document.ready functions have been executed. I simply want the function to be called
at the very end, after all other document.ready functions have executed.
An example of this could be that each document.ready function increments a global variable when it has been executed, and the last function needs to check the value of that variable at the very end.
Any ideas ?
This will be enough:
$(function () {
window.setTimeout(function () {
// your stuff here
}, 0);
});
This postpones the execution of your function after all other in the document ready queue are executed.
First idea (for small apps): Tidy up
You can just put everything in one $().ready() call. It might nieed refactoring, but it's the right thing to do in most cases.
Second idea: A Mediator [pattern]
Create a mediator class that will register functions and call its register() instead of $().ready(). When all functions are registered You just loop over the collection and run them in the single and only $().ready() and You have a point in code that is just after all is executed.
I am currently developing a kind of a framework for jquery applications that has a mediator. I might stick together a small version including the mediator if You're interested.
Why not just calling it after all the others ?
$(function(){
func1();
...
funcN();
functionThatNeedsToBeCalledAfter();
});
Of course you will have to cleanup your code to have only 1 place where the document ready function is used... but then your code would be more readable so it's worth it.
little hacky but might work, create a variable inside jquery scope like that
$.imDone = false
then create a function with setTimeout called after short time to lookup for the variable ser to true
var theLastFunctionToCall = function(){
alert('I m the last being called!')
}
var trigger = function(){
$.imDone?theLastFunctionToCall():window.setTimeout(trigger,10);
}
trigger();
I only recommend this when u have different $(document).ready in different big js files, but if you can refactor i sincerelly recommend an optimal solution.
I have a 2000 line jquery file, I just broke up the file into smaller ones, If I have a function in the first file, that file # 2 is referring to, it's coming up undefined.
Every file is is wrapped in a jquery ready function, What's the best way to do this?
If the function in question is declared within the scope of the ready handler, it won't be accessible to any other code, including other ready handlers.
What you need to do is define the function in the global scope:
function foo()
{
alert('foo');
}
$(document).ready(function()
{
foo();
});
P.S. A more concise way of adding a ready handler is this:
$(function()
{
foo();
});
Edit: If the contents of each of your divided ready handlers rely on the previous sections, then you can't split them up, for the reasons outlines above. What would be more sensible would be to factor out the bulk of the logic into independent functions, put these in their own files outside the ready event handler, and then call them from within the handler.
Edit: To further clarify, consider this handler:
$(function()
{
var foo = 'foo';
var bar = 'bar';
alert(foo);
alert(bar);
});
I might then split this up:
$(function()
{
var foo = 'foo';
var bar = 'bar';
});
$(function()
{
alert(foo);
alert(bar);
});
The problem with this is that foo and bar are defined in the first handler, and when they are used in the second handler, they have gone out of scope.
Any continuous flow of logic like this needs to be in the same scope (in this case, the event handler).
Function definition should not be wrapped in another function. Not unless you really want that function definition to be private. And if I understand correctly that's not your intention.
Only wrap function invocation in the jQuery ready function.
If you're worried about your functions clashing with third party function names then namespace them:
var myFunctions = {}
myFunctions.doThis = function () {}
myFunctions.doThat = function () {}
But really, you only need to worry about this if you're creating a mashup or library for others to use. On your own site YOU have control of what gets included in javascript.
Actually, for performance reasons, it may be better to keep it in one file; multiple requests actually can take up more bandwidth... but as separate files, you would need to order them in a particular order so that there is a logical sequence. Instead of having everything in a document.ready, have each script define a method, that the page will execute within its own document.ready handler, so that you can maintain that order.
Most likely the reason it's coming up undefined is because when you have separate ready calls, the scope of the code inside those calls is different.
I would reorganize my code. Any shared functions can be attached to the jQuery object directly, using $.extend. This is what we do for our application and it works well.
See this question. Hope it helps.
Everyfile shouldnt have a ready function. Only one file should have the ready function and that should be the last file.
"wrapped in a jquery ready function" is nothing else than binding stuff to the ready event that is fired when jQuery thinks the DOM is ready.
You should only bind methods that is depending on the DOM to the ready event. It doesnt matter how many binds you make, all of the methods will be executed in the binding order in the end.
Functions provide scope in JavaScript. Your code in the jquery.ready is an anonymous function, so it is unaware of the other scopes. remove the wrappings for those JavaScript functions and declare them as regular functions, a la
$(document).ready(function ()
{
functionFromFile1();
functionFromFile2();
};
I have seen this (I'm also using it):
$(document).ready(function(){
// do jQuery
})
and also this (I have tried lately):
(function(){
// do jQuery
})(jQuery)
both work fine.
What is the difference of the two (except on how it looks)?
Which one is more proper to use?
The second example you show is a self executing anonymous function. Every separate JS file you use would probably benefit from using it. It provides a private scope where everything you declare with the var keyword remains inside that scope only:
(function($){
var special = "nice!";
})(jQuery);
alert(special); // would be undefined
The first example is shorthand for $(document).ready which fires when the DOM can be manipulated.
A couple cool things about it. First, you can use it inside the self executing function:
(function($){
$(function(){
// Run on DOM ready
});
// Run right away
})(jQuery);
Secondly, if all you need is a few lines in document ready, you can combine both the private scope and the DOM ready function like this:
jQuery(function($){
// $ = jQuery regardless of what it means
// outside this DOM ready function
});
The first example runs the function when the DOM tree is built.
The second example runs the function right away.
If you look closely, in the second example, there are two parentheses after the function declaration ( in this particular case, you pass in the global jQuery object as an argument to avoid conflict ), thereby immediately invoking the function
The right function to use depends on when you want the function to run.
If you want to run a function on DOMReady ( the ready event ), you can use $( document ).ready like you mentioned or the shorthand $( function() {...} ).
Otherwise, if you want to run a function immediately and have anonymous function scope, use the second example.
In addition to all the previous answers,
jQuery have three initialization methods that can be used:
The traditional method compatible with most browsers, see code:
$(document).ready(function () {
});
The short-hand method, see code:
$(function () {
});
The implicit method, see code:
$().ready(function () {
});
They all work for modern browsers and safe to use.
I always use the first. The second appears to be a way to protect against jquery being overriden. One reason you might do this is if you don't know what other scripts will be loaded on the page. If all of your stuff depends on, say, jquery 1.3, and you're in an environment where you don't control the entire page, your code could break if someone loads in jquery 1.4. Sounds ugly, but this sort of thing does happen. So you can cover your butt by creating a closure immediately after you load jquery, and holding your version of jquery inside that closure. I think that's what's going on in the second example.
Neither one actually initializes jquery. Jquery takes care of any initilazation it needs on its own. You'd still, quite likely wind up using the first example even if you were using the second, you'd just be putting the $(document).ready inside the function in your second example.
Though it's an old conversation, I want to share my way to init jQuery
;(function($, window, document) {
// Your Code Goes Here
}(window.jQuery, window, document));
By this, you can sure about that nothing can go wrong.