Run functions in a loop JavaScript/JQuery - javascript

I have a bunch of functions that calls another function. I want to run those group of functions in an infinite loop and can't really come up with a logic.
My code looks like this:
<script>
function runAnim(x,y) {
//animation code
}
runAnim(a,2);
setTimeout(function() {
$('#a').fadeOut('fast');
}, 3000);
runAnim(b,4);
setTimeout(function() {
$('#b').fadeOut('fast');
}, 3000);
</script>
So I want to run these two 'runAnim' functions in an infinite loop. I tried
while(1) {}
but this hangs up my browser. I tried implementing setInterval method but don't know how I can do this. If you want I can post the runAnim(x,y) function for more clarity.

Change your runAnim method to include a call to runAnim via setTimeout so that you can an infinite loop while ensuring that maximum stack isn't exceeded.
function runAnim(x,y) {
//animation code
if ( y == 2 )
{
setTimeout( () => {
runAnim(x,4);
$('#a').fadeOut('fast'); //call the fadeout here itself
}, 3000 );
}
else
{
setTimeout( () => {
runAnim(x,2);
$('#a').fadeOut('fast');
}, 3000 );
}
}

You don't need an explicit infinite loop, you can just let the functions call the other one over and over again
Here is an example with chaining:
function fadeOutA() {
$('#b').fadeIn('fast');
$('#a').fadeOut('fast', fadeOutB);
}
function fadeOutB() {
$('#a').fadeIn('fast');
$('#b').fadeOut('fast', fadeOutA);
}
function stop() {
$('#a, #b').stop();
}
$('#start').click(fadeOutA);
$('#stop').click(stop);
div {
width: 50px;
height: 50px;
float: left;
margin: 10px;
}
#a {
background-color: green;
}
#b {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="a"></div>
<div id="b"></div>
<button id='start'>START</button>
<button id='stop'>STOP</button>

What i suggest is don't write any logic which run is infinite loop, because it will cause problem for your browser. But event if you want it to be done done something like below
create for loop for(var i=0;;i++){} and then place your function inside this loop which will execute unlimited times.

Related

Make a Testimonial Scroller Stay on the Screen Before Fading Out

