Javascript accidental closure - javascript

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

Related

My global variables keep refreshing when I load the script, is there any way to stop this?

I'm trying to get a prototype for a system finished, however I couldn't find a way to stop my global variables initializing when I reload the script. When I'm writing my full system I will be making use of localStorage etc, but for now I'm just trying to find a quick fix to stop the variables and functions from executing every time I load the script.
$(function() {
questions = [];
count = 0;
addQuestions();
var originalHtml = document.body.innerHTML;
$(document).ready(createWebpage);
$(document).ready(createAnswerPage);
function Question(questionText, possibleAnswers, chosenAnswer) {
this.questionText = questionText;
this.possibleAnswers = possibleAnswers;
this.chosenAnswer = chosenAnswer;
}
function addQuestions() {
var question1 = new Question(
"Do you have or are you being treated for high blood pressure?",
['Yes','No'],
""
);
var question2 = new Question(
"Within the last year, have you had chest pain or pressure with activity such as walking or climbing stairs?",
['Yes','No'],
""
);
var question3 = new Question(
"Do you currently take medication to prevent or reduce agnia (chest pain from the heart)?",
['Yes','No'],
""
);
var question4 = new Question(
"Have you ever had a heart attack?",
['Yes', 'No'],
""
);
questions.push(question1);
questions.push(question2);
questions.push(question3);
questions.push(question4);
}
function submitFunction() {
if ($('input[name=answerValue]:checked', '#buttons').val() != null) {
questions[count].chosenAnswer = $('input[name=answerValue]:checked', '#buttons').val();
console.log( questions[count].chosenAnswer);
count++;
if (count < questions.length) {
document.body.innerHTML = originalHtml;
createWebpage();
} else {
location.href= '../src/answerpage.html';
}
} else {
alert("Please select an option");
}
}
function createAnswerPage() {
for (var i = 0; i < questions.length; i++) {
$('#question_section').append("<h1>" + questions[i].questionText + "</h1>");
$('#answer_section').append("<h1>" + questions[i].chosenAnswer + "</h1>");
console.log(questions[i].chosenAnswer);
}
}
function createWebpage() {
$('#question_text').append("<h1>" + questions[count].questionText + "</h1>");
console.log("questions");
for ( var index = 0; index < questions[count].possibleAnswers.length; index++) {
console.log(questions[0].possibleAnswers[index]);
$('#buttons').append("<input type='radio' name = 'answerValue' value=" + questions[count].possibleAnswers[index] + ">" + questions[count].possibleAnswers[index] + "<br>");
}
$('#answer_text').append("<br> <br> <br>");
$('#answer_text').append("<button id = 'nextPage'>Next</button>");
$('#nextPage').bind("click",submitFunction);
}
});
It is in the submit function where I load the new webpage and I am trying to use questions[i].chosenAnswer when the script reloads, but every time I run the script it is making me run the addQuestions() function which replaces all the objects in my array with the original data.
First of all, read up: Why are global variables considered bad practice?
A quick fix in your case would be to use HTML5 localStorage.
Example:
window.localStorage.setItem('myCat', 'Tom'); // save data
window.localStorage.getItem('myCat'); // get data
Here, you are using myCat as the key/variable.
Window.localStorage - MDN docs

Counting unknown/dynamic array length of class element

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

Run a for loop. Increment the value; exit and begin loop again with new value

I want to run a loop. I want it to excecute it 16 times like,
for (var i = 0; i <= 15; i++) {
alert(i);
}
I want this loop to run on clicking a button. But the loop should only return the first value of i and then exit. Like this,
for (var i = 0; i <= 15; i++) {
alert(i);
exit();
}
What I am confused with is, whenever I click the button I want this loop to run-only once-but with the value being incremented by one. The whole idea is to alert the i value on each click of the button but incremented by one each time. I think even my use of for loop also is not making any sense. Or is my whole logic wrong. I think I am doing something more complex where something simple like using counter will accomplish the same. Any help appreciated.
var myVal = 0;
function incrementValue(){
myVal++;
alert(myVal);
}
Just increment a variable every time you call the function.
If I am getting it right, it should be somewhat like this,
var btn_init = 0;
//on click
$(function(){
$('#your_button_id').on('click',function(){
btn_init++; //increment
alert(btn_init);
}
});
<div class="button1">click</div>
<div class="valuecontainer"></div>
<script>
var i=0;
var x=15;
$('.button1').click(function(){
if(i<x){
i++;
$('.valuecontainer').html(i);
}
else
{
alert("rechaed limit");
}
});
</script>
I guess you will find your answer here:
Count function call in JS
This is the shortest code found there though i donot completely understand this (somebody plz explain):
function myFunction() {
this.num = (this.num || 0) + 1;
if(this.num <= 15)
alert(this.num);
}

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...

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