run an IF statement once - javascript

I have an age value which I'm using as a condition to enter an IF statement. The IF statement populates random values in to a field (this is a childs math game). After the fields are populated the user can enter their answers and then check them using a 'Check Answers' button. Once the 'Check Answers' block is run the IF statement gets ran again(!), which causes the math problems to change - new random values are created.
How can I prevent the IF statement from running after the page has already loaded; causing the values to change each time the 'Check Answers' button is clicked?
Here is is the relevant javascript:
$(document).ready(function () {
var getAge = localStorage.getItem('setAge');
var userResponse = new Array();
var answer = new Array();
if (getAge >= 1 && getAge <= 7) {
var operator = new Array('+', '-');
for (var counter = 0; counter <= 2; counter++) {
var index = Math.round(Math.random());
var1 = Math.floor((Math.random() * 5) + 1);
var2 = Math.floor((Math.random() * 10) + 1);
// these add the values to the mathQuestions.aspx
$('#a' + counter).text(var1);
$('#b' + counter).text(operator[index]);
$('#c' + counter).text(var2);
answer[counter] = eval(var1 + operator[index] + var2);
}
// this stores the users answers in userResponse[]
for (var counter = 0; counter <= 2; counter++) {
$('#d' + counter).change(function () {
for (var counter = 0; counter <= 2; counter++) {
userResponse[counter] = $('#d' + counter).val();
// window.alert("userResponse = " + userResponse[counter]);
}
});
}
// Button3 = 'Check Answers'
$('#Button3').click(function () {
for (var counter = 0; counter <= 2; counter++) {
window.alert('userResponse after checking the answers = ' + userResponse[counter]);
if (answer[counter] != userResponse[counter]) {
$('#span' + counter).val(answer[counter]);
}
}
});
});
I'm still learning all of this so I could have others errors that are contributing to my problem. To my knowledge the root problem is caused by the IF statement running again. Also, in case it's relevant I'm using Visual Studio Express 2012 for Web using some ASP controls (table, buttons, input, etc).

My guess is that the issue is not within the code you've posted, but within your HTML; Based on the code you've posted does contain a click-event, but this could never cause the 'randomize'-part to be ran again.
Could it be that your HTML looks like:
<form>
<button>Check answers</button>
</form>
or
<form>
<input type="submit" value="Check answers">
</form>
Having a button or submit inside a form-attribute results in a 'submit-action' when you hit the button. The result is that you first see the alert-message from the click-event. Next the page is reloaded and the whole document.ready() script will be executed again.
A simple solution could be:
$('#Button3').click(function (event) {
event.preventDefault()
/* ... */
}
This stops the form from submitting.
http://api.jquery.com/event.preventdefault/

Related

How to exchange counter after delete field using plain javascript

I'm new in javascript. i have a JS function that add and remove input fields. its working fine with my JS function. But I want when delete a field its Id looks like:
I have
no. 1
no. 2
no. 3
After Delete 2:
no. 1
no. 2
already i got this answer:
Reset JavaScript Counter after Deleting a field
But i want it with plain javascript. Can anyone help?
<script>
var count = 1;
function add_new(){
count++;
var div1 = document.createElement('div');
div1.id = count;
var delLink = '<button type="button" onclick="deleteLink('+count+')" class="btn btn-primary">Delete</button>';
div1.innerHTML = document.getElementById('add_link1').innerHTML+delLink;
document.getElementById('add_link').appendChild(div1);
document.getElementById("input_link1").id = count;
document.getElementById("input_link2").id = count;
document.getElementById("input_link3").id = count;
}
function deleteLink(eleId){
var ele = document.getElementById(eleId);
var par = document.getElementById('add_link');
par.removeChild(ele);
}
</script>
After deleting an element call the following function to reset Id of existing elements and also reduce the count.
function reset_counter(deletedCount) {
for (var impactedElementId = deletedCount + 1; impactedElementId < count; impactedElementId++) {
var currentElement = document.getElementById(impactedElementId);
currentElement.id = impactedElementId - 1;
var button = currentElement.firstChild;
button.innerHTML = 'Delete ' + currentElement.id;
button.setAttribute('onclick', 'deleteLink(' + currentElement.id + ')');
}
count--;
}
The full code is available here: AddDeleteElements Sample Code

counter for number of NEW buttons clicked (HTML/Javascript)

I am new to programming and I am working with a table on otree were 256 different buttons are displayed using Javascript. Each button unveils an icon which is recalled by a simple function.
In this function, I have installed a simple click counter that increases by one each time a button is clicked. The simple click counter works fine (that is not my issue) :)
The table:
for(var r = 0; r < rows;r++)
{
table += '<tr>';
for(var c= 0; c< cols;c++)
{
var random = Math.floor(Math.random() * nums.length);
table += '<td style="width:50px">' + '<button id="' + nums[random] + '" type="button" onclick="displayImage(this.id)">' + "show me" + '</button>' + '</td>';
nums.splice(random, 1);
}
table += '</tr>';
}
The function:
function displayImage(num){
document.canvas2.src = '{% static "bottone/'+ imagesArray[num]+ '.png" %}';
document.getElementById("YourImage2").style.visibility = "visible";
onClick();
}
The counter:
var clicks = 0;
function onClick() {
clicks += 1;
document.getElementById("clicks").innerHTML = clicks;
};
All good till here, there is a hidden HTML field and I manage to save the value of the counter when the user clicks the "next" button...
My problem is the following: this counter counts the amount of buttons clicked, however, I would like it to count only the number of times a button is clicked for the first time (could range from 0 to 256) while still enabling people to click the same button more times.
I´m sure it can be really simple but have no idea where to start...
You can track for each button whether it was clicked before, and if so not count the click.
Your onClick function would look like this (note you should pass it the id of the clicked button):
var clicks = 0;
function onClick(id) {
var clickedEl = document.getElementById(id);
if (clickedEl.dataset.wasClicked) {
return;
}
clickedEl.dataset.wasClicked = true;
clicks += 1;
document.getElementById("clicks").innerHTML = clicks;
}
Here is a simple JSFiddle example:
HTML:
<button onclick="buttonClicked(event)">
New 1
</button>
<button onclick="buttonClicked(event)">
New 2
</button>
<button onclick="buttonClicked(event)">
New 3
</button>
<div id="counter">0
</div>
JS:
var clickedList = [];
var counter = 0;
function buttonClicked(event){
if (clickedList.indexOf(event.currentTarget) === -1){
clickedList.push(event.currentTarget);
counter++;
document.getElementById("counter").innerHTML = counter;
console.log(counter);
}
}

Getting an infinite loop and can't see why - Javascript

I'm writing a simple little Connect 4 game and I'm running into an infinite loop on one of my functions:
var reds = 0;
var greens = 0;
function checkEmpty(div) {
var empty = false;
var clicked = $(div).attr('id');
console.log(clicked);
var idnum = parseInt(clicked.substr(6));
while (idnum < 43) {
idnum = idnum + 7;
}
console.log("idnum=" + idnum);
while (empty == false) {
for (var i = idnum; i > 0; i - 7) {
idnumStr = idnum.toString();
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
}
}
return divToFill;
}
function addDisc(div) {
if (reds > greens) {
$(div).addClass('green');
greens++;
console.log("greens=" + greens);
} else {
$(div).addClass('red');
reds++;
console.log("reds=" + reds);
};
$(div).removeClass('empty');
}
$(function() {
var i = 1;
//add a numbered id to every game square
$('.game-square').each(function() {
$(this).attr('id', 'square' + i);
i++;
//add an on click event handler to every game square
//onclick functions
$(this).on('click', function() {
var divToFill = checkEmpty(this);
addDisc(divToFill);
})
})
})
Here is a link to the codepen http://codepen.io/Gobias___/pen/xOwNOd
If you click on one of the circles and watch the browser's console, you'll see that it returns true over 3000 times. I can't figure out what I've done that makes it do that. I want the code to stop as soon as it returns empty = true. empty starts out false because I only want the code to run on divs that do not already have class .green or .red.
Where am I going wrong here?
for (var i = idnum; i > 0; i - 7);
You do not change the i.
Do you want to decrement it by 7?
Change your for loop to the one shown below:
for (var i = idnum; i > 0; i -= 7) {
// ...
}
You also do not use loop variable in the loop body. Instead, you use idnum, I think this can be issue.
while (empty == false) {
for (var i = idnum; i > 0; i -= 7) {
idnumStr = i.toString(); // changed to i
var checking = $('#square' + idnumStr);
var str = checking.attr('class');
empty = str.includes('empty');
console.log(empty);
var divToFill = checking;
// and don't forget to stop, when found empty
if (empty) break;
}
}
I add break if empty found, because if we go to next iteration we will override empty variable with smallest i related value.
You can also wrap empty assignment with if (!empty) {empty = ...;} to prevent this override, but I assume you can just break, because:
I want the code to stop as soon as it returns empty = true
Offtop hint:
while (idnum < 43) {
idnum = idnum + 7;
}
can be easy replaced with: idnum = 42 + (idnum%7 || 7)
Change to this:
for (var i = idnum; i > 0; i = i - 7) {
You are not decrementing the i in your for loop
Building on what the others have posted You would want to change the value of empty inside the for loop. because obviously the string still checks the last string in the loop which would always return false.
while(empty==false){
for (var i = idnum; i > 0; i -= 7) {
// your other codes
if (!empty) {
empty = str.includes('empty');
}
}

Timeout function to highlight words does not work correctly

I am using the setTimeout and clearTimeout functions to highlight words in a textarea element at certain specified intervals. The steps I am following are:
Get text from textarea element.
Split into words.
Output each word into a separate textarea element every 5 seconds.
The code is:
<html>
<head>
<script type="text/javascript">
/* this function does the folloeing:
* 1. takes all the words in the textarea.
* 2. Separates them into words.
* 3. Iterate through the list of words.
* 4. Search and highlight each word for 1 second.
*/
var highlightBtn = document.getElementById("start");
var continueHighlight = false;
var text;
var highlighter;
var words;
function startHighlight(val) {
continueHighlight = val;
console.log("Highlight = " + continueHighlight);
//1. get words within textarea.
var textarea = document.getElementById("inputText");
text = textarea.value;
console.log("text = " + text);
//2. split text into words.
var words = text.split(' ');
console.log("There are " + words.length + " words in the text.");
//highlight();
if(continueHighlight) {
//3. iterate through list of words.
var i = 0;
while(i < words.length) {
highlighter = setTimeout(searchAndHighlight, 5000, words[i]);
//console.log("Word highlighting = " + words[i]);
i = i + 1;
}
} else {
console.log("Stopping highlighting.");
clearTimeout(highlighter);
}
}
function highlight() {
if(continueHighlight) {
//3. iterate through list of words.
var i = 0;
while(i < words.length) {
highlighter = setTimeout(searchAndHighlight, 5000, words[i]);
//console.log("Word highlighting = " + words[i]);
i = i + 1;
}
} else {
console.log("Stopping highlighting.");
clearTimeout(highlighter);
}
}
function searchAndHighlight(word) {
console.log("Highlighting word = " + word);
var output = document.getElementById("output");
output.value = word;
}
</script>
</head>
<body>
<textarea id="inputText"></textarea>
<br/>
<button id="start" onclick="startHighlight('true')">Start!</button>
<br/>
<button id="stop" onclick="startHighlight('false')">Stop!</button>
<br/>
<textarea id="output"></textarea>
</body>
</html>
I expected every word to be displayed in the second textarea every 5 seconds. This is not happening. Instead, I get nothing for 5 seconds and then all words in quick succession. This happens even if I press the stop button. My questions:
Where am I going wrong in using the setTimeout function?
This piece of code:
var i = 0;
while(i < words.length) {
highlighter = setTimeout(searchAndHighlight, 5000, words[i]);
//console.log("Word highlighting = " + words[i]);
i = i + 1;
}
is rapidly calling setTimeout() a bunch of times in a row and setting them all for the same time. That will match your symptoms of waiting 5 seconds and then running them all at once.
You will either have to set each successive timeout for a longer period of time or change the structure of the code to not start the next timer until the first one fires.
Here's how you could solve it by only setting one setTimeout() at a time. This would also solve the stop button problem:
function highlight() {
if(continueHighlight) {
var i = 0;
function next() {
if (i < words.length) {
highlighter = setTimeout(function() {
searchAndHighlight(words[i]);
i++;
next();
}, 5000);
}
}
next();
} else {
console.log("Stopping highlighting.");
clearTimeout(highlighter);
}
}
When you want to stop the progressive highlighting, I don't understand why you're taking such a circuitous route. You should just call the clearTimeout(highlighter). There's no need to go through multiple functions like you're doing just to do that.
Or, the solution that sets successively longer timers could work like this:
var i = 0;
while(i < words.length) {
highlighter = setTimeout(searchAndHighlight, 5000 * (i+1), words[i]);
//console.log("Word highlighting = " + words[i]);
i = i + 1;
}
If you want to use this type of solution, then to fix the stop button problem, you will have to keep all the timer ids in an array and cancel all of them. Personally, I'd probably restructure the code and only have one setTimeout() in flight at a time and when each one fires you kick off the next one. Then, you only have one setTimeout() going at once so it's simpler to cancel.
Here is a solution that fixes the stop button problem. If you keep track of i, you could also have the highlight function resume where it left off.
<html>
<head>
<script type="text/javascript">
/* this function does the folloeing:
* 1. takes all the words in the textarea.
* 2. Separates them into words.
* 3. Iterate through the list of words.
* 4. Search and highlight each word for 1 second.
*/
var highlightBtn = document.getElementById("start");
var continueHighlight = false;
var text;
var highlighter;
var words;
function startHighlight(val) {
continueHighlight = val;
console.log("Highlight = " + continueHighlight);
//1. get words within textarea.
var textarea = document.getElementById("inputText");
text = textarea.value;
console.log("text = " + text);
//2. split text into words.
var words = text.split(' ');
console.log("There are " + words.length + " words in the text.");
//highlight();
//3. iterate through list of words.
var i = 0;
highlighter = setTimeout( function( ){
searchAndHighlight( words, 0 );
}, 5000);
function searchAndHighlight(words, i ) {
if(i >= words.length){
clearTimeout(highlighter);
}else{
console.log("Highlighting word = " + words[i]);
var output = document.getElementById("output");
output.value = words[i];
i++;
highlighter = setTimeout( function( ){
searchAndHighlight( words, i );
}, 5000);
}
}
}
function stopHighlight(){
console.log("Stopping highlighting.");
clearTimeout(highlighter);
}
</script>
</head>
<body>
<textarea id="inputText"></textarea>
<br/>
<button id="start" onclick="startHighlight()">Start!</button>
<br/>
<button id="stop" onclick="stopHighlight()">Stop!</button>
<br/>
<textarea id="output"></textarea>
</body>
</html>

large form or javascript locks up browser

I have a html form with about 105 fields, which includes some javascript activity:
1) expand/collapse sections
http://www.adipalaz.com/experiments/jquery/nested_accordion.html
2) date picker
3) AutoSave functionality
<script type="text/javascript">
function counter() {
email = document.getElementById("applicant-email").value;
if (email.match(emregex) || cd == cdLength){
if (email.match(emregex)){
document.getElementById("countdown").innerHTML = left + cd-- + right + button;
if (cd < 0){
formAutosave();
}
}else{
document.getElementById("countdown").innerHTML = "Enter your email address for AutoSave <a onclick=\"javascript:alert(\'Please enter an email address\');\"><span><b></b>Save Now</span></a>";
}
}
};
function formAutosave() {
window.clearInterval(timer);
email = document.getElementById("applicant-email").value;
if (email.match(emregex)){
document.getElementById("countdown").innerHTML = \'<a><span><b></b>Saving ...</span></a>\';
var values = "";
for (var i = 0; i < userForm.length; i++) {
if (userForm.elements[i].value != null) {
if (userForm.elements[i].name == "form[autosave]") {
userForm.elements[i].value = "TRUE";
}
if (userForm.elements[i].id == "'.$fieldId.'"){
userForm.elements[i].value = email;
}
if (userForm.elements[i].id != "finished"){
values += userForm.elements[i].name + "=" + encodeURI(userForm.elements[i].value) + "&";
}
}
}
values = values.substring(0, values.length - 1);
jQuery.post(
"http://'.$_SERVER['SERVER_NAME'].
$uri.strstr($uri,'?')?'&':'?').'autosave=1&format=raw",
values,
function (submissionId){
if (parseInt(submissionId) > 0){
jQuery("#continue").val(parseInt(submissionId));
}
cd = cdLength;
timer = window.setInterval("counter()", 1000);
}
);
};
};
var userForm = document.getElementById("userForm");
var emregex = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
cdLength = '.self::SAVEINTERVAL.';
var left = \'Automatically saving in \';
var cd = cdLength;
var right = \' seconds or \';
var button = \'<a onclick="javascript: formAutosave();"><span><b></b>Save Now</span></a>\';
jQuery("#applicant-email").val(jQuery("#'.$fieldId.'").val());
var timer = window.setInterval("counter()", 1000);
';
We have recorded 3 testing videos (Chrome, Firefox, IE9), in all of which there is a visible slowdown using dropdowns in the form, even though the user has not used expand/collapse or date picker. SO I'm expecting that we are causing a lock up or memory leak in the auto save routine.
Advice on refactoring would be appreciated.
The comments above are great and I'd recommended following the advice posted by #Adam and #Alex (pass a named function instead). Also, you might try implementing a bit differently (i.e. the Module design pattern or some other best practices). Take a look at this StackOverflow question: https://stackoverflow.com/questions/4840420/recommended-javascript-annotated-source-code-for-learning

Categories

Resources