I have a testimonial scroller that shows one testimonial, fades out, shows the next, fades out, and returns to the first.
My issue is that after the fade in animation, the fade out animation begins immediately. It doesn't give enough time for someone to read it.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
$("#one").fadeOut(6000).delay(3000);
setTimeout(fadeTwo,6000);
});
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
$("#two").fadeOut(6000).delay(3000);
setTimeout(fadeThree,6000);
});
}
function fadeThree() {
$("#three").fadeIn(4000,function() {
$("#three").fadeOut(6000).delay(3000);
setTimeout(doFade,6000);
});
}
doFade();
});
jQuery's delay function will only delay functions that are called after it in the chain, so it is having no effect on your code. Delay docs
You need to use it before the call to fadeOut, e.g.
$(document).ready(function() {
function doFade() {
$("#one").fadeIn(6000,function() {
setTimeout(fadeTwo,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeTwo() {
$("#two").fadeIn(6000,function() {
setTimeout(fadeThree,6000);
})
.delay(3000)
.fadeOut(6000);
}
function fadeThree() {
$("#three").fadeIn(6000,function() {
setTimeout(doFade,6000);
})
.delay(3000)
.fadeOut(6000);
}
doFade();
});
Edit:
You are currently setting a timeout to execute the next function, within the complete callback of fadeIn. This is a bit confusing to my mind, and I think it is simpler and clearer to do something like the following. In addition, there is no reason to define the three functions within the ready function - it is personal preference but I like to keep the amount of code within a callback to a minimum, such as...
$(document).ready(function() {
doFade();
});
function doFade() {
setTimeout(fadeTwo,12000);
$("#one").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeTwo() {
setTimeout(fadeThree,12000);
$("#two").fadeIn(6000).delay(3000).fadeOut(6000);
}
function fadeThree() {
setTimeout(doFade,12000);
$("#three").fadeIn(6000).delay(3000).fadeOut(6000);
}
Edit 2:
In further effort to reduce the amount we repeat ourselves, we can extract the whole animation sequence into a function:
$(document).ready(function() {
doFade();
});
function fadeInThenOut(element) {
element.fadeIn(6000).delay(3000).fadeOut(6000);
}
function doFade() {
setTimeout(fadeTwo,12000);
fadeInThenOut($("#one"));
}
function fadeTwo() {
setTimeout(fadeThree,12000);
fadeInThenOut($("#two"));
}
function fadeThree() {
setTimeout(doFade,12000);
fadeInThenOut($("#three"));
}
Edit 3:
At this point we probably notice how similar our three functions are, and want some way to reduce that repetitiveness. So we could use recursion, and just change which element we pass in each time.
$(document).ready(function() {
doFade();
});
function doFade(elementNumber) {
const elementNumber = elementNumber < testimonialElements.length ? elementNumber : 0;
setTimeout(doFade(elementNumber + 1),12000);
$('#' + testimonialElements[elementNumber]).fadeIn(6000).delay(3000).fadeOut(6000);
}
var testimonialElements = ["one","two","three"];
While this solution may lose something in readability and simplicity, the great advantage is that when you add a fourth testimonial, you don't need to write a function to handle it. All you would do is change the testimonialElements array to include the new element id.

AJAX Complete Handler not beeing fired

After some hard work on the backend of my Web Application I noticed that the GetMeasure Request takes up to 10 seconds to finish. I decided to apply an overlay so a potential user won't get confused because nothing happens on the screen. No matter if the request is successfull or not the overlay should get removed after the call - so using the complete handler should be the best choice - at least I thought. I really don't get why but in opposite to the success handler the complete handler won't get called.
AJAX Request:
$_loadingCircle = $('<img id="loading" src="http://www.obergurgl.com/_images/layout/loading.gif"/>');
PopulateOverlay($_loadingCircle);
$.ajax({
url: 'CoDTracker/Home/GetMeasures',
type: 'POST',
dataType: "html",
data: {
buID: buid,
aID: aid,
lID: lid
},
success: function (data) {
$('#measures').html(data);
},
complete: function () {
$_overlay.remove();
}
});
The request ends with status 200 (successfull) but the overlay won't get removed. I'm sure that the request completed because my measures got filled into the page while the circle spins as crazy instead of disappearing.
Am I doing something wrong?
Edit:
Overlay-definition
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
Your $_overlay is defined incorrectly.
Please use:
$_overlay = $('div.overlay');
And please refer to jQuery Selectors for more information:
https://api.jquery.com/category/selectors/
The way to select a div with a particular class, is not to copy the entire <div class="">, but rather as I did in the example above.
EDIT: in fact, if you make this change, your PopulateOverlay will no longer work, so you should rather just select it without assigning it to a variable:
complete: function () {
$('div.overlay').remove();
}
Because overlay is appended in the DOM, you should remove it with .class:
complete: function () {
$('.overlay').remove();
}
First, if there's no error, and that's all your code, it should work fine.
Let's try to make an example, with a mimic function to mimic the behavior of ajax complete, we can write it like:
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
$_overlay.remove();
});
}
$(function() {
theWorks();
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
So I guess, that your codes, is inside another function, and you may call it many times, let's make a button, and click to trigger it:
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
debugger;
$_overlay.remove();
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
Now, if click the button before the previous pop out disappear, some popouts last forever.
Why? Because when you click again, your $_overlay will be assign to a newly created element, which means you lost the reference to the previous pop out, and when later the remove works takes action, it only remove the newest one, and all the following removes, are about to remove something that is not on the page, so you won't see effects, and older popouts remains.
We could fix it, by catch the current element in another variable when you're executing your codes. This would work if you expect many pop outs.
var $_overlay = null; // We assume you define it somewhere, and it's visible to all your functions.
function PopulateOverlay($content) {
$_overlay = $('<div class="overlay">');
$content.appendTo($_overlay);
$_overlay.appendTo('body');
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
// Cache the current overlay, or simply move $_overlay here, if no other using it.
var $_curOverlay = $_overlay;
mimic(function() {
$_curOverlay.remove();
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: block;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
Or as what Laurens Swart suggest, simply toggle the state if you only need one pop out at a time.
var $_overlay = $('.overlay');
function PopulateOverlay($content) {
$_overlay
.empty() // Clear previous
.append($content) // Append the content
.show(); // Make it visible.
}
// See this as an ajax call with 2 sec delay.
function mimic(cb) {
setTimeout(cb, 2000);
}
function theWorks() {
$someEle = $('<div class="example">example</div>');
PopulateOverlay($someEle);
mimic(function() {
$_overlay.hide(); // Instead of remove, we make it hide, so we can reuse it later.
});
}
$(function() {
$('#click').on('click', theWorks);
});
.overlay {
display: none;
width: 100px;
height: 100px;
background-color: black;
}
.example {
color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="click">Click</button>
<div class="overlay"></div>

jQuery - Combine .hide() and .remove()

I want to define a function to remove element after x milliseconds.
jQuery.fn.extend({
remove: function(x) {
this.hide(x);
//this line won't work
//setTimeout(function(){ this.remove() }, x);
}
});
$("button").click(function() {
$("p").remove(600);
});
p {
background: yellow;
margin: 6px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div>
<p>Hello</p>
how are
<p>you?</p>
</div>
<button>remove</button>
After clicking the button, html looks like this:
<div>
<p style="display: none;">Hello</p>
how are
<p style="display: none;">you?</p>
</div>
<button>remove</button>
My problem is: The line: setTimeout(function(){ this.remove() }, x); didn't work. I think the compiler didn't understand what did this mean?
Can you give me any idea to call remove() function inside setTimeout?
this inside the setTimeout refers to the window object.
Use complete callback of hide()
A function to call once the animation is complete, called once per matched element.
this.hide(x, function() {
this.remove();
});
jQuery.fn.extend({
remove: function(x) {
this.hide(x, function() {
this.remove();
});
}
});
$("button").click(function() {
$("p").remove(600);
});
p {
background: yellow;
margin: 6px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div>
<p>Hello</p>
how are
<p>you?</p>
</div>
<button>remove</button>
Two issues, firstly this in the setTimeout() does not refer to the element which raised the click, but the window. You need to store the this reference in a variable within the function body. Secondly, inside the setTimeout you call remove() again, which creates a circular reference which only serves to create a new timeout. You need to change the name of the function so that remove() is still valid. Try this:
jQuery.fn.extend({
delayedRemove: function (x) {
var $el = this;
setTimeout(function(){
$el.remove()
}, x);
}
});
$("button").click(function () {
$("p").delayedRemove(600);
});
Example fiddle
No need to use timeout, you can remove the element in the done callback of hide.
jQuery.fn.extend({
remove: function (x) {
this.hide(x, function () {
this.remove();
});
}
});

javascript : post data after click finished

i am trying to do post AJAX request only once after color is set for more than 2 seconds.
[DEMO FIDDLE]
fiddle
in the fiddle i want AJAX call to be fire only once after color is selected.
i don't want AJAX call to done on every click
how to do that?
As you want it to fire only once, bind .one() instead of .on() to the element. This will make the event execute only once.
And for delay, use setTimeout().
You can simply add a flag to check if your code ran before.
var timeout;
var executed;
var arry = ['red', 'blue','orange', 'green'], i=0, len= arry.length;
$('#element').on('click',function(){
$(this).css('background',arry[i++]);
if(i===len){i=0;}
if(!executed){
clearTimeout(timeout);
timeout = setTimeout(function(){
alert("executed");
executed = 1;
}, 2000);
}
})
#element{
width:50px;
height:50px;
border:1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="element"></div>
Demo
This can be done by just adding a condition in your click event as below
$(document).on("click", "#element", function () {
if ($('body').data("isServerHit") === undefined) {
$('body').data("isServerHit", true);
setTimeout(function () {
// Write the code for ajax call here
alert('server will hit now');
}, 2000);
}
});
For more details on $('body').data("isServerHit", true);, visit save data (in jquery)
Hope this helps :)

Animate forever loop works in Chrome but not in IE

I have the following snippet of code that loops through the jQuery animate function endlessly. It works fine on Chrome, but fails after the first animate call on IE. My questions are:
How can I make this work in IE (9)?
How can I add a delay after the first loop? I want there to be a delay between consecutive pulses.
#container {
position : relative;
width : 500px;
height : 200px;
overflow : hidden;
opacity: 1;
}
.
#container > img {
position : absolute;
top : 0;
left : 0;
}
.
$(window).load(function(){
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else {console.log('2');
$image.animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
});
.
<div id="container">
<img src="blah.jpg" width="500" height="375" />
</div>
Remove the console.log() statement from the else branch and it should work in IE - IE doesn't like console.log() unless the console is actually open, whereas (most) other browsers either ignore it or log in a way you can see if you open the console later. (I don't have IE9, but that's all it took to fix it when I tested it in IE8.)
Also it doesn't make sense to have a document ready handler inside a $(window).load() handler, so you should remove one or the other.
As far as adding a delay between consecutive pulses, just use jQuery's .delay() function before calling .animate() in the else branch, like this:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == '1') {
$image.animate({opacity: '0.4'}, 2000, function () {
animate_img();
});
} else { // console.log removed from this spot
$image.delay(500).animate({opacity: '1'}, 2000, function () {
animate_img();
});
}
}
animate_img();
});
P.S. Given that the anonymous functions you've got for the .animate() complete callbacks don't do anything except call animate_img() you can remove the anonymous functions and just pass animate_img directly. So you can make the function much shorter if you wish:
$(function () {
var $image = $('#container').children('img');
function animate_img() {
var fade = $image.css('opacity') == '1';
$image.delay(fade?1:500).animate({opacity:fade?'0.4':'1'},2000,animate_img);
}
animate_img();
});
After a deleted discussion about if setTimeout() or setInterval() should be used, a different solution using setInterval()
$(function () {
var $image = $('#container').children('img');
function animate_img() {
if ($image.css('opacity') == 1) {
$image.animate({opacity: 0.4},{ queue:false, duration:2000});
} else {
$image.animate({opacity: 1},{ queue:false, duration:2000});
}
}
setInterval(animate_img, 4000);
});
Notice that interval time should have a minimum of 4000ms, which the sum of the animation time (2000ms each) back and forth. If the interval is less than that, the animations won't be completed.
I insisted in the previous (deleted) discussion that the correct syntax for setInterval should be setInterval("animate_img()", 4000) ... my bad, because I missed that setInterval was within a function ... so the function animate_img should be called as a pointer rather than a string.
The advantage of this solution (I think) is less lines of code but also that we don't need to call the function animate_img() 3 times in the loop and from within itself.
This should work fine in Chrome as well as in IE.

Categories

Resources