JavaScript / Jquery Rotating Slider - Double Delay Issue - javascript

with some help I have created a rotating slider using jquery and CSS3, and it seems to be working great except for one thing... The first 'slide' seems to have double the delay on the first play through. Can anyone shed some light on why this might be happening? Any help would be greatly appreciated...
var i = 0;
var z = 0;
delay = 5000;
var el = $('#scroll-script');
var ql = $('#info-box');
var classesb = ['fp-info-one', 'fp-info-two', 'fp-info-three', 'fp-info-four'];
var classes = ['fp-slide-one', 'fp-slide-two', 'fp-slide-three', 'fp-slide-four'];
var interval = setInterval(function () {
el.removeClass().addClass(classes[i]);
i = (i + 1) % 4;
ql.removeClass().addClass(classesb[z]);
z = (z + 1) % 4;
}, delay);

Your anonymous function, the one inside the setInterval, is waiting the same amount of time (your delay) to run initially. You can either:
1) change the anonymous function into a named function, and run that once before executing your interval
2)Run these lines before the setInterval method. Just to emulate that the code inside the anonymous function once.
el.addClass(classes[3]);
ql.addClass(classesb[3]);
You can look inside this fiddle, and see some solutions I have provided.
http://jsfiddle.net/G7NdU/4/

Related

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;
}

Javascript using a For Loop with setTimeout (or another delay)

I apparently don't fully understand how the setTimeout function works in Javascript:
function move() {
var a;
for(a = 0; a < 101; a++){
setTimeout(function(){
block.style.marginTop = (750 - a) + 'px');
}, 1000);
}
for(a = 0; a < 101; a++){
setTimeout(function(){
block.style.marginTop = (650 + a) + 'px');
}, 1000);
}
}
I have tried writing this out in many different ways, but the For Loops always execute instantly every single time. How can I make a For Loop wait for 1 second between each value of 'a'? So, when a = 0, the code executes and then waits for 1 second before running when a = 1, etc. until the first For Loop is finished, then the second For Loop executes in the same way.
Also, is there a more efficient way of doing this than using setTimeout? Like a way of just writing
sleep(1000);
or something like that. This whole setTimeout feature seems very overly complicated if it is the only way of producing delays in javascript. I tried this once but it didn't work at all in any way
await sleep(1000);
Any help with Timeouts and delays in Javascript, especially within a loop, would be greatly appreciated!
You may find value in the answer I posted here. That will explain setTimeout in loops a little more.
Separately, you may want to explain what you are trying to accomplish. It looks like you are either
trying to move an element one pixel per second
trying to move an element ~100 pixels after one second
For the first option I would use CSS Transitions instead. You'll have a lot more flexibility over how the element moves and you only need to dictate the direction and distance.
For the second option, you could toss the loop and keep the stuff inside, setting the new marginTop to the full value after some timeout.
setTimeout(function(){
block.style.marginTop = (750 - a) + 'px');
}, 1000);
this part of your code use 'a' variable after 1000 miliseconds. in this time 'a' is 100, because your loop not stoped for run setTimeout function, and it happened because javascript is asyncronous.
one solution for solving this problem in js is using recursive functions. if is not necessary to use for loop, you can use this code:
var a = 0;
function my_loop(a) {
if (a < 101) {
setTimeout(function() {
block.style.marginTop = (750 - a) + 'px');
my_loop(a);
}, 100);
a++;
}
}
my_loop(a);
but if you want do your question's job, i seriously recommened you to use CSS.
As #squint mentioned, you can use setInterval for your task.
Here's an example:
// create an element
const width = 10;
const el = document.createElement('div');
el.setAttribute('id', 'main');
document.body.appendChild(el);
el.style.width = width + 'px';
// question-relevant code starts here
const a = [...Array(101).keys()]; // fancy way to create [0, 1, 2, 3, ...]
const it = a[Symbol.iterator](); // for convenience
const int = setInterval(() => {
const { value, done } = it.next(); // next iteration
if (done) { clearInterval(int); return }; // finished?
el.style.width = width + value + 'px'; // adjust width
}, 10);
#main {
height: 100px;
width: 10px;
background: green;
}

How can I ignore deceleration from event.acceleration in JS?

I'm trying to have an event occur when the phone first starts moving. This triggers just fine. However, I am running into a problem: deceleration is measured similarly to acceleration. When I stop moving the device, I see another spike. Any suggestions on how to ignore that second spike?
The following code gives me "huzzah!" when I first move the phone and when I stop moving it. I only want the trigger on the first movement. I got the pertinent functions and most of the variables defined here. Not the full extent of the script, but all the parts of this functionality.
var elmt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var acceleration = eventData.acceleration;
var speed = 0;
speed = round(acceleration.y);
elmt.splice(0,1);
elmt.push(speed);
speedSmoothed=elmt.average();
//Rounding function
function round(val) {
var amt = 10;
return Math.round(val * amt) / amt;
}
//Averaging function for the array
Array.prototype.average=function(){
var sum=0;
var j=0;
for(var i=0;i<this.length;i++){
if(isFinite(this[i])){
sum=sum+parseFloat(this[i]);
j++;
}
}
if(j===0){
return 0;
}else{
return sum/j;
}
}
//trigger
if (speedSmoothed>1.5){
console.log("Huzzah!");
}
a few hours of thinking later, I got a little crafty. Enough to reliably behave like I want it to anyway.
if (speedSmoothed>1.5 && elmt[0]>elmt[4]){
console.log("Huzzah!");
}

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.

Categories