Does dojo/_base/fx support promises? - javascript

I am need to execute a method after an animation on a dom element ends.
At the moment I am using the following code with no success.
I would like to know if dojo, support promise for animation, if no, I would like to know in which way I could work it out.
fx.fadeOut({ node: 'target'}).play().then(function () {
// do smt here
}.bind(this));

Yes can you use the registered Callback of the FadeOut function.
the fadeOut (dojo/_base/fx function which returns an annimation instance)
provides 5 registred callback functions :
beforeBegin
onBegin
onEnd
onPlay
onAnimate (with argument)
In your case you need to make some actions when the animation is done so passe the onEnd function in the FadOut arguments, it should look like :
fx.fadeOut({
node:"target",
onEnd: function(){
// Some stuff at the end of the animation.
}
}).play();
you can also use the above callback as args .

I was able to solve this issue using 'dojo/on' and subscribing to the End event on fx.fadeOut(). Still I am very interesting to understand if there are better way for the same result.
var anim = fx.fadeOut({ node: 'target'}).play();
on(anim, "End", function () {
// dom smt here
}.bind(this));

Related

How to trigger visual effects and call a function afterwards in jQuery?

Good day fellow coders,
After tinkering awhile, I still couldn't find a way to invoke visual effects in jQuery and trigger a function afterwards. The program either completes mere visual effects, such as a vertical flip, or solely executes the denoted function. Is there a way to firstly complete the graphical effects and trigger the included function lastly, in just one click?
Below the pertaining code:
$("#HTMLButton").click(function(){
$("#Div").slideUp(400); //Is only run
arbitraryFunction; //Ignored
});
$("#HTMLButton").click(function(){
arbitraryFunction; //Is only run
$("#Div").slideUp(400); //Ignored
});
Thank you in advance!
First thing to do is have a look at the jQuery docs
- https://api.jquery.com/slideUp/
.slideUp( [duration ] [, complete ] )
duration (default: 400)
Type: Number or String
A string or number determining how long the animation will run.
complete
Type: Function()
A function to call once the animation is complete, called once per matched element.
So rather than a Promise interface, they offer a more traditional callback interface
$("#HTMLButton").click(function(){
$("#Div").slideUp(400, () => {
arbitraryFunction()
});
});
An alternative approach (if you lacked a callback mechanism) would be a setTimeout() function:
$("#HTMLButton").click(function(){
$("#Div").slideUp(400);
setTimeout(() => {
arbitraryFunction();
}, 400);
});

How do you get JQuery to wait until a previous event has fired

