Incremental counter Javascript/JQuery - javascript

I'm trying to work out how to make this counter work. After a certain amount of animations have played, I want to make the page refresh. I know my code sucks. I'm not educated in this and I'm very new, not to mention it being difficult to concentrate (to say the least) where I'm staying at the moment... so be nice. Here it is:
$(document).ready(function () {
function loop() {
var p = 0;
if (p = 3) {
location.reload(true);
} else {
$("#p3").delay("1000").fadeIn("slow");
$("#p3").delay("1000").fadeOut("slow", loop);
p + 1;
};
loop();
});

Your if (p = 3) statement is using the assignment operator = instead of the comparison operator === or ==. So p gets assigned to 3, the result of which is truthy, so the else statement is never executed.
Also your p variable is declared inside your loop() function, so it gets reset every time the function is called - you could move that declaration to just before the function (keep it inside the document ready handler: no need to make it global).
Also the line p + 1; doesn't do anything: it doesn't increment p because you'd need to assign the result back to p with p = p + 1, the shorthand for which is p += 1 or just p++.
Finally, your code as posted has a syntax error: you are missing the closing } from the loop() function. I would guess the intention is to end the function and then call it, so:
$(document).ready(function () {
var p = 0; // <--- moved outside function
function loop() {
if (p === 3) { // <-- changed = to ===
location.reload(true);
} else {
$("#p3").delay("1000").fadeIn("slow");
$("#p3").delay("1000").fadeOut("slow", loop);
p++; // <-- changed from p + 1
};
} // <--- this is the missing bracket
loop();
});

I've made some assumptions and written what I believe is what you want, code is un-tested.:
Change it to:
$(document).ready(function () {
var globalP = 0;
//this is called when fadeOut completes.
function fadeComplete() {
if (globalP == 3) {//if it is 3 reload..
location.reload(true);
} else {
globalP++;//increment counter
animate();//start animation again...
}
}
function animate() {
//start fading in...
$("#p3").delay("1000").fadeIn("slow", function() {
//start fading out when the fadeIn completes.
//should this happen? Since you're fading in the SAME element.
$("#p3").delay("1000").fadeOut("slow", fadeComplete);
});
};
animate();
});

Related

js add event listener not working

I am trying to load interactivly some questins from questions' array (q) into my page and after student clicks at one of the 2 questions register the answer and change the question using js while loop. What is my mistake that it doesn't work?
var q = [
['NFR', 'Reusability'],
['NFR', 'Robustness'],
['FR', 'Reporting Requirements'],
['FR', 'Historical Data']
];
var correct = 0;
var incorrect = 0;
var total = q.length;
var i = 0;
document.getElementById('nick').innerText = name;
document.getElementById('question').innerText = q[0][1];
var nfr = document.getElementById('non-functional');
var fr = document.getElementById('functional');
function callback(ans) {
if (q[i][0] === ans) {
correct++;
} else {
incorrect++;
};
if (i < q.length - 1) {
i++;
document.getElementById('question').innerText = q[i][1];
} else {
location.href = "answer.html";
}
}
nfr.addEventListener('click', callback('NFR'));
fr.addEventListener('click', callback('FR'));
Your while loop is looping endlessly, because the only thing it does logically is set toNext to False, set some event listener callbacks and then evaluate toNext again, which will always be False. So i++ will never be called and i < q.length will always be True.
Get rid of the while loop. Write a separate function that evaluates the answer and updates your window with the next question. Use that function as callback for the click events.
In a callback function this will be set to the object calling the function, so you could write a function like this:
function callback() {
if (this.id == q[i][0]) {
window.correct++;
} else {
window.incorrect++;
}
i++;
set_question(i); // Logic to set the i-th question.
}
Edit
function callback(ans) {
// This function will return
// another function with the ans
// variable set, which in turn
// will be called as a callback
// when needed by the 'click' event.
return function () {
if (q[i][0] === ans) {
correct++;
} else {
incorrect++;
};
if (i < q.length - 1) {
i++;
document.getElementById('question').innerText = q[i][1];
} else {
location.href = "answer.html";
}
}
}
Event listeners are executed asynchronously and the code you write might assumes that the listeners can block loop execution.
To fix this, try removing the loop and move the logic of switching to the next question into the listener callback.

