javascript w/ jquery loop - javascript

im having a problem with my code, i have to make a loop, that each it loops, have to change add a class/change the color of something for just a while. i tried with a for and it didnt work, then i tried something like a loop using setinterval and it works better but still have something that is not working, it just adds the class/or toggle in that case first 1 element, and then maybe 2, then 3,etc and not 1 by 1 thanks
function runp(patron){
var x = 0;
var intervalID = setInterval(function () {
$("#container"+patron[x]).toggle(1).delay(1000).toggle(1).delay(1000);
if (++x === 20) {
window.clearInterval(intervalID);
}
}, 2000);
}
this is what i have: https://jsfiddle.net/dt8kxebg/
and this is what im trying to replicate: https://jsfiddle.net/jf0opams/

I think your problem is that you execute the runp() several times, because it is inside of a for loop. You should rather invoke the function just once after the loop, when your patron[] array is filled with random numbers (1-4).
The problem happens, because the for loop is super fast (few millisecs) filling your array with 20 random numbers. So you have invoked the animation/toggling function 20 times. This on/off behaviour takes 2 seconds and happens 20 times almost at the same time. You can see in my code in the browser console what the console.log() output to understand the behaviour better.
function start(patron, patronl){
while (patron.length<20){
patron.push(rand(1,4));
console.log('start: '+patron.length);
//runp(patron, patron.length);//old place
//readp(patron,//
}
runp(patron);//new place
}
function runp(patron, iteration){
var x = 0;
var intervalID = setInterval(function () {
$("#container"+patron[x]).toggle(1).delay(1000).toggle(1).delay(1000);
//see how 20 outputs come at once, if runp() is inside for loop
console.log('togglewait: '+x, 'start: '+iteration);
if (++x === 20) {
window.clearInterval(intervalID);
}
}, 2000);
}

Related

Why can I not implement a method here?

Here is the code:
function startAnimation() {
setInterval( doAnimationStep, 40) // 40 ms = 25 frames per second
this.stopAnimation= stopAnimation(){
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
}
}
My IDE does underscore the curly braces:
I started programming last week and I'm really struggling with methods now...
You can only have methods in classes and objects. However you can create functions within functions. Therefore you could change your code to the following and have similar behavior.
function startAnimation() {
const setInterval = (doAnimationStep, 40) // 40 ms = 25 frames per second
const stopAnimation = () => {
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
}
}
On another note: I am not sure what you're trying to accomplish with this line:
document.getElementById("buttonStop")= setInterval(doAnimationStep, 0)
setInterval() returns a non-zero number and getElementById() returns an Element and you're assigning one to the other.

How to rotate from different titles

No, I am not talking about <h1> or something like that. I am talking about the <title> element. I created a function, that delays every .5 seconds or so, and changes titles.
The script I have developed reads the array, which includes the titles, and rotates from it. The first time I have ran it, I did not use setTimeout, and it ran instantly, I couldnt read anything.
But when I tried using the setTimeout function, it started to return undefined. What is the problem with this code?
for(var i = 0; i < titles.length ; i++){
setTimeout(function () {document.title = titles[i]}, 500)
}
You're going about this the wrong way (IMO). Using a loop you'll fire off all your timeouts at once. You'd be better off using setInterval
let i = 0, titles = ['title1', 'title2', 'title3'];
let int = setInterval(() => {
document.title = titles[i];
console.log('doc.title: ', document.title);
if (i++ >= titles.length - 1) clearInterval(int);
}, 500)

Creating a for loop that loops over and over =

