Creating a for loop that loops over and over = - javascript

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

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)

Updating Dom on array element swaps for sorting visualiser Vue.JS

Vue noob here who will be most grateful for any advice.
I am trying to build a basic sorting algorithm visualiser that will display an array of integers as a bar chart and my goal is to have the program step through the comparison steps by changing the colors of the two values being compared before swapping them so there will be a slight delay to the user to make them easier to understand.
The issue I am currently having is that I cannot get the DOM to update on the array change. I know that Vue has some limitations when it comes to watching for arrays changes when set by index so I have been using the splice mutation which I understand should resolve it however my screen doesn't get updated until the entire array is sorted.
I have tried utilising setTimeout function to add in a delay incase it was just happening too quickly for me to see but that doesn't appear to resolve anything.
I tried this.$forceUpdate() that I have seen on some other posts but was unsuccessful with that option also. Another post recommended modifying the div to be displayed an hidden so I tried seeing if adding a 'v-if' and then changing the value to false and then back to true to hack it to update but no luck either.
Any help would be amazing. Here is a sample of the code I wrote.
bubbleSort(){
var is_sorted = false;
var counter = 0;
while(!is_sorted){
is_sorted = true;
for( let i = 0; i < (this.num_list.length - 1 - counter); i++){
this.show = false;
this.index_compare_val_1 = this.num_list[i];
this.index_compare_val_2 = this.num_list[i +1];
// check if values need to be swapped
if(this.num_list[i] > this.num_list[i + 1]){
this.swapNumbersInArray(i, i+1)
is_sorted = false;
}
//this.show = true
setTimeout(this.show = true, 50)
}
counter =+ 1
}
},
swapNumbersInArray(index_1, index_2){
var a = this.num_list[index_2]
this.num_list.splice(index_2, 1, this.num_list[index_1] );
this.num_list.splice(index_1, 1, a );
this.temp_list = this.num_list
this.num_list = this.temp_list
},
Solved this issue by switching approach by utilising a sleep promise that has a setTimeout and making the sorting algorithm function asynchronous.
It now steps through the animations of the algorithm at a speed that properly visualises the sorting process.
Code Below:
async bubbleSort(){
console.log("Running Bubble Sort")
var is_sorted = false;
var counter = 0;
while(!is_sorted){
is_sorted = true;
for( let i = 0; i < (this.num_list.length - 1 - counter); i++){
// set compared values for coloring
this.compare_val_1 = this.num_list[i];
this.compare_val_2 = this.num_list[i +1];
// check if values need to be swapped
if(this.num_list[i] > this.num_list[i + 1]){
this.swapNumbersInArray(i, i+1)
await this.sleep(5) // short delay so user can see the animation
is_sorted = false;
}
}
counter =+ 1
}
this.sorted = true; // changes color to finalColor
},
sleep(ms){
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
},

I am trying to stop my function from displaying the same object twice when clicking a button