Cancel an infinite loop in JavaScript

I am trying to timeout a function in case it has an infinite loop. But the below does not work. Any idea why and how to fix it?
setTimeout(clearValues,1000);
function clearValues(){
i=0;
alert("hi "+i);
}
i=19
function infin(){
while(i>0){
console.log(i);
i++;
}
alert("Done");
}
infin();
In the below case, I get the alert displayed ( a bit later than expected ) and the console statements continue printing even after the alert. That means setTimeout did not wait for the loop to end in this case. Any explanation for this?
setTimeout(clearValues,500);
function clearValues(){
alert("clear");
}
function infin(){
for(i=0;i<10000;){
i=i+0.3;
console.log(i);
}
}
infin();
setTimeout works asynchronously, means it will run after 1000ms and the previous event loop is completed. Since the while loop will never be completed, the callback will never be called.
Add a condition to the loop if you want to exit it.
Another solution might be to use interval:
var code = function(){
console.log('tick');
};
var clock = setInterval(code, 200);
When you don't need it anymore:
clearInterval(clock);
It works, when you made the infin call with a slightly different change.
var i = 0;
setTimeout(clearValues, 1000);
var interval = setInterval(infin, 0);
function clearValues() {
out("clear");
clearInterval(interval);
}
function infin() {
if (i < 10000) { // if you be shure that you
i++;
out(i);
} else { // never reach the limit,
clearInterval(interval); // you can remove the four
} // commented lines
}
function out(s, pre) {
var descriptionNode = document.createElement('div');
if (pre) {
var preNode = document.createElement('pre');
preNode.innerHTML = s + '<br>';
descriptionNode.appendChild(preNode);
} else {
descriptionNode.innerHTML = s + '<br>';
}
document.getElementById('out').appendChild(descriptionNode);
}
<div id="out"></div>

clearInterval doesnt stop loop

I have the following code
startProgressTimer: function () {
var me = this,
updateProgressBars = function (eventItems) {
alert("updateProgressBars: looping");
alert("me.eventProgressTimerId:" + me.eventProgressTimerId);
var i = 0;
if (eventItems.length === 0) {
alert("internal Stop Begin")
clearInterval(me.eventProgressTimerId);
alert("internal Stop End")
eventItems = [];
}
for (i = 0; i < eventItems.length; i++) {
if (eventItems[i]._eventId) {
eventItems[i].updateProgressBar();
}
}
};
alert("Start Progress Timer");
this.eventProgressTimerId = setInterval(function () {
updateProgressBars([]);
}, 10000);
}
When the function is called I would expect it to run and bottom out only it keeps on looping.
screen output
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
Any ideas
I suspect the problem might be that the code you don't show calls the startProgressTimer() method more than once for the same instance of whatever object it belongs to, and then within the method you store the interval id in an instance property this.eventProgressTimerId - so multiple calls overwrite the property and you'd only be able to cancel the last one.
If that's the case, a simple fix is to declare your eventProgressTimerId as a local variable within startProgressTimer().

Animating a jquery set one object at a time