So I have a weird problem (as I can do this using dummy code, but cannot make it work in my actual code) -
The concept is simple - I need a for loop that upon hitting its max "I" number reverts "I" to 0 again and creates a loop over and over -
DUMMY CODE:
for(i=0;i<10;i++){
console.log(i);
if(i === 10){
i = 0
}
}
Now for the longer code (sorry)
function reviewF(){
// add ID to each of the objects
reviews.forEach((e, i)=>{
e.id = i
})
// get the elements to be populated on page
var name = document.querySelector('p.name');
var date = document.querySelector('p.date');
var rating = document.querySelector('.rating_stars');
var review = document.querySelector('p.review_content_text');
// reverse the array - so the newest reviews are shown first (this is due to how the reviews where downloaded)
var reviewBack = reviews.slice(0).reverse();
// start the loop - go over each array - take its details and apply it to the elements
/**
* THIS IS WHAT I WOULD LIKE TO LOOP OVER FOREVER
*
* **/
for (let i = 0; i < reviewBack.length; i++) {
(function(index) {
setTimeout(function() {
// document.getElementById('reviews').classList.remove('slideOut')
name.classList.remove('slideOut')
date.classList.remove('slideOut')
rating.classList.remove('slideOut')
review.classList.remove('slideOut')
name.classList.add('slideIn')
date.classList.add('slideIn')
rating.classList.add('slideIn')
review.classList.add('slideIn')
name.innerHTML = reviewBack[i].aditional_info_name;
date.innerHTML = reviewBack[i].Date;
rating.innerHTML = '';
review.innerHTML = reviewBack[i].aditional_info_short_testimonial;
if(reviewBack[i].aditional_info_short_testimonial === 'none'){
reviewBack.innerHTML='';
}
var numberOfStars = reviewBack[i].aditional_info_rating;
for(i=0;i<numberOfStars;i++){
var star = document.createElement('p');
star.className="stars";
rating.appendChild(star);
}
setTimeout(function(){
// document.getElementById('reviews').classList.add('slideOut')
name.classList.add('slideOut')
date.classList.add('slideOut')
rating.classList.add('slideOut')
review.classList.add('slideOut')
},9600)
}, i * 10000)
})(i);
// should create a infinite loop
}
console.log('Loop A')
}
// both functions are running as they should but the time out function for the delay of the transition is not?
reviewF();
EDITS >>>>>>>>
Ok so I have found a hack and slash way to fix the issue - but its not dry code and not good code but it works.....
this might make the desiered effect easier to understand
reviewF(); // <<< this is the init function
// this init2 function for the reviews waits until the reviews have run then
// calls it again
setTimeout(function(){
reviewF();
}, reviews.length*1000)
// this version of the innit doubles the number of reviews and calls it after that amount of time
setTimeout(function(){
reviewF();
}, (reviews.length*2)*1000)
From trying a bunch of different methods to solve this issue something I noticed was when I placed a console.log('Finished') at the end of the function and called it twice in a row (trying to stack the functions running..... yes I know a horrid and blunt way to try and solve the issue but I had gotten to that point) - it called by console.log's while the function was still running (i.e. the set time out section had not finished) - could this have something to do with it.
My apologies for the rough code.
Any help here would be really great as my own attempts to solve this have fallen short and I believe I might have missed something in how the code runs?
Warm regards,
W
Why not simply nest this for loop inside a do/while?
var looping = True
do {
for(i=0;i<10;i++){
console.log(i);
}
if (someEndCondition) {
looping = False;
}
}
while (looping);
I would think that resetting your loop would be as simple as setting "i = 0" like in the dummy code. So try putting the following into your code at the end of the for loop:
if(i === 10){
i = 0;
}

Problems using setInterval and clearInterval more than once

