Reputation: 48758
According to the jQuery documentation .animate
has a parameter called 'Complete' that should only fire once the animation has finished. Unfortunately I'm finding that it fires before the animation has even started.
if ($('html').scrollTop()) {
$('html').animate({ scrollTop: 0 }, callback);
return;
}
JSFiddle showing the problem: http://jsfiddle.net/JohnnyWalkerDesign/5zu90ygz/
What am I missing?
Upvotes: 4
Views: 1880
Reputation: 28611
The callback
parameter should be a function pointer
. It's not a term used very often these days, but it means that you pass the function itself, not the result of a function.
What does this mean?
Given the example:
function message(q) {
alert(q);
}
Here, message
is a function. To pass that function as a callback
, use the name of the function, eg:
setTimeout(message, 100);
$("#id").click(message);
Note that there's no ()
after the name of the function.
In javascript terms, the function itself is a variable and you pass the variable, but as soon as you add ()
you are calling the function and passing the result, not the function itself.
If you use message()
then the function will be executed and the result of the function passed as the callback
, ie:
setTimeout(message("x"), 100);
is the equivalent of:
var x = message("x");
setTimeout(x, 100);
So you can see from this code why message runs immediately (more obvious with click event or longer timeout).
The format setTimeout(message, 100);
isn't used very often as a) it looks like a typo (should that be message()
?) and b) it doesn't allow you to pass a parameter, so this would frequently be written as:
setTimeout(function() { message("x") }, 100);
which uses an anonymous in-line function as the callback
variable / function pointer.
Back the question:
In your original fiddle, all you needed to do was change the callback
to a true callback
without the need to add a separate parameter, ie:
$('#scroll').on('click', function(e) {
e.preventDefault;
scrollToTop(function() { message("Reached Top")});
});
Updated fiddle: http://jsfiddle.net/5zu90ygz/9/
Upvotes: 11
Reputation: 87203
You're calling the function message
when registering it as callback in the statement scrollToTop(message('Reached Top'));
. Here the function message
will be called and the returned value will be passed to the scrollToTop
function.
You can pass an extra parameter to the function scrollToTop
i.e. message to be displayed and then this message can be forwarded to the message
function after animation completes.
// Scroll to the top and fire callback
function scrollToTop(callback, message) {
// Send the message as the second parameter
if ($('html').scrollTop()) {
$('html').animate({
scrollTop: 0
}, function() {
// Call the callback function with the message as param after completion of animate
callback(message)
});
return;
}
if ($('body').scrollTop()) {
$('body').animate({
scrollTop: 0
}, function() {
// Call the callback function with the message as param after completion of animate
callback(message)
});
return;
}
callback(message);
}
// Dummy callback function to fire
function message(q) {
alert(q);
}
// On click event
$('#scroll').on('click', function(e) {
e.preventDefault;
// Add message as second parameter
scrollToTop(message, "Reached Top! Yay!");
});
div {
width: 100%;
border: 1px solid black;
height: 200px;
margin: 10px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<a href="#" id="scroll">Scroll to top</a>
Upvotes: 6