First, I'm relatively new to both js and jQuery, so I apologize in advance if this is a really stupid question. That said, here it is:
I'm trying to create a cannon-like animation for a background that does a slow 'sweep-like' transition from one image to another.
The biggest issue I've been running into is ensuring that;
a. The increment counter is progressed and;
b. Each 'slice' of the image completes its fadeOut before the next begins.
If there's an easy (or obvious) way of doing this, I'd love to hear it. I've been pulling my hair out for a while now trying to figure out why these (and other similar variations) aren't working.
HTML:
img class="bg" (10 instances of this)
(function () {
// --- Variation 1 ---
function effect() {
var i = 0,
var current = $(".bg_1:eq(" + i + ")"),
arrLength = $(".bg_1").length;
while (i < arrLength) {
current.fadeOut(1000, 0);
i++;
}
}
effect();
// --- Variation 2 ---
function effect() {
var i = 0,
var current = $(".bg_1:eq(" + i + ")"),
arrLength = $(".bg_1").length;
while (i < arrLength) {
current.fadeOut(1000, 0, function () {
i++;
});
}
}
effect();
})();
I think it may be a problem with the scope of the 'i' variable, or a conflict in jQuery at that depth of scope. Any possible solutions would be GREATLY appreciated!
Thanks.
Without seeing your html, it's a bit hard to answer, but here's a general way to animate multiple elements in sequence:
(function _loop(idx) {
var $elements = $('#wrapper .bg'), idx = idx % $elements.length;
$elements.eq(idx).fadeIn('slow').delay(2500).fadeOut('slow', function () {
_loop(idx + 1);
});
}(0));​
demo: http://jsfiddle.net/UU5AM/
Your var current will always be the same
try this:
function effect() {
var i = 0;
var arrLength = $(".bg_1").length;
while (i<arrLength) {
$(".bg_1:eq(" + i + ")").fadeOut(1000, 0);
i++;
}
}
effect();
Only now it will run as fast as the while loop goes. That means it will fade everything out almost immediately. You might want to run a setTimeout function for as long as the fadeOut goes:
var i = 0;
setTimeout(function(){
$(".bg_1:eq(" + i + ")").fadeOut(1000, 0);
i++;
}, 1000);
And ofcourse you will need to reset it when it reaches the end.
Edit:
Beat Richartz way, running the function again when the fadeOut is completed, is even better then the setTimeout.
You can use fadeOut's callback argument to provide it with a function which it will execute when the animation is completed. You can use this to raise the counter and (if necessary) animate the next element.
For example:
(function () {
function effect() {
var i = 0,
var current = $(".bg_1:eq(" + i + ")"),
arrLength = $(".bg_1").length;
var animateNext = function() {
current.fadeOut(1000, 0, function() {
i++;
if (i < arrLength) {
animateNext();
}
});
}
animateNext();
}
effect();
})();
As you can see, we've stored a reusable function in animateNext. We call it at the end of effect the first time to start the string of animation. After that, each next animation is started from the callback in fadeOut.
Your solutions are animating all the pictures at once. You have to install a recursive chain of events to do this:
// initial count value declared outside the function to not reinitialize
var count = 0;
function effect() {
// search the current image
var current = $(".bg_1:eq(" + count + ")");
// if there's an image, fade it out
if (current.length) {
current.fadeOut(1000, function() {
// increment the count;
count++;
// call the function recursively
effect();
});
}
}
// call the function
effect();
See it working with the JSFiddle here

Stopping function on event in javascript

i'd like to include three image galleries on one page. one is running two are paused.
On event should the running gallery stop and the clicked one be running.
How do I bring the "return (function().." be stopped?
cheers
mate
var delay = 2500;
var start_frame = 0;
var container = "willkommen";
function fokus(container) {0.5
new Effect.Appear('willkommen', { duration:, to: 0.3 });
new Effect.Appear('eintreten', { duration:0.5, to: 0.3 });
new Effect.Appear('reservieren', { duration:0.5, to: 0.3 });
new Effect.Appear( container, { duration:1, to: 1 });
var lis = $(container).getElementsByTagName('li');
for( i=0; i < lis.length; i++){
if(i!=0){
lis[i].style.display = 'none';
}
}
end_frame = lis.length -1;
setTimeout(fadeInOut(container, start_frame, start_frame,end_frame, delay, lis), delay);
}
function fadeInOut(container, frame, start_frame, end_frame, delay, lis) {
return (function() {
lis = $(container).getElementsByTagName('li');
Effect.Fade(lis[frame]);
if (frame == end_frame) { frame = start_frame; } else { frame++; }
lisAppear = lis[frame];
setTimeout("Effect.Appear(lisAppear);", { duration:0.5, from:0.5, to:1 } );
setTimeout(fadeInOut(container, frame, start_frame, end_frame, delay), delay + 3500);
})
}
You need to store the timeout id returned from setTimeout and pass it into the clearTimeout function.
I'm not sure exacly how you're invoking the fokus function, but if you want it to encapsulate logic in multiple places on one page you should use it as a constructor function.
function Fokus (container) {
...
this.timeout_id = setTimeout(fadeInOut(container, start_frame, start_frame,end_frame, delay, lis), delay);
this.cancel = function () {
clearTimeout(this.timeout_id);
}
}
var gallery = new fokus("willkommen");
gallery.cancel();
There's not a whole lot of context given with your code, but it looks like you're using global variables for everything; I urge you to look into anonymous, self-executing closures to prevent global namespace pollution.

Categories