I'm getting confused with what's happening here. The quiz works fine the first time. After the first play, though, I get all sorts of problems. I want to click the same button,"#start2", to start and also restart the quiz, ie clear the timer, put all variables back to 0 etc, and display the first question. As if the page had been refreshed, basically.
Instead, I'm getting faster ticking, the timer is incrementing on correct guess and so on. Horrible.
I've used modulo to measure how many times the "#start2" div is clicked. On first click, start timer. On second click - I want to reset the timer. Third click - start timer, and so on.
Any help is massively appreciated.
var n = 0;
var x = 0;
var p = 0;
var incTime;
function a(n) {
var x,y,z;
x = Math.floor((Math.random() * 3))
if(x == 0){y = 1; z = 2}else if(x == 1){y = 0; z = 2}else{y = 0; z = 1}
$("#question_holder2").text(questions[n].q);
$(".answer_holder2").eq(x).text(questions[n].a).data('answer', 'a');
$(".answer_holder2").eq(y).text(questions[n].b).data('answer', 'b');
$(".answer_holder2").eq(z).text(questions[n].c).data('answer', 'c');
}
$(document).ready(function() {
//timing element
function startTimer(x){
$("#start2").text(x);
}
$("#start2").click(function(){
var setTimer;
p++;
//if it's been clicked before
if(p%2 === 0){
clearInterval(setTimer);
$("#start2").text("Start");
n = 0;
x = 0;
a(n);
alert("okay");
}else if(p%2 !== 0){
//never been clicked before
a(n);
setTimer = setInterval(function(){startTimer(x=x+1)}, 1000);
$('.answer_holder2').click(function() {
//correct answer given
if ($(this).data('answer') === 'a') {
n++;
if (n < questions.length) {
a(n);
} else {
alert("End of quiz!");
clearInterval(setTimer);
$("#start2").text("You took " + x + " seconds, you answered " + n + " questions correctly, with - incorrect answers given.");
x = 0;
n = 0;
a(n);
}
}else{
//incorrect answer given
$(this).fadeTo(1000,0.4);
var timeString = $("#start2").text();
var incTime = (timeString * 1) + 5;
$("#start2").text(incTime);
startTimer(incTime);
x = incTime;
};
});
};
});
});
You have this:
$("#start2").click(function(){
var setTimer;
p++;
//if it's been clicked before
if(p%2 === 0){
clearInterval(setTimer);
//....
In this case, when you set to the clearInterval line, setTimer will always be 0, and not the id of a running timer. So this is not actually stopping any timer. If you don't stop the timer it will continue to run. So the function here:
setTimer = setInterval(function(){startTimer(x=x+1)}, 1000);
Will continue to run. So the next time you create a timer, you now have two timers updating x and it'll look like it's running faster.
Try this:
$(document).ready(function() {
var setTimer;
$("#start2").click(function(){
// the rest of your click handler code...
});
//timing element
function startTimer(x){
$("#start2").text(x);
}
}
Your setTimer variable needs to exist in a scope outside of your click handler. As you had it you were declaring a new variable every time so when you try and clear the timer, you are not actually clearing the timer.
Also: freakish's point about how you are reattaching the click handler is also a problem. You need to fix that too.
The answer is that bad things happen because of this:
$("#start2").click(function(){
// some code...
$('.answer_holder2').click(function() {
// some code...
});
});
When you click on #start2 new handler is attached to .answer_holder2. So after for example 3 clicks, .answer_holder2 has 3 handlers attached to it and when you click on it all 3 fire.
You're code is a bit complicated and I'm not going to give you a solution how to fix that. But I can give you a hint. Put inner .click outside of outer .click. You will have to change some code probably, but that has to be done.
EDIT What you could try ( as a fast fix, but not necessarly good ) is adding this:
$('.answer_holder2').off( "click" ).click(function() {
Additonally have a look at Matt's answer.

While loop only returning final result

while (counterInc < counter) {
window.setTimeout(function () {
$('#results').text(counterInc);
}, 3000);
counterInc++;
}
This code should increment the tag with ID results every 3000 milliseconds instead the while loop is running and returning the final result. For example instead of changing the text to 1, 2, 3, 4, 5,..n, it is changing the text to n. How would one have the loop update the text field every 1000 milliseconds with each increment instead of only the final result?
Try this
var counterInc = 0;
var counterMax = 10;
var timeoutId = window.setInterval(function() {
$('#results').text(counterInc++);
if (counterInc >= counterMax) {
window.clearInterval(timeoutId);
}
}, 500);​
http://jsfiddle.net/GufCs/4/
What was happening was you timeout updated the cell every three seconds, however, your loop can run through a ridiculous amount of numbers in 3 seconds, so it's long since complete by the time the function in setTimeout had run.
This will trigger the function every 500ms (change to 3000ms for your purposes) and only then will it increment the counterInc. Add it clears the Interval when it reaches counterMax.
The problem is that setTimeout() acts as an "independent thread". You set it and it executes once after the specified amount of time. In the mean time the "main thread" keeps running: so your counter will get increased in the meantime.
To understand the problem you need to understand what a closure is.
Here you want each time to pass a certain value not the one computed at the end of the loop scope.
So compute the value at the moment you declare the setTimout rather than when it is call you can do as follow: http://jsfiddle.net/lechevalierd3on/jhYm3/
var counter = 10;
var counterInc= 0;
while (counterInc < counter) {
window.setTimeout(function () {
var inc = counterInc;
return function(){
$('#results').text(inc);
}
}(counterInc), 1000 * counterInc);
counterInc++;
}​
while (counterInc < counter) {
window.setTimeout(function () {
$('#results').text(counterInc);
}, 3000 * counterInc++);
}

Categories