myWait(ms) in jQuery? - javascript

I want to extend the $.fn object in order to have a delay between my jquery commands :
like this working (and quite long) code :
$('.d').delay(1000).queue(
function ()
{
$(this).css('background-color', 'green');
$(this).dequeue();
}).delay(1000).queue(function ()
{
$(this).css('background-color', 'red');
$(this).dequeue();
});
a working sample is here : JSBIN
So I tried this :
My code at jsbin
$.fn.myWait = function (ms)
{
return this.queue(
function ()
{
var _self = this;
setTimeout(function ()
{
$(_self).dequeue();
}, ms);
})
};
invoking :
$('.d').myWait(1000).css('background-color', 'red').myWait(1000).css('background-color', 'green');
But it doesnt work.
What am I doing wrong ?
p.s.
I did read this similar solution, but if I remove the animation part and use only css , it also doesnt work.

The .css() does not get queued on the animation queue by itself, that's why you needed to put it in a callback in your first snippet. In the second snippet, it is called immediately (even though there's timeout waiting in the queue - just as like you called .delay()). Instead, you would need to use an .animate() call with a zero-duration.
For allowing the syntax which you wanted, you will need to take a step further. Have a look at the jQuery timing plugin and how their magic works.

I doubt you can do it in this way. You need to defer execution of those attribute changes, which means you shall store said code in individual functions.

Related

Implement delayed jquery change event handler

What I basically want to achieve is create some kind of delayedChange plugin to be able to call some action (such as ajax call to the server) only after some delay the last input change event was fired. At the moment I've came up with this (jsfiddle). I should see alert only in 5 seconds (5000 msec) the last text change had place but it fires immediately.
(function ($) {
var timer;
$.fn.delayedChange = function (onchange, delay) {
return this.each(function () {
$(this).bind('change', function () {
if (typeof onchange == 'function') {
window.clearTimeout(timer);
timer = window.setTimeout(onchange.call(this), delay);
}
});
});
}
})(jQuery);
$(document).ready(function(){
$('input').delayedChange(function(){
alert($(this).attr('id'));
}, 5000);
});
The weirdest is that this code actually worked for some time, and then it's functionality just vanished for no reason. Obviously there is some explanation but I can't see it for now. Are there some more certain ways to implement/improve such plugin?
The functionality you've described is called "debouncing". Libraries such as underscore, lodash, and ampersand have a debounce method to make this effect convenient.'
With underscore, the code is:
$('input').each(function () {
$(this).on('change', _.debounce(...your function..., 5000));
});
No new function is needed, although you will need to include a new dependency.
I'd made a mistake with the first version. You need to generate a separate debounce function for each element, otherwise changing different elements will cause the timer to reset for all of the elements.

jQuery toggle class with delay works only once

I am clearly missing something fundamental when it comes to jQuery, anonymous functions, and delays.
The following code works only ONCE per page load (it will add the class, then remove it after 1 second, and if i click again, it will add the class, but will NEVER remove the class for the duration of the page, unless I reload the page):
var jElement = $(currElem);
jElement.addClass("highlight")
.delay(1000)
.queue(function(){
$(this).removeClass("highlight");
});
HOWEVER,
if I add the (non-existant) function call as a parameter, AND I call it in my anonymous function, then the add/remove class combination will work indefinitely.
var jElement = $(currElem);
jElement.addClass("highlight")
.delay(1000)
.queue(function(randomFunction){
$(this).removeClass("highlight");
randomFunction(); //this makes it seemingly 'miraculously' work??
});
Side Note:
var jElement = $(currElem);
jElement.addClass("highlight")
.delay(1000)
.queue(function(randomFunction){
$(this).removeClass("highlight");
// this does NOT work; if I dont actually call the 'randomFunction'
// so that function, even though it does nothing; must somehow cause
// the implicit call of 'dequeue()' ??
});
There is no miracle there. This behavior it's written in the documentation of .queue().
Note that when adding a function with .queue(), we should ensure that .dequeue() is eventually called so that the next function in line executes.
$('#foo').slideUp().queue(function() {
alert('Animation complete.');
$(this).dequeue();
});
As of jQuery 1.4, the function that's called is passed another function as the first argument. When called, this automatically dequeues the next item and keeps the queue moving. We use it as follows:
$("#test").queue(function(next) {
// Do some stuff...
next();
});
the randomFunction is actually referred to as next and references the .dequeue method. Calling it causes the queue to continue on to the next item in the queue.
http://api.jquery.com/queue/

Code not running when using ".remove()" function

