Javascript setTimeout Parameter Issue (The I'm Using an Anonymous Function Version) - javascript

I can't believe that I'm having an issue with this. My setTimeout is:
setTimeout(function(){showContent(entries, 0);}, 500);
I also tried:
(function(entries, index){
clear_show_content = setTimeout(function(){
showContent(entries, index);
}, 500);
})(entries, 0);
and in showContent(entries, index) index is undefined. Please tell me I'm just missing something obvious here.
EDIT: This code is causing so many problems tonight :)
var clear_show_content;
function showContent(json){
var entries = json;
$('#content').html('');
if(checkIfNoneEntered(entries))
$('#content').append('<div class="entry">No Alumni Entered Yet!</div>');
else if(checkIfNoMatches(entries))
$('#content').append('<div class="entry">No Matches Found!</div>');
else if(checkIfError(entries))
$('#content').append('<div class="entry">There was an error!</div>');
else {
clearTimeout(clear_show_content);
$('#content').append('<table border="2" id="content_table" width="50%">');
var filler = '<img width="1" height="1" />';
clear_show_content = setTimeout((function(){showContent(entries, 0);}),
500);
}
}
function showContent(entries, index){
if(index < 0)
return;
stop = index + 10 > entries.alumnus.length ? entries.alumnus.length : 10;
start = new Date();
for(allIndex = index; allIndex < stop; allIndex++){
}//This is where it becomes proprietary, but I highly doubt the issue is after here
EDIT 2: Here's a jsFiddle of the issue. It's not working on my browser (Chrome 16) and I don't currently have access to any other browser. I don't think that's the issue though, as I've written code like this hundreds of times. http://jsfiddle.net/eygraber/NduqY/1/

You're defining your showContent function twice...

Both your functions are called 'showContent' which means when you try to call the first one, you're really calling the second one because the first is overwritten.
When you check if index is undefined, check what's in entries. I bet it's the json you meant to pass to the first function.

Related

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

recursive function with multiple parameters in javascript/reactjs

I am writing some react code, in which I build a list of diagnoses. These diagnoses are build dynamically, so one can add sub diagnoses and attributes to them by clicking them. Therefore, I want to know where some potential diagnosis is placed in my list, and therefore when creating a new diagnosis, I give it a path as an attribute, which I can then use to navigate to it from the list.
I want to be able to set an attribute 'showRequirements' to a given diagnosis, and for this I implement the following two functions:
onClick = (path) => () => {
let currentDiagnosis = this.state[path[0].type][parseInt(path[0].key, 10)];
if (path.length > 1) {
this.showRequirementsFromPath(path, currentDiagnosis.algorithm.children, 1)
}
else {
currentDiagnosis.showRequirements = !currentDiagnosis.showRequirements;
}
this.setState({
[this.state[path[0].type][parseInt(path[0].key, 10)]]: currentDiagnosis,
})
}
showRequirementsFromPath = (path, diagnosis, counter) => {
if (counter < path.length) {
diagnosis[path[counter].key].showRequirements = true;
this.showRequirementsFromPath(path, diagnosis[path[counter].key], counter + 1);
}
else {
diagnosis.showRequirements = !diagnosis.showRequirements;
}
}
The onClick works when the path has length 1, so I believe the problem is in the showRequirementsFromPath function. If I run this with a path of length > 1, the app crashes, and I get the error message 'Too much recursion'. However, if I delete the diagnosis.showRequirements = !diagnosis.showRequirements from the else in showRequirementsFromPath, the app doesn't crash, and it does everything perfectly besides setting the attribute showRequirements.
This is my first post in here, so please tell if I'm breaking some guidelines/what I can do better in future posts.
Thanks in advance!
Edit: As asked, the type of path[0].key is String. Note that path[counter].key is an integer when counter > 0.
Update: I am so sorry, I just found out that the problem was elsewhere in the code. I believe the code I have posted is actually correct.

Replace contents of <div> in a loop while waiting

I'm having difficulty figuring out my issue, or even finding solutions for it, which leads me to believe I may be going in the wrong direction.
On a cshtml page I have an ajax function tied to a button click. That routes back to my controller and a json string array is returned back to the client.
On the page itself I have <pre id="replaceMe">***</pre> defined. I am attempting to iterate through the json array doing $("#replaceMe").replaceWith('<pre id="replaceMe">' + data[i] + '</pre>');
Technically speaking this works, but only in the sense that the last update is visible. I might as well just go straight to the last element of the array.
I've tried using setTimeout to no avail, no changes and then suddenly the last element is displayed. I've found some sleep like functions that mimic the same basic behavior, all with similar results. I did see some recommendations for an async sleep, but none of my browsers seem to like the async and give me an error about a missing ;.
I then thought I could do something like
function updateSection(data) {
for (var i = 0; i < data.length; i++){
var section = $("#replaceMe");
section.fadeOut(500);
section.replaceWith('<pre id="replaceMe">' + data[i] + '</pre>');
section.fadeIn(500);
}
}
That however has the same end result. No apparent change and then suddenly it's the last element in the array.
I'm clearly going about this wrong, otherwise I'd find an example fairly readily I think, so what should I be doing instead?
To clarify and sum up, I want to replace the content of the <pre></pre> with text that's contained in an array. I want each iteration to be visible long enough for a human to see it and observe the changes (~1000ms) before going to the next iteration.
If, for example the array contains "Tom", "Dick", "Harry", then I would like for the page to have
<pre id="replaceMe">Tom</pre> for 1 second, then that element is replaced with
<pre id="replaceMe">Dick</pre> for 1 second, then that element is replaced with
<pre id="replaceMe">Harry</pre>
I am NOT looking for
<pre id="replaceMe">Tom</pre>
<pre id="replaceMe">Dick</pre>
<pre id="replaceMe">Harry</pre>
setTimeout in a for loop runs after the for loop execution completed. so, you always see the last value. to solve this, you can use $.each method which provides a callback function or use an Immediately Invoked Function Expression.
more detailed info: https://codehandbook.org/understanding-settimeout-inside-for-loop-in-javascript/
var data=[];
for(var i=0; i<10; i++){
data.push(i+' lorem ipsum doloret');
}
$.each(data, function(i, el){
setTimeout(function(){
$("#replaceMe").replaceWith('<pre id="replaceMe">' + data[i] + '</pre>');
},500 + ( i * 1000 ));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="replaceMe">***</pre>
You can do that using setInterval function:
var words = ['interating', 'and', 'replacing', 'text'];
var replace = document.querySelector('#replace');
var count = 0;
function replaceText() {
replace.innerHTML = words[count];
if(count === words.length - 1)
count = 0;
else
count++;
}
setInterval(replaceText, 1000);
Updating:
You don't need to replace all the element, you can replace only the content, using the atribute innerText.
//pass in the data to loop over, and the index to show
function updateSection(data, index) {
//get a reference to the section
var $section = $('#replaceMe');
//fade out the section over 500 milliseconds, then perform callback on finish
$section.fadeOut(500, () => {
//change the text
$section.text(data[index]);
//fade in the section over 500 milliseconds, and then advance the index
//use modulus to reset the index to 0 when it reaches beyond the array
$section.fadeIn(500, () => updateSection(data, ++index % data.length));
});
}
updateSection(['Tom', 'Dick', 'Harry'], 0);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="replaceMe">***</div>

Create variables on the fly

Im creating code snippets dynamicly:
var gg = setInterval(function() {
if($('p:visible').length > 0) {
$('p').trigger('click') ;
clearInterval(gg);
}
},500);
The code works. The problem is that I create the same code snippets with different selectors:
var gg = setInterval(function() {
if($('input:visible').length > 0) {
$('input').trigger('focus') ;
clearInterval(gg);
}
},500);
So when I put(create) these codes together, the whole thing goes in to some loop and it doesn't work anymore, take a look at this example: JsFiddle
The problem is that I assign the same variable (gg) to the codes. So my question is: How do I create different variables every time I create these code snippets? I tried some things with var x=x++ but I can't get it to work.
Here are two ways of accomplishing what you want to do (dynamic variables). The first is evaling a string.
(There are a ton of articles out there that will explain why this is bad. But, for the sake of being complete, I'm providing this example...maybe as an example of what not to do ;)
A function that creates variables based on a string you pass in, and then using that eval'd variable would work. Something like:
function varMaker(str){
// Nothing fancy...
var token = Math.floor(new Date().getTime() * Math.random(10));
// Defining variable with no var for global scope (bad)
return eval(str + '_' + token + ' = undefined;');
}
Here's a quick/dirty fiddle example (no function maker, just an eval'd string): http://jsfiddle.net/D3wZ7/
The second, cleaner approach is using square bracket notation (and what I would recommend). Something like this:
window['gg' + randomized_string] = setInterval(..)
Note: Once you've defined the variable, you can reference it as you normally would as such:
window['my_cool_variable' + 1] = "stack";
alert(my_cool_variable1); //alerts "stack"
Here's a fiddle demonstrating this: http://jsfiddle.net/ZmGH5/
Good luck!
Simply put the snippets in anonym wrapper functions so that the variable gg is not global anymore:
(function(){
var gg = setInterval(function() {
if($('input:visible').length > 0) {
$('input').trigger('focus') ;
clearInterval(gg);
}
},500);
})();
(function(){
var gg = setInterval(function() {
if($('p:visible').length > 0) {
$('p').trigger('click') ;
clearInterval(gg);
}
},500);
})();
(These Functions are executed automatically...)
var gg= [];
gg[0] = setInterval(function() {
if($('p:visible').length > 0) {
$('p').trigger('click') ;
clearInterval(gg[0]);
}
},500);
gg[1] = setInterval(function() {
if($('input:visible').length > 0) {
$('input').trigger('focus') ;
clearInterval(gg[1]);
}
},500);
so go on like this way. You can create lots of by using array.
in that other snippet change
var gg =...
to var hh =...
and then clearInterval(hh)

cannot get a variable to pass from function called onclick

I am calling a function onclick secVar(sec1); which should run it through the script below, but it does not seem to be doing so, can someone tell me what I am doing incorrectly. I am new to javascript, and only have a little experience into scripting, and this code seems to be doing less and less of what I want it to.
<script type="text/javascript">
var sec1=0;
var sec2=0;
var sec3=0;
function secVar(){
if(sec1) {
sec1++;
document.getElementById('sec1text').innerHTML = sec1;
}
if(sec2) {
sec2++;
document.getElementById('sec2text').innerHTML = sec2;
}
if(sec3) {
sec3++;
document.getElementById('sec3text').innerHTML = sec3;
}
}
function largestVar(){
if (sec1 >= sec2 && sec1 >= sec3) {
//a
document.getElementById('rig').innerHTML = 'Test1';
} else if (sec2 >= sec1 && sec2 >= sec3) {
//b
document.getElementById('rig').innerHTML = 'Test2';
} else {
//c
document.getElementById('rig').innerHTML = 'Test3';
}
}
</script>
If this helps, The old code was the code below, before I tried to add in the script to determine the largest of the variables. It was incrementing the variables onclick, but no longer so. The onclick contained sec1Var() at that point.
<script type="text/javascript">
var sec1=0;
var sec2=0;
var sec3=0;
function sec1Var(){
sec1++;
document.getElementById('sec1text').innerHTML = sec1;
}
function sec2Var(){
sec2++;
document.getElementById('sec2text').innerHTML = sec2;
}
function sec3Var(){
sec3++;
document.getElementById('sec3text').innerHTML = sec3;
}</script>
If someone can explain to me what I am doing wrong I would greatly appreciate it.
I think it's hard to tell what your intention is. Sparticus has it right IF what you're trying to do is see if sec1, 2, and 3 are currently true or false (0 or 1). Since they are currently false, the code will never do anything as Sparticus correctly points out.
However, I'm not convinced that's actually what you MEAN to do. It looks like the condition you want to check is whether or not you're trying to increment sec1, 2, or 3. In other words, "If you are passing me sec1, increment it and update a piece of HTML".
But variables don't work that way. When you say secVar(sec1) what you are actually saying is `secVar(0)'. I don't think that's your intention.
So, a big waste of my time if I'm wrong, but because I'm already rolling along, let's pretend I'm right:
secVar needs to be able to accept a parameter, but right now you've declared it void. Changing it to accept a parameter is a first step:
function secVar(param) { ... };
But this still won't do anything. Because when you're still passing it "0" with your existing syntax. You need to pass it something that can be checked, like a string:
secVar('sec1');
When you do this, you can now update your conditions to check which string is being passed
if (param === 'sec1') { ... }
Here's a fiddle: http://jsfiddle.net/ch4yk/
Notes:
The fiddle includes jQuery just for easy brute-force event binding on the buttons. It's just an example. You don't need jQuery; bind your events however you want.
It is currently not doing anything with the largest value function, even though the code is in the fiddle
None of your counters will increment in this implementation.
When secVar() gets run, all the counters are at zero. They never increment because they start at zero.

Categories