Why does this work:
$("#oneButton").click(function () {
alert("hello");
});
But this doesn't work?
$("#oneButton").click(
alert("hello");
);
The anonymous function route gives a function to be executed later. The second example merely executes code immediately, never waiting for a click event to take place.
The $.fn.click method expects to call a function on your behalf, which will handle the future click event(s). If you give it a number, or a string, or undefined, it will do nothing.
The alert function returns undefined, so your second example is nothing more than:
$("#oneButton").click(undefined);
Note that you don't need to use an anymous function, and in most cases you probably shouldn't. You can use a named function, which helps with debugging down the road:
function handle ( event ) {
alert( "Clicked" );
}
$("#oneButton").click(handle); // or .click(function handle ( event ) { ... });
In this example, we're passing the function reference to our click event to serve as the handler. Now that jQuery knows of our function, it will execute it when the click event is raised on #oneButton.
Related
If I call the function once like this
var button = document.querySelector('button');
button.addEventListener('click', once);
function once() {
console.log('one');
button.removeEventListener('click', once);
}
It's calling only once.
But if I called like this once()
var button = document.querySelector('button');
button.addEventListener('click', once());
function once() {
console.log('one');
button.removeEventListener('click', once());
}
Exception throws
Exception: InternalError: too much recursion
Could you please explain why this is happening.
() after function name invoke's the function. So as button.addEventListener('click', once()); you are bind the return value of once() method which is undefined.
And since once() is called recursively without any break statement, you are getting the InternalError: too much recursion.
You should pass the function reference.
button.addEventListener('click', once);
For Additional Info:
Pointer Vs Delegates
If you put () after the name of a variable holding a function, then you call the function.
If a function calls itself, then it will get called, call itself, call itself again and so on unto infinity. This is recursion. Doing something unto infinity will cause a computer to run out of memory, so it is undesirable.
JavaScript engines prevent this by throwing an exception when you try it.
(There are exceptions, of course, a function that calls itself conditionally can be very useful).
The first code is correct, because you register the function to be called.
The second code tries to register the result of the function call once(). This means you actually execute the function when you only want to register it. Now, in your function body, you do the same to deregister the callback. Here again, you call the function you are already executing and hence, you recurse infinitely.
I have the following jQuery code:
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(function(){
next();
});
$("#previous").click(function(){
previous();
});
This works, but this doesn't:
$("#next").click(next());
$("#previous").click(previous());
Why is this happening? Is there a problem in my code, or is this just a thing with jQuery? Note: #next and #previous refer to two buttons in my html file.
The callback should be a reference to the function.
Why $("#next").click(next()); doesn't work?
func() is a function call and not a reference, which is why it is called immediately.
This,
$("#next").click(function(){
next();
});
is a preferable way in case you need to pass arguments.
Else,
$("#next").click(next) //notice just the signature without ()
This works (if the functions next and previous are defined):
$("#next").click(next);
$("#previous").click(previous);
In this case the next and previous are also callback functions, the difference between the two is,
when you call this line
$("#next").click(next()); the function is executed immediately, and you are passing the result of the next function to the eventHandler of jQuery.
and in this case
$("#next").click(next); you are passing the function next to the EventHandler of jQuery.
Btw.: in the jQuery API Documentation (https://api.jquery.com/click/) it shows all parameters for the click function and the required types it states: "...handler Type: Function( Event eventObject ) A function to execute each time the event is triggered. ..."
try like this you will get your answer,
function next() {
//some code here
}
function previous() {
//some code here
}
$("#next").click(next);
$("#previous").click(previous);
working demo jsfiddle Example
What is going on there is a little bit obscured by the syntax of anonymous functions function() { ... }. What you are doing by that is passing a function, without calling it. And I want to explain how this works:
If you have a simple function
function next() { return 5 };
It will simply return the value 5, if you call it from somewhere:
a = next(); // value of a will be 5
But what you can do too, is to pass the whole function to a. This is possible, because functions in JavaScript are actually objects:
a = next;
b = a(); // value of b will be 5
If you look at the syntax, it shows you, that putting parentheses () at the end of a function invokes it, and returns the return value. While the naked string, without parentheses hands you the function itself.
So what is a callback now, and what does click() like to get as a parameter? A callback function is a function, that gets called later; we actually hand it over, to get called later. click() would like to get such a function as parameter, and it should be clear now, that we have to pass the function without parentheses, to enable click() to call it later, instead of just passing a 5 to it.
$("#next").click(next);
So how does then the initial syntax with the anonymous function work?
function() { next(); }
actually wraps your next() into another function, which is anonymous – because it does not have a name – but is working in the same way as a named function. You can even set a variable by it:
a = function() { next(); } // a will be the anonymous function that calls next()
But calling that function a() will return nothing, because the anonymous function does not return a value (To be exactly: every function call in JavaScript is returning at least undefined, but that's a technical detail).
It can even be called immediately by putting parenthesis at the end of it:
a = function() { return next(); }() // value of a will be 5
Adding the return there will make sure, the return value of next() will be passed through the anonymous function.
This should make clear why
$("#next").click(function(){ next(); });
is working, and why
$("#next").click(next());
is not, but
$("#next").click(next);
will be a good solution.
$("#next").click(next); would work. Notice parenthesis are not required as the function/callback handler should be passed as a parameter.
I have two functions.
function function_a(callback) {
if (some_condition===true) {
callback // fire the callback
}
}
function function_b() {
... do some action
}
My script calls:
function_a(function_b());
Meaning, the callback in function_a() will be the execution of function_b().
However I do not always want function_b() to fire. I only want it to fire when some_condition===true (as in the function_a() body).
The problem right now is that whenever I feed a callback function into the parameters of another function it fires it automatically without running through the script of the function to determine whether or not the callback needs to fire at all.
Is there something I am doing wrong or some different way to do this?
Thank you!
You need to call function_a(function_b);.
Right now you are not passing function_b itself, you are calling it immediately and passing in its return value.
Your function_a should do callback() rather than callback.
Parentheses cause a function to "execute" or "fire". So like Comptonburger said, drop the parentheses for the "script call", but add the parentheses on the callback.
function function_a(callback) {
if (some_condition === true) {
callback(); // parentheses do the "firing"
}
}
function function_b() {
// ... do some action
}
// Script calls:
// No parentheses on function_b because we
// don't want to "fire it" right here and now.
function_a( function_b );
You can also pass function_b() as a string and evaluate it after condition passes.
function function_a(callback) {
if (some_condition===true) {
eval(callback); // fire the callback
}
}
function function_b() {
... do some action
}
function_a("function_b()");
Both of the functions are $.getJSON() functions, and even though my first function is placed before the other one, it sometimes occurs after the second one. Note that I mentioned "sometimes". When I keep refreshing the page, I get different results, and it's like it's randomly being chosen which function is called first. Here is the snippet of code:
timeClusters = [];
$.getJSON('java_output/tasksTab.json', function (data) {
console.log ("first");
// Method stuff here, not important
});
$( document ).ready(function() {
console.log("second");
// Method stuff here, not important
});
Now, when I run the program and look at the console, sometimes I get
first
second
but other times I get
second
first
It is essential that I get the first one first, and second second, because the second method processes data that is produced and altered in the first method.
Let me know if you need more information
The getJSON method is Asynchronous, that means that once started it will eventually hold a result, the function wrapped in document ready instead fires as soon as the DOM is ready, instead of doing this sequence of action you should move the code form the ready function to the getJSON callback:
$(document).ready(function() {
$.getJSON('java_output/tasksTab.json', function (data) {
console.log ("first");
}).done(function() {
console.log( "second" );
})
})
As adeneo pointed out you don't actually need to chain the done method, you can simply add the computation in the default callback:
$(document).ready(function() {
$.getJSON('java_output/tasksTab.json', function (data) {
console.log ("first");
console.log( "second" );
})
})
Other kinds of callback you can use are fail and always.
I have some javascript functions being called on Document Ready:
fogFields();
getLoS();
getShips();
startGame();
getNextMove();
However, it is as though getNextMove() is being called first, most likely as all it does is an ajax call and alerts the result. All the other functions have more work, so, the first thing that happens on load is the getNextMove() alert, and in the background you can see that none of the other functions did their work. Until I click OK on the alert window, no results are shown. Can I make it so that until a function finishes, the next wont even start. Some functions call their own extra functions before they finish, and that works in order, but I cant do that with the whole code...
Given the code in your question, there is no way the call to getNextMove can be invoked before startGame has been exited, regardless of their contents.
It may be true that a function that has been scheduled asynchronously (via timeout, AJAX callback etc.) within startGame completes at any time before or after the invocation of getNextMove, but this is a separate issue. To resolve that issue we need to know more about the contents of the functions.
If the other functions have an AJAX call in them, then these AJAX calls most certainly take a callback argument, which is a function that gets executes, when the AJAX call has finshed. Now, if you want to execute your functions in a way, the one function starts when the AJAX call of the previous function finished, you can add an additional callback argument to your own functions, which will then be passed to the AJAX calls. This should illustrate what I mean:
function logFields(callback) {
ajaxCall(callback);
}
function getLoS(callback) {
ajaxCall(callback);
}
function getShips(callback) {
ajaxCall(callback);
}
function startGame(callback) {
ajaxCall(callback);
}
function getNextMove() {
}
fogFields(function(){
getLoS(function(){
getShips(function(){
startGame(function(){
getNextMove();
});
});
});
});
If all of your functions use a ajax call then just use promises.
Simply return it, for example:
function fogFields(){
return $.ajax();
};
and then just use .then:
fogFields().then(getLos());
more information about deffered object on jquery doc page if you use it.
Or implementation in pure javascript you can find here and more theory here.
or another option, which I will not recommend you is to set async param in $.ajax call to false. Again it's for case you use jQuery.