I'm writing this jquery code :
$('form').after('<p id="suc"></p>');
$('#suc').html('success !');
$('#suc').show(700);
setTimeout(function(){$('#suc').hide('slow')},2500);
$('#suc').remove();
When i remove $('#suc').remove(); like this :
$('form').after('<p id="suc"></p>');
$('#suc').html('success !');
$('#suc').show(700);
setTimeout(function(){$('#suc').hide('slow')},2500);
The code run succefuly, but when i put it, it dosen't run !!
What the problem with that ?
it's illegal to but $('#suc').remove(); here ?
The setTimeout call doesn't wait for the callback to run before the code continues, so you will be removing the element immediately. When the code in the callback tries to hide the element, it's not there.
Remove the element in the complete callback of the hide method:
setTimeout(function(){
$('#suc').hide('slow', function(){
$('#suc').remove();
});
},2500);
As you're using hide you're also safe to use delay, so:
$('#suc').show(700).delay(2500).hide('slow', function () {
$(this).remove();
});
will suffice.
demo: http://jsbin.com/isediz/2/
Also, as a bit of clarification, regarding:
The code run succefuly, but when i put it, it dosen't run !!
Actually the code runs (in a sense), the problem is that your remove will not wait for the two asynchrones events (setTimeout and .hide('slow')). So it will get executed way before those two are done doing what they should do.
You need to put the remove() inside of the setTimeout and in the callback for the hide() function:
$('form').after('<p id="suc"></p>');
$('#suc').html('success !');
$('#suc').show(700);
setTimeout(function() {
$('#suc').hide('slow', function() { $(this).remove(); })
}, 2500);
You are using the element setTimout callback which you have already removed with the statement just after setTimout. The call back of setTimeout will execute after the statement removing element with id #suc by the next statement of setTimeout. Remove #suc in hide callback so that it is not accessed by script after removal.
$('form').after('<p id="suc"></p>');
$('#suc').html('success !');
$('#suc').show(700);
setTimeout(function(){
$('#suc').hide('slow',
function(){$(this).remove();
});
},2500);

In JQuery, Is it possible to get callback function after setting new css rule?

I have $('.element').css("color","yellow") and I need that next event was only after this one, something looks like $('.element').css("color","yellow",function(){ alert(1); })
I need this because:
$('.element').css("color","yellow");
alert(1);
events are happen at one time almost, and this moment call the bug in animation effect (alert(1) is just here for example, in real module it's animation)
you can use promise
$('.element').css("color","yellow").promise().done(function(){
alert( 'color is yellow!' );
});
http://codepen.io/onikiienko/pen/wBJyLP
Callbacks are only necessary for asynchronous functions. The css function will always complete before code execution continues, so a callback is not required. In the code:
$('.element').css('color', 'yellow');
alert(1);
The color will be changed before the alert is fired. You can confirm this by running:
$('.element').css('color', 'yellow');
alert($('.element').css('color'));
In other words, if you wanted to use a callback, just execute it after the css function:
$('.element').css('color', 'yellow');
cb();
You can use setTimeout to increase the sleep time between the alert and the css like this:
function afterCss() {
alert(1);
}
$('.element').css("color","yellow");
setTimeout(afterCss, 1000);
This will make the alert appear 1 second after the css changes were committed.
This answer is outdated, so you might want to use promises from ES6 like the answer above.
$('.element').css("color", "yellow").promise().done(function(){
// The context here is done() and not $('.element'),
// be careful when using the "this" variable
alert(1);
});
There's no callback for jquery css function. However, we can go around, it's not a good practice, but it works.
If you call it right after you make the change
$('.element').css('color','yellow');
alert('DONE');
If you want this function has only been called right after the change, make an interval loop.
$('.element').css('color','yellow');
var detectChange = setInterval(function(){
var myColor = $('.element').css('color');
if (myColor == 'yellow') {
alert('DONE');
clearInterval(detectChange); //Stop the loop
}
},10);
To avoid an infinite loop, set a limit
var current = 0;
$('.element').css('color','yellow');
current++;
var detectChange = setInterval(function(){
var myColor = $('.element').css('color');
if (myColor == 'yellow' || current >= 100) {
alert('DONE');
clearInterval(detectChange); //Stop the loop
}
},10);
Or using settimeout as mentioned above/
use jquery promise,
$('.element').css("color","yellow").promise().done(function(){alert(1)});

jQuery animate loop

I have a problem with animate loop. There is an object i want to move in a special way and do it in loop. Are there any native options to make it? I have this:
$(function () {
function runIt() {
$('#div').show("slow");
$('#div').animate({"marginLeft":"300px"},8000);
$('#div').animate({"marginLeft":"0px"},8000);
$('#div').hide("slow", runIt);
}
runIt();
});
But it seems not so pretty.
That's the proper way to queue animations. However, there's some things that can be made to your code to make it a bit snappier and prettier:
Store a reference to the selected element in a local variable to speed up execution (less queries made to the DOM)
Clean it up by removing unnecessary quotes for object properties
Sizing is measured in pixels per default so we can use pure integers instead
The named function can be replaced with a immediately invoked anonymous function and then use arguments.callee as the callback
Here's an example showcasing the above changes:
$(function () {
var element = $("#div");
(function(){
element
.show("slow")
.animate({ marginLeft: 300 }, 1000)
.animate({ marginLeft: 0 }, 1000)
.hide("slow", arguments.callee);
}());
});
You can also do it in a more advanced way by creating your own plugin to use custom queues. I created a small fiddle a while back when I was fooling around with animation queues.
More about immediately invoked function expression can be read on Ben "Cowboy" Alman's blog.
That is how I would do it. The only suggestion I would make is to use chaining for nicer code and so the jquery object doesn't get created every time.
$(function () {
function runIt() {
$('#div').show("slow")
.animate({"marginLeft":"300px"},8000)
.animate({"marginLeft":"0px"},8000)
.hide("slow", runIt);
}
runIt();
});

Categories

Resources