I have for quite some time now been trying to figure out how I can stop my code to print the same quote twice.
Also, when every single object in the array has been printed out, I'd like for it to reset somehow. So that you can browse through the quotes once you've gone through all of them.
This is the essential parts of my code:
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
The printQuote function simply contains information that's accessing information from my array:
var randomObjectNumber = getRandomQuote();
var html = "<p class='quote'>"
+ quotes[randomObjectNumber].quote +
"</p>";
document.getElementById('quote-box').innerHTML = html;
One random object is displayed each time you click the eventListener:
function getRandomQuote () {
var randomObjectNumber = Math.floor(Math.random() * quotes.length );
return randomObjectNumber;
}
I have some ideas on how to do this and I have tried them but without success. I tried giving each object a boolean property but I can't really seem to assign each property a boolean value without messing the printQuote function up.
I also tried assigning the object displayed to a different array but the same problem occurred there.
I feel like there is some concepts around the eventListener that I don't fully understand, because every time I try to manipulate a displayed object I just end up changing every single object.
This is what a typical object in the array looks like by the way:
{quote : "Darkness is merely the absence of light"}
(I also have other properties assigned to the object but i feel like presenting them would be redundant)
If someone could explain, or give me a hint, on how to solve this problem I've been struggling with for some time.
Some hints would be greatly appreciated!
Have a nice day.
Sebastian.
EDIT: All code: https://jsfiddle.net/fusqb7hz/
Basically what you need:
Create a separate array that will store all quotes that you've already used.
Remove quote from initial array.
Check if you still have quotes in initial array, if not, get them back from backup array.
The problem is that you call addEventListener twice:
//Let's developers create multiple eventListeners without being redundant.
function onClicking (printFunction) {
document.getElementById('loadQuote').addEventListener("click", printFunction, false);
}
onClicking(printColor);
onClicking(printQuote);
by calling onClicking twice you make the click happen twice, so addEventListener is added twice, meaning one click counts as two.
Change the above code for this:
//Let's developers create multiple eventListeners without being redundant.
document.getElementById('loadQuote').addEventListener("click", function(){
printColor();
printQuote();
});
Here is the jsfiddle:
https://jsfiddle.net/fusqb7hz/3/
I think the easiest approach is to shuffle your quote array and then go through them one by one. This gives you the next "random" as yet unseen quote. The only part I'm not keen on is this shuffler (a derivation of Fisher Yates) modifies the original quote array. You might not care about that though.
// --------------------------------
// A bunch of quotes
// --------------------------------
var quotes = [];
quotes.push({quote : "Darkness is merely the absence of light"});
quotes.push({quote : "quote 2"});
quotes.push({quote : "quote 3"});
quotes.push({quote : "quote 4"});
quotes.push({quote : "quote 5"});
// --------------------------------
// --------------------------------
// Your favorite array shuffle utility
// --------------------------------
var shuffle = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
};
// --------------------------------
// --------------------------------
// construct a function to get a random unseen quote until
// all quotes have been seen. Then reset...
// --------------------------------
var getQuote = (function(quotes, shuffle){
var current = 0;
var get = function(){
if ( !quotes || !quotes.length ) { return ""; }
if ( current >= quotes.length ){ current = 0; }
if ( current === 0 ){
console.log("randomizing quotes...");
shuffle(quotes);
}
return quotes[current++].quote;
};
return get;
})(quotes, shuffle);
// --------------------------------
var printQuote = function(){
document.getElementById('quote').innerText = getQuote();
};
document.getElementById('loadQuote').addEventListener("click", printQuote, false);
<div id="quote"></div>
<button id="loadQuote">get quote</button>

While loop and setInterval()

I am trying to mix the initial string and randomly compare the string's elements with the right elements on the right indexes, and if true push them into a set, to reconstruct the initial string. Doing this I met the problem that while loop does nothing just crushng the browser. Help me out with this.
function checker() {
var text = document.getElementById("inp").value;
var a = [];
var i = 0;
while (a.length < text.length) {
var int = setInterval((function() {
var rnd = Math.floor(Math.random() * text.length);
if (text[rnd] === text[i]) {
a.push(text[rnd]);
clearInterval(int);
i++;
}
}), 100)
}
}
P.S. I need the setInterval() function because I need the process to happen in exactly the same periods of time.
So, you stumbled into the pitfall most people hit at some point when they get in touch with asynchronous programming.
You cannot "wait" for an timeout/interval to finish - trying to do so would not work or block the whole page/browser. Any code that should run after the delay needs to be called from the callback you passed to setInterval when it's "done".
In my answer its doing exactly what you want - creating exactly the same string by randomly mixing the initial, and also using setInterval. You didn't write where you want the result, so you have it written in the console and also in another input field with id output_string.
HTML:
<input id="input_string" value="some_text" />
<input id="output_string" value="" readonly="readonly" />
JavaScript:
function checker() {
var text = document.getElementById("input_string").value;
var result = '';
// split your input string to array
text = text.split('');
var int = setInterval((function() {
var rnd = Math.floor(Math.random() * text.length);
// add random character from input string (array) to the result
result += text[rnd];
// remove used element from the input array
text.splice(rnd, 1);
// if all characters were used
if (text.length === 0) {
clearInterval(int);
console.log(result);
document.getElementById("output_string").value = result;
}
}), 100);
}
checker();
DEMO
Honestly, I have no idea what you are trying to do here, but you seem to have lost track of how your code is operating exactly.
All your while loop does, is creating the interval, which is ran asynchronous from the loop itself.
In other words, the only way your while condition equates to false, is after multiple 100ms intervals have elapsed. 100 miliseconds is an eternity when comparing it to the speed of 1 loop iteration. We're looking at 1000s of iterations before your first setInterval even triggers, not something a browser can keep up with, let alone wait several of these intervals before you change a.length.
Try more like this:
function checker() {
var text = document.getElementById("inp").value;
var a = [];
var i = 0;
// start to do a check every 100ms.
var interv = setInterval(function() {
var rnd = Math.floor(Math.random() * text.length);
if (text[rnd] === text[i]) {
a.push(text[rnd]);
i++;
}
// at the end of each call, see if a is long enough yet
if(a.length > text.length){
clearInterval(interv); // if so, stop this interval from running
alert(a); // and do whatever you need to in the UI.
}
}, 100);
}
}

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