How do I use .queue() to properly chain custom callback functions? - javascript

I'm trying to figure out how to chain custom functions:
I have something like this:
show_loader(0, function() {
open_box($target_open, event.value, '.wide-col', function() {
hide_loader(function() {
scroll_to_content($target_open, function() {
});
$(this).dequeue();
});
$(this).dequeue();
});
$(this).dequeue();
});
Those functions have a callback implemented that looks something like this:
function show_loader(position, callback) {
$ajaxSpinner.fadeIn();
status = "loading"; //some non-jQuery stuff
if (callback) $ajaxSpinner.queue( function() {callback()} );
}
You can see the basic idea of what i'm trying to do: execute my functions after the animations inside the functions are complete.
I don't think my code is quite right. The order should be: show loader, open box, hide loader, then finally scroll to content. Instead, it seems like this is what's actually happening when i test it: show loader, hide loader, scroll to content, then open box.
How do I get that order of function calls properly queued? And am I using the keyowrd "this" in the proper context?

You can see the basic idea of what i'm trying to do: execute my functions after the animations inside the functions are complete.
If you use standard animation functions from jQuery, you should be able to directly pass a callback to them. E.g.:
function show_loader(position, callback) {
$ajaxSpinner.fadeIn(callback);
status = "loading"; //some non-jQuery stuff
}
Have a look at http://api.jquery.com and see how they work.
Update:
Here is an example that produces the desired result using queue. I'm using a newer form, where the next function to execute is passed as argument to the callback. Maybe you are doing something wrong with dequeue. Edit: I tried your code and it works fine. I guess your are not using queue properly in the other functions.

Related

Callbacks : animate complete: called after .promise().done()