I am having a list of divs,whenever I click them I call a function,some trigger other ajax functions.
Now while the click even fires an ajax event,if I click another div I get last clicked div function called.How to solve this.
document.addEventListener("click",function(event){
checkparent(event);
}
function checkpaternt(event){
if(($(event.target).class=="checkparent"){//call ajax functions
}
else {//call local functions}
later I check the class name of the target and call different functions.
some more info(there are lots of div elements and if else statements)
Thank you.
Using a boolean flag: (and fixing your code)
function checkparent(event) {
if (ajaxRequestOn) return;
if (event.target.className == "checkparent") {
ajaxRequestOn = true;
//call ajax functions
$.ajax( /* ...*/ ).always(function () {
ajaxRequestOn = false;
});
} else {
//call local functions
}
}
I think following example might help you.
callbacks = [$.Deferred(), $.Deferred()];
obj1.on('click', callbacks[0].resolve);
obj2.on('click', callbacks[1].resolve);
$.when(callbacks).done(function() { console.log('After to events done'); });
Here I am creating two deferred object.
And each event resolving a deferred object.
when these all deferred object will be resolved next function you can write inside .done()
I think element.type will help you,
HTML
<input type="text" id="tipo-imovel" />
Script
$("#tipo-imovel").on("click change", function(event){
alert(event.type + " is fired");
});
This code will alert which event has been triggered
I'd suggest you to look at this possible events
Please let me know if it helped you
This might help: jQuery queues. Please go on below for the relevant quote:
How can jQuery queues be used here
Working Example
This is an amazing resource on using queues for custom ajax calls. I know the SO preference for archiving linked content, but I can't really copy code here, so I've also made a small fiddle showing custom queues - here
The example uses a text-color change, but that can easily be any AJAX call. The setTimeout has an asynch callback similar to many AJAX calls, this fiddle should be a useful template...
Theory
$('#elementId').click(function (e) {
var $element = $(e.currenttarget);
$element.queue('myqueue', function () {
var $el = $(this);
//Do stuff on $el
//Remove this event from the queue and process next...
$el.dequeue();
});
});
Breaking this down:
Listen to the click event
Get the specific element clicked
Queue a function on the 'myqueue' of this element
The function to be queued may need a reference to this element - luckily jQuery calls it with the required element as the 'this' pointer.
If you desire a gap between two events, you could even put the dequeue inside a timeout like window.setTimeout(500, function () { $this.dequeue(); }); , which sets a 500ms interval before the next event...
jQuery Queue Docs
This feature is similar to providing a callback function with an
animation method, but does not require the callback to be given at the
time the animation is performed.
$( "#foo" ).slideUp(); $( "#foo" ).queue(function() {
alert( "Animation complete." );
$( this ).dequeue();
});
This is equivalent to:
$( "#foo" ).slideUp(function() {
alert( "Animation complete."
); });
Note that when adding a function with .queue(), we should
ensure that .dequeue() is eventually called so that the next function
in line executes.
Update The answer has been modified to include a working fiddle and some explanation as well.

Fire a callback only once on animating two objects

I was starting to make a quite complex animation with jQuery and I was looking for a certain way to animate elements together. I wrote the code somewhat as follows, which I could use to animate multiple elements together:
Here's the fiddle: http://jsfiddle.net/wkhrU/
$(document).ready(function(){
$('#firstElement, #secondElement').animate(
{left : '+=400px'},
500,
"linear",
function(){
alert("completed");
});
});
However, the callback function fires twice i.e. each time for the element inside. What I was looking for is to be something like animating multiple elements simaltaneously for the same time duration and after the completion, fire a call inside which I wanted to swap the id attrib of the elements. I can't do the same here because on completion callback, it swaps the ids once and on the next function callback, swaps them back again. What's the appropriate way to achieve this?
SOLUTION
You could maybe use a promise() to call the function to be executed instead of the inbuilt callback of animate. This ensures that the function in done is called only after animating both the elements. It's basically like you're asking #firstElement & #secondElement to promise JS that it'll inform when both of 'em are done so that you could attach a done handler to it.
$(document).ready(function () {
$('#firstElement, #secondElement').animate({
left: '+=400px'
},
500, "linear").promise().done(function () {
alert("completed");
});
});
DEMO
http://jsfiddle.net/hungerpain/wkhrU/1/
MORE INFO ON USED METHODS :
promise
Docs : http://api.jquery.com/promise/
What it does : Makes sure that all actions of a certain type bound to the collection, queued or not, have finished.
done
Docs : http://api.jquery.com/deferred.done/
What it does : Add handlers to be called when the promise is resolved.

How should I make complex, sequential events in javascript

I'm working on an interactive tutorial-tool for JavaScript. The core of the tool is the script of the tutorial. The script will trigger various functions that run animations, speaker-voices load new pages etc. Three sample calls(most tutorials will have 10-100s of calls, so a neat overview of the calls is highly desired:
wrap(); //wrap the page in an iframe
playsound('media/welcome') //playing a sound (duh)
highlight('[name=firstname]'); //animation that highlights an element.
playsound('media/welcome2');
loadpage(page2); //loading a new page
All calls have something in common: they have non-normal-triggers. In this simple script for example, the second call should be triggered once the iframe in the first call is loaded. The third script is triggered once the sound is complete (ie delay). The fourth function should be triggered once the animation is complete. The fifth event should be triggered on an event (for example a click).
A technical solution to this would be to call the function in the callback of the previous function, this has the potential to get pretty messy. What I like with a solution wherer the functions are called lite this is that someone with a little bit of brains, but no coding experience could hammer up a script of their own. How would you solve this? I'm pretty new to javascript so if you could be explicit i'd appreciate it.
I'd use a per-built solution. There is bound be one that fits your needs. Something simple like jTour or if that doesn't cover it something a little more complex like Scriptio. Some of the answers to this question may also be of interest to you.
Edit
If you don't want to use a preexisting solution, I'd do something like this:
var runTutorial = (function () {
// The command object holds all the different commands that can
// be used by someone for the tutorial. Each of these commands
// will recive a callback set as their `this`. This
// callback should be called by your commands when they are done
// running. The person making the tutorial won't need to know
// about the callback, the code will handle that.
var commands = {
wrap: function () {
//wrap the page in an iframe
this();
},
playsound: function (soundPath, soundLength) {
//playing a sound (duh)
setTimeout(this, soundLength);
},
highlight: function (selector) {
//animation that highlights an element.
//I'm using jQuery UI for the animation here,
// but most animation libraries should provide
// a callback for when the animation is done similarly
$(selector).effect('highlight', 'slow', this);
},
loadpage: function (pageUrl) {
//loading a new page
setTimeout(this, 500);
},
waitForClick: function () {
// when we go into the click handler `this` will no
// longer be availble to us since we will be in a
// different context, save `this` into `that` so
// we can call it later.
var that = this;
$(document).one('click', function () {
that();
});
}
},
// This function takes an array of commands
// and runs them in sequence. Each item in the
// array should be an array with the command name
// as the first item and any arguments it should be
// called with following as the rest of the items.
runTutorial = function (commandList) {
var nextCommand = function () {
if (commandList.length > 0) {
var args = commandList.shift();
// remove the command name
// from the argument list
cmd = args.shift(1);
// call the command, setting nextCommand as `this`
commands[cmd].apply(nextCommand, args);
}
}
nextCommand();
};
return runTutorial;
}());
$('#tutorialbutton').click(function() {
runTutorial([
['playsound', 'media/welcome', 1000],
['highlight', '[name=firstname]'],
['playsound', 'media/welcome2', 1500],
['waitForClick'],
['loadpage', page2],
['playsound', 'media/page2', 100]
]);
});
The runTutorial function takes a simple array containing the commands in the order they should be run, along with their parameters. No need to bother the person writing the script with callbacks, runTutorial handles that for them. This has some big advantages over a system that requires the writer to manage callbacks. You don't need an unique name for each line in the script as you do with explicit callbacks, nor endless nesting of anonymous functions. You don't need to rewire anything to change the order that the commands are played in, you just physically rearrange them in the array.
jsfiddle you can play with
Each of your commands will need to wait for its action to be done before it calls its callback (aka this). I simulate this in the fiddle using setTimeout. For instance, if you are using jQuery's .animate for highlight, it provides a complete handler that fires when the animation is done, just stick this (with out the invocation parentheses ()) there. If you are using jQuery UI, it has a built-in 'highlight' effect, so you could implement it like this:
highlight: function (selector) {
//animation that highlights an element.
$(selector).effect('highlight', 'slow', this);
},
Most other libraries that provide animations should provide a similar callback option you can use.
Controlling the callback for the sounds may be harder depending on how you are playing them. If the method you are using doesn't provide a callback or a way of polling it to see if it is done yet you might just have to add another parameter to playsound that takes the length of the sound in ms and then waits that long before proceeding:
playsound: function (soundPath, soundLength) {
//playing a sound (duh)
setTimeout(this, soundLength);
},
Callbacks are your best bet, I think. They don't have to be messy (though it's certainly possible to make them completely incomprehensible). You could create each function to accept a callback, then use a structure like this to call them in sequence in a readable way:
var loadingSequence = {
start : function() { wrap(this.playsound); },
playsound : function() { playsound('media/welcome', this.highlight); },
highlight : function() { highlight('[name=firstname]', this.playsound2); },
playsound2 : function() { playsound('media/welcome2', this.loadpage); },
loadpage : function() { loadpage(page2); }
};
loadingSequence.start();

Chain to pre defined functions with jQuery

I have been trying to chain this last bit of code to work nicely.
It calls two functions that have been preset:
slideToImage(newIndex);
setCaption();
I want the caption to be set once the image has slid.
This has always been a confusing topic for me as I have tried different ways of calling it such as:
callbacks = $.Callbacks();
callbacks.add(slideToImage(newIndex));
callbacks.add(setCaption());
callbacks.fire();
But that does not work.
slideToImage must contain some animation logic that happens over time. So slideToImage would start the animation process and then return before the animation has completed which causes setCaption to be called to early.
You should pass setCaption into slideToImage as a callback and call it once the animation has completed.
function slideToImage(newIndex, callback) {
// I assume you're using jQuery for animation
targetElement.animate({left: 100}, 200, function() {
// once animation has finished we call the callback function
callback();
});
}
slideToImage(newIndex, function() {
setCaption();
});
For "setCaption", it's easy:
callbacks.add(setCaption);
For "slideToImage", since you need to pass a parameter, it's slightly more involved:
callbacks.add(function() { slideToImage(newIndex); });

Categories