Counting unknown/dynamic array length of class element - javascript

I wrote a simple code/userscript to notify me about changes on a webiste:
function notifier(){
setTimeout(function () {
location.reload(true);
},60000)
}
function notiCounter() {
console.log("Counting notifications");
var noti = document.getElementsByClassName("notification");
for(var i = 0; i < 2; i++) {
if(noti[i].innerHTML != undefined) {
console.log(noti[i].innerHTML);
notifications++;
console.log("Notifications: " + notifications);
}
}
}
function notification(){
setTimeout(function () {
notiCounter();
if(notifications > 0){
document.title = "(" + notifications + ") new notifcations";
sound.play();
}
notifier();
},50)
}
notification();
The problem is, that the actual final number of noti[i] is unknown/dynamic and changes all the time, so if i < 2 is replaced with a higher number the for loop ends up in an infinite loop - and if I pick it too low (2 for example), data will gets lost if the actual number is above 2.
Any idea about that problem? Maybe it's really obvious and I can't see, as it is really late haha.

Rather than checking for i < 2, check for i < noti.length. Or you can iterate through using a for(var i in noti) type loop. Or better yet, if you just want the number of notifications directly, just use the value in noti.length

Related

Store score in a variable after an event

Desirable result: After the user choose an answer, I want to modify score variable in:
score += 1 if the answer is right either not changing at all if the answer is wrong.
Current result: For every choice user is making, the score remains the same: 0.
First, I store the paragraph that will be changed in question_paragraph and the button that will be clicked by user in next_button. Also, I stored the value(I put the attribute value on every input using the array notation - 0 first, 1 second etc.) in user_answer.
var question_paragraph = document.getElementById('question');
var next_button = document.getElementById('next');
var i = 0;
var user_answer = getCheckedValue(document.getElementsByName('choice'));
var y = 0;
var score = 0;
The getCheckedValue function will return the value attribute of my input if exists.
function getCheckedValue(radioObj) {
var radioLength = radioObj.length;
for(var z = 0; z < radioLength; z++) {
if(radioObj[z].checked) {
return radioObj[z].value;
}
}
return "Error!";
}
Here is the problem. The function works fine, except the isolated area. allQuestion is my object where I stored the questions, the possible answers and the right answer, correctAnswer(I don't included it here but works correctly). I put a conditional statement to increase y and code>score with one if the allQuestions[y].correctAnswer is qual with the value of the user_choice.
function changeQuestion() {
//PROBLEM
if(allQuestions[y].correctAnswer == user_answer){
score += 1;
y++;
} else{y++;}
//PROBLEM
i = (i < allQuestions.length) ? (i + 1) : 0;
if (i == allQuestions.length) {
i = 0;
return question_paragraph.replaceChild(document.createTextNode(allQuestions[0].question), question_paragraph.firstChild);
}
var newNode = document.createTextNode(allQuestions[i].question);
console.log(score);
return question_paragraph.replaceChild(newNode, question_paragraph.firstChild);
}
Finnaly, I called the addHandler function.
function addHandler(name, type, handler){
if (name.addEventListener){
name.addEventListener(type, handler, false);
} else if (name.attachEvent){
name.attachEvent("on" + type, handler);
} else {
name["on" + type] = handler;
}
}
addHandler(next_button, 'click', changeQuestion);
Well, something just appears to be funny here so far. First of all, I don't see any initialization to the variable y. If y is a global variable that is retaining its value, then maybe there is an issue with your object: allQuestions{}. Could you provide the code for building your object allQuestions{}? Without it, I don't think that I could fully answer this question, but I believe that is where your problem lies.
Oops, this was supposed to be a comment, not an answer, sorry...

Pausing JavaScript Asynchronous Loop for some time

I have a problem with pausing asynchronous JS loop from execution for some period of time.
I need it to pause, for example every 45th iteration so I came up with a simple code to help me determine when it happens:
if (i > 1)
{
var numba = i / 45;
if (isInteger(numba))
{
document.write('TIMEOUT START <br>');
setTimeout(function(){document.write('TIMEOUT END<br>');}, 540000);
}
}
function isInteger(x)
{
return x % 1 === 0;
}
And my async loop code is following:
var num = 150;
var asyncLoop = function(o)
{
var i=0;
var loop = function(){
i++;
if(i==o.length){o.callback(); return;}
o.functionToLoop(loop, i);
}
loop();//init
}
asyncLoop({
length : num,
functionToLoop : function(loop, i)
{
if (i==0){}
loop();
},
callback : function(){
}
});
First I tried to place this code for pausing loop inside the loop function however that didn't work and now I partly understand why. However every other way I tried failed also.
Does anyone know how to achieve what I'm trying to do?
Thanks in advance
Here's a snippet I whipped up.
It will call functionToLoop loops times, pausing for pauseTimeout milliseconds each pauseAt runs, then calls callback at the end.
function loopWithPause(functionToLoop, callback, loops, pauseAt, pauseTimeout) {
var n = 0;
function start() {
if(n + pauseAt > loops) pauseAt = loops- n;
for(var i = 0; i < pauseAt; i++) {
functionToLoop(n + i);
}
n += pauseAt;
if(n == loops) callback();
else setTimeout(start, pauseTimeout);
}
start();
}
Example:
loopWithPause(function(i){console.log(i)}, function(){console.log('done!')},10, 2, 2000);
Outputs:
0
1
(2 second pause)
2
3
(2 second pause)
4
5
(2 second pause)
6
7
(2 second pause)
8
9
done!
For your scenario the call will probably be:
loopWithPause(functionToLoop, callback, 150, 45, 540000);
This does what you're asking. Perhaps you can adapt it to your need. Paste it into your JavaScript console and watch it run forever.
var printNumbers = function(startingAt) {
var end = startingAt + 45;
for (i = startingAt; i < end; i++)
{
console.log(i)
}
window.setTimeout(function() { printNumbers(end); }, 1000)
}
printNumbers(0)
It's almost recursive, except that the recursion happens via the event loop with the time-out.
This carries state forward via the variable, to be used next time the function runs (alternatively use a global variable or closure to contain the state between function executions). It's the only way to do something like this, because JavaScript is single-threaded and you can't 'pause' without making the whole runtime grind to a halt.

Javascript : How can I add X elements to an array

I need to create an array including the first 100 prime numbers, here is my code:
var premier= [];
var nombre= premier.length;
function isPrime(n)
{
if(n < 2)
{
return false;
}
for(i=2; i<Math.sqrt(n); i++)
{
if(n%i===0)
{
return false;
}
}
return true
};
while(nombre<100)
{
var j=2
if(isPrime(j)==true)
{
premier.push(j);
}
j=j+1
}
I am a beginner in Javascript, but I have tested the isPrime function and it works fine even forlarge numbers.
but when I run the program I have:
FATAL ERROR: JS Allocation failed - process out of memory
I think this part is wrong:
while(nombre<100)
{
var j=2
if(isPrime(j)=true)
{
premier.push(j);
}
j=j+1
}
console.log(premier)
But I can't tell why
You are repeatedly setting j=2 every time the loop runs, and you never change nombre so the loop will never end. Note that JavaScript sets literal vaues by value, not by reference, so nombre = premier.length won't magically update.
Additionally, statements of the form if( x = true) will set x to true, and then pass the condition automatically. In this case, since x is a function call, it is invalid syntax.
Did you mean this?
var j = 2;
while(premier.length < 100) {
if( isPrime(j)) premier.push(j);
j++;
}

Javascript accidental closure

I have this piece of code on my website which counts the number of image and then output a list each time the user clicks on desired category.
The problem is, my image counter variable (noIMG) does not clear itself every time the function is called. I tried adding a reset(noIMG) at the end of the function but it seemed like a bad idea.
I did some research and i've stumbled upon articles about closures. After trying numerous methods to fix it, my code is still not acting the way I want it to.
function thumbCounter(){
var noIMG = $(".artwork img").size()+1;
for (var count = 1; count < noIMG; count++){
if (count == 1){
$('#list_here').append('<li class="active">' +count+ '</li>');
} else{
$('#list_here').append('<li>' +count+ '</li>');
}
}
};
If you mean you want to clear the list every time the function is called, then do it like this:
function thumbCounter() {
var noIMG = $(".artwork img").size() + 1;
var myList = $('#list_here'); // reference to list
myList.html(""); // clear the contents
for (var count = 1; count < noIMG; count++) {
if (count == 1) {
myList.append('<li class="active">' +count+ '</li>');
} else {
myList.append('<li>' +count+ '</li>');
}
}
};

Cannot confirm that element exists on the page when I clearly see it there

I'm using a function which utilizes jQuery in order to grab information from a JSON feed. The problem here is that from the feed I must pick 10 items that meet the criteria of being within the last year (31 billion milliseconds from the request for argument's sake) and I have to specify how many results I want from the feed with a variable 'maxRows' that is inserted into the URL. Here's the function...
function topTen(rows) {
$.getJSON("http://ws.geonames.org/earthquakesJSON?north=90&south=-90&east=-180&west=180&maxRows=" + rows,
function(json) {
var topTen = new Array();
var now = new Date();
var i;
for(i = 0; i < json.earthquakes.length; i++)
{
var time = json.earthquakes[i].datetime;
var then = new Date(time.replace(" ", "T"));
if(now - then < 31536000000) { topTen.push(json.earthquakes[i].eqid); }
}
if(topTen.length >= 10)
{
var html = "The Top Ten Earthquakes Of The Past Year<ol>";
for(i = 1; i <= 10; i++)
{
html += "<li id='number" + i + "' >" + topTen[i - 1] + "</li>";
}
html += "</ol>";
$('#top_ten').html(html);
}
});
}
Now the problem is that from the first request it is likely I will not get 10 results that meet my criteria. So in order to counteract this I try to put the function in a loop until another criteria is met. However, this always winds up failing because the getJSON function (or perhaps the callback) is asynchronous, meaning if I try something like
var rows = 10;
do{
topTen(rows);
rows += 10;
while(!document.getElementById("number10"))
The problem then becomes, however, that the function doing the actual work is not bound by the line-by-line timing of the loop and so the loop itself runs many, many, MANY times before any of the functions actually finish and the loop condition is met. So right now I'm trying to devise another approach that goes something like this
topTen(rows);
rows += 10;
pause(1000);
topTen(rows);
rows += 10;
pause(1000);
topTen(rows);
rows += 10;
pause(1000);
if(document.getElementById("number10"))
alert("There's 10!");
else
alert("There's not 10!");
The pause is basically just what it sounds like and takes in milliseconds. A simple comparison of an initial date object to later date objects in a loop that I copied and pasted. This works to keep the functions from firing off immediately after one another, but then the problem becomes that the if condition is NEVER met. I don't know what it is, but no matter how much time I allow for pausing, the getElementById function never seems to find the element with an id of 'number10' even though I can see it very clearly in Firebug.
I've have been crashing my browser SEVERAL times because of this problem and I am seriously getting PO'd and sick of it. If anyone could find a solution to this problem or even suggest an easier, more elegant solution, I would be eternally grateful.
PS - I've tried things like global variables and using recursion to call topTen() from inside the callback function and send in a larger 'rows' variable, but those don't work because it seems like the callback functions are in their own contained little world where 90% of the rest of my javascript doesn't exist.
You are doing this the wrong way...
You need to wait for one call to return before calling again. Lucky for you, you already have a function being called with it returns. So a simple change to that function and you are done.
var topTenList = new Array();
function topTen(rows) {
$.getJSON("http://ws.geonames.org/earthquakesJSON?north=90&south=-90&east=-180&west=180&maxRows=" + rows,
function(json) {
var now = new Date();
var i;
for(i = 0; i < json.earthquakes.length; i++)
{
var time = json.earthquakes[i].datetime;
var then = new Date(time.replace(" ", "T"));
if(now - then < 31536000000) { topTenList.push(json.earthquakes[i].eqid); }
}
if (topTenList.length < 10)
{
topTen(rows+10);
return;
}
else
{
var html = "The Top Ten Earthquakes Of The Past Year<ol>";
for(i = 1; i <= 10; i++)
{
html += "<li id='number" + i + "' >" + topTenList[i - 1] + "</li>";
}
html += "</ol>";
$('#top_ten').html(html);
}
});
}

Categories