I made a very simple plugin for my personal use that allows animated rotations in jQuery.
And I added callback functions.
If the rewind parameter is true, the rotation is undone and then, a callback.
If it's false, the callback is immediate after the rotation.
I had to do this because, for some reason, the .promise().done(function(){ ... }) is called before complete: of animate()
So I had to skirt this.
Now the problem is that if I target multiple elements, the callback is called for each element. 'cause I use an each function I presume. But I want only one callback for the whole animation.
Here is the fiddle
How to do this please? Thx !
PS: I saw a similar question here : jQuery $.animate() multiple elements but only fire callback once but not applying because of the .promise().done() issue. And I don't want to add a variable, I want to understand ^^
You could try using the index of each and only call the callback if it is the first element
Something like:
return this.each(function(i) {
....
....
complete: function() {
i==0 && a.callback && a.callback()
}

Can I make Javascript always call a method after JQuery Load?

We have started using jquery load in our site to load contents into a div rather than re-loading whole page. However in the complete function we have a method that re-applies various bindings. Is it possible to provide load method with a default complete function? So developers don't have to specify it in the jquery load complete function.
As we currently are providing a lot of duplicate complete functions
E.g.
$('#Target').load(callBackRedirect, function () {
ApplyBindings('#Target');
});
These bindings can't be applied using on and need to be re-applied on page loads. We also do some other work that we want to do on every page load.
The answer is no.
You need the callback because that's what the method calls when the request is done.
This works with on method to, you might be doing something wrong out there in the code.
You could create a helper function for this.
function loadSomething(targetElement, uri,callback) {
targetElement.load(uri, callback);
}
loadSomething(
$('myElement'),
'mylink.com/content',
function() {
applyBindings($(this));
}
)
Yes. Check out the list of Global AJAX Event Handlers.
e.g.
$(document).ajaxComplete(function() {
alert('Triggered ajaxComplete handler.');
});
That said, you shouldn't need to reapply your bindings after an AJAX call. If you need to do this, you're probably doing something wrong. Check out jQuery.on, which explains how to bind to content which is added dynamically.
Try $.ajaxSetup:
$.ajaxSetup({
complete: function() {
ApplyBindings('#target');
}
});
EDIT
You could also make a named function like:
var ajaxApplyBindings = function() {
ApplyBindings('#Target');
// anything else...
};
And then pass it to load:
$('#Target').load(callBackRedirect, ajaxApplyBindings);

How do you make animations not fire unless previous is done (withtout using callback)

I have a function called:
this.makeStuffHappen()
Which makes different animations according to a switch statement and a couple of variables. Is it possible to make a function not fire unless all previous are done resolving.
I want to write something like
$('button').click(function(){
a.makeStuffHappen();
b.makeStuffHappen();
c.makeStuffHappen();
d.makeStuffHappen();
});
And then it should only run b after a is done, c after b is done and d after c is done. Is it only possible to make animations wait for the previous by chaining them? Is it possible to chain any function?
Edit: makeStuffHappen() is animating different elements so a.makeStuffHappen() will animate a different element than b.makeStuffHappen and so on.
Thanks.
The easiest (or at least most flexible) way would be using deferred objects [docs]. For that you have to return a deferred object from each function, for example:
a.makeStuffHappen = function() {
elementA.animate(...);
elementB.animate(...);
...
return $.when(elementA, elementB,...);
};
Same for b.makeStuffHappen, etc.
$.when() [docs] returns a deferred object where you can attach callbacks to which are executed once all deferred objects passed to it are resolved.
Then in your event handler, you can call .pipe() [docs] on these deferred objects, to chain them together:
$('button').click(function(){
a.makeStuffHappen()
.pipe($.proxy(b.makeStuffHappen, b))
.pipe($.proxy(c.makeStuffHappen, c))
.then(function() {
console.log('All done');
});
});
DEMO
A callback would be the easiest way, but since you don't want to use a callback (which jQuery's .queue() does require - well... a recursive callback anyways), you could let the methods you have return a bool:
$('button').click(function()
{
var theObjects = [a,b,c,d];
for (var i=0;i<theObjects.length;i++)
{
if (theObjects[i].makeStuffHappen() === false)
{
break;//or throw, or whatever...
}
}
});
Of course, it is well possible the methods may vary depending on which object is called. You could work around this by using an object instead of an array, in which case your event handler could look something like:
$('button').click(function()
{
var theObjects = {a:'aMethod',b:'bMethod',c:'cMethod'};
for(var i in theObjects)
{
if (theObjects.hasOwnProperty(i))
{
if(window[i][theObjects[i]]() === false)
{
break;//or throw, or return...
}
}
}
});
Mind you, I don't know why you don't want to use some form of callback here, as it would be the easiest way to go... but that is, of course, none of my concern... :-)
Well, had a quick look at your game... seems fun, keep working on it :). BTW, you're one step away from using callbacks all over the place:
$('#placeBet').click(function() {
placeBet();
});
Can be written as:
$('#placeBet').click(placeBet);
In the latter, placeBet is a callback function.
I think you're main concern is here:
player.printHand();
dealer.printHand(isDealerHidden);
What I'd do here, is change the printHand function, by adding this at the end:
if (this.name !== 'dealer')
{
dealer.printHand(isDealerHidden);
}
I haven't read enough of your script to make this work as you need it to, but you get the idea... An easier way would be not to animate the dealer explicitly, but alter all animators of the players hand to end with some code that animates the dealer after the players animation is completed... I know, I'm talking gibberish, but I'm at work... and sick... Good luck, anyway. I might take some more time checking your progress, maybe read your script more closely tonight and edit this dribble to something that will actually work :-)
Take a look at jquery's queue function:
http://api.jquery.com/queue
You could add a callback function to your method :
this.makeStuffHappen = function(callback) {
//do things like animations
$(this).animate({ ... }, 200, callback);
//or call the callback after everything is done:
callback();
}
and you can use it like this:
$('button').click(function(){
a.makeStuffHappen(b.makeStuffHappen(c.makeStuffHappen(d.makeStuffHappen())));
});

jQuery: How can I perform an action after .css has executed?

So my issue is pretty straight forward, since there is seemingly no callback for after a .css is executed, what options do I have for making performing something after a task is done?
I'm creating a simple lightbox, and I need to wait for the center align to finish...
$("#img_lightbox").css("top", top);
So when that completes, I then need to fade in the whole thing, but since there is no callback option (to the best of my knowledge) it will occasionally start fading in before the alignment finishes... how can this prevented?
Any help is appreciated, thank you.
Anything being chained with your jQuery object will execute after the function before it. The easiest way to accomplish what you are asking is with Plugins.
jQuery.fn.myPlugin = function () {
//code to execute
return this;
}
$("#img_lightbox").css("top", top).myPlugin();
You could even write a plugin to execute a custom function, so you do not need to create plugins for every function you might happen to need to run:
jQuery.fn.myCallback= function (callback) {
this.each(function () {
callback.call($(this));
});
return this;
}
$("#img_lightbox").css("top", top).myCallback(function () {
// some code to run where this = $("#img_lightbox")
});
But incase I am still misunderstanding, you may be wanting a callback for your fade function: (otherwise please clarify more)
$("#img_lightbox").fadeIn('slow', function () {
$(this).css("top", top)
});
Adding and removing CSS styles are synchronous functions -- there is no callback because the next statement will be executed once the style has been applied. Rendering of the updated style is slightly different, since that will happen during the next repaint, but unless you're doing some serious number-crunching in your UI code, the difference would be completely unnoticeable. In any case, it would be applied before the 'fading in' starts to happen.
If you're seeing something wrong with your display, I'd suggest that the problem lies elsewhere.
jQuery provides you with a way to tell once the document is "ready" and in the correct state to execute code correctly. Use one of the following:
$(document).ready(function(){
//your code here
});
or the shorter,
$(function(){
//your code here
});
More information at http://api.jquery.com/ready/

Javascript: How do you make function2 execute only after function1 is completely finished?

I have some code, with the order of the functions in the order I want them executed. However, they seem to at the same time (they begin sequentially within microseconds of eachother presumably).
The problem is that some of the functions include animations. How do I make it so the next function doesn't execute until the previous functions are completely finished???
Following is some of my code. I created a callback chain thinking that it would be the solution, but indeed it is not. The functions themselves call jQuery animations. I'm guessing i need to use some type of notofication from jQuery to tell me when animations are done. Anyhow, any advice is greatly appreciated!
show_loader(0, function() {
close_box($target_close, '/', '#' + $target_close.attr('id') + ' .post_wrap', function() {
open_box($target_open, event.value, '.wide-col', function() {
hide_loader(function() {
scroll_to_content($target_open, function() {
});
});
});
});
});
To be precise, I want the scroll_to_content() function to be executed after all the previous actions have been completed in their entirety. Currently, it executes at the same time as everything else, and therefore my page scroll is completely off because the size of my content continues changing after scroll_to_content() is finished.
Callback chains are basically the solution but I suspect you're not threading your callbacks correctly in your calls to jQuery. $.animate(...) has an optional complete callback-- that's where you want to pass the function that should execute after your initial animation finishes. All of the Effects in jQuery UI should have a similar optional argument.
You can use a similar pattern yourself in order to chain event handlers, for instance:
function handler(event, callback) {
// do some work
// ...
callback();
}
This strategy for chaining function evaluations is called continuation-passing style and is handy in a lot of situations. Be careful using it, however, as many people find it more confusing to read than a traditional, sequential implementation.
http://api.jquery.com/queue/
Sorry, I don't have enough time to go into detail, but as the previous commenter said, queues are what you want to be focusing on to solve this problem.
you have 3 options:
1- Split your animations into multiple chained animate() calls.
This is an example to clarify it for you.
2- Follow the answer posted by #dml.
3- Try to use this plugin to add delays between your calls (don't know if it can fix this scenario or not, give it a try)
http://www.evanbyrne.com/article/jquery-delay-plugin

Categories

Resources