Javascript Onclick Function Only Works Once - javascript

I have a hopefully pretty easy problem. I'm trying to create a JS function on my app where there's a number in HTML and every time it is clicked, another number is subtracted from it and the result displays.
(So far this much works.)
Then the action should be repeatable so the number keeps getting smaller.
(This part doesn't work yet.)
Finally, there's a reset button that, when clicked, resets the original number to a random number.
(The random number is found correctly, but when you click to subtract it subtracts from the original number, not from the randomly-chosen replacement number.)
Here's a partially-working JSFiddle
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
var n = n - s;
document.getElementById("countdownNumber").onclick = function updateNumber(){
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
var n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>
Can anyone (1) double check what I've done to make sure I'm not doing things in a stupid way and (2) help me figure out how to get the repeatable action functioning?

The issue is you are calculating value of n only once, it should be calculated on every click thus change you countdown click function to:
document.getElementById("countdownNumber").onclick = function updateNumber(){
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
n = n - s;
this.innerHTML = n;
}
Here is a working demo:
https://jsfiddle.net/m3q8fn2x/

If you are still struggling with this ,then consider the fact that when you declare a variable inside an event function its starting value is always the same , when the event is triggered. So consider this fact and declare variables outside the event function's scope.
const togglerBtn = document.getElementById("togglerBtn");
let temp = false;
togglerBtn.addEventListener("click", () => {
// alert();
if (!temp) {
togglerDiv.style.transform = "translateY(48px)";
return (temp = true);
} else if (temp) {
togglerDiv.style.transform = "translateY(-500px)";
return (temp = false);
}
});

Here is your working code:
You need to put the n = n - s part into the update number function so its called each time you click.
var s = document.getElementById('incrimentOfNumber').innerHTML
var n = document.getElementById('countdownNumber').innerHTML
document.getElementById("countdownNumber").onclick = function updateNumber() {
n = n - s;
this.innerHTML = n;
}
document.getElementById("resetCountdown").onclick = function resetCountdown(){
n = Math.floor(Math.random() * 500) + 200;
document.getElementById("countdownNumber").innerHTML = n;
}
<h3>Count down from the number you see in incriments of <span class="incrimentOfNumber" id="incrimentOfNumber">7</span>.
<br />Tap the number to see the correct answer.
<br />Repeat as needed.
</h3>
<div class="countdownNumber">
<h1 id="countdownNumber">284</h1>
</div>
<div class="btn" id="resetCountdown">Reset</div>

Related

how do i create a simple onclick add function()

i try to do these code and expecting it for increase by 1 everytime i click on the button but it returns me NaN instead.
im really new to javascript. really hope someone could help me!
thanks in advance.
function add(){
var sum = parseInt(1);
var adding = adding + sum;
document.getElementById("amt1").innerText = adding;
}
I see, here you've asked two problems:
Why adding is NaN
At line #2, you haven't initialized variable adding, hence in RHS adding is undefined.
Therefore, the RHS block adding + sum; is evaluated as undefined + 1, which evaluates to NaN
How to use onClick()
W3School's tutorial on onClick()
Here is your code in working state (HTML + JavaScript):
var adding = 0; // initialization. This is the step, that your code was missing
function add() {
var sum = parseInt(1);
adding = adding + sum;
document.getElementById("amt1").innerText = adding;
}
<h1>The onclick Event</h1>
<button onclick="add()">Click me</button>
<p id="amt1"></p>
You could take a closure over the sum and take the returned function for adding to the value.
var add = function(sum) {
return function () {
document.getElementById("amt1").innerHTML = ++sum;
};
}(0);
<span id="amt1">0</span> <button onclick="add()">add</button>
You're making the assignment in the local scope of the function, so every time the function executes, it's going to assign the value 1 to the 'sum' variable. Next, you're creating the variable 'adding' by trying to assign the value of adding, which doesn't exist yet.
It seems like the goal of your function is to just increment the value of 'amt1' by one.
function add(elId){
let currentAmt = document.getElementById(elId).innerText;
currentAmt = parseInt(currentAmt) + 1;
document.getElementById(elId).innerText = currentAmt;
}
By passing in the element ID, your function can now be applied to any element. It parses the integer from its current inner text, adds 1, then sets the new amount to the inner text of the element.
you might need to have a look on this post- Increment value each time when you run function
about how to increment, the idea is keep the variable outside the function as in you case,
you dont need parseInt as its used for parsing integers from a string.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
you need to keep the sum variable outside function. following is the general function to add
var n = 0;
function add(value){
n += value;
return n;
}
try it
document.getElementById("amt1").addEventListener("click", displayDate);
function displayDate() {
var node = document.getElementById('amt1');
document.getElementById("amt1").innerHTML = parseInt(node.textContent)+1;
}
<button id="amt1">1</button>
You're using an undefined variable adding to make your calculation that's why you get a NaN as a result :
var adding = adding + sum : the variable adding isn't yet initialized so it's value equals to undefined which give us var adding = undefined + sum = NaN. See next example :
var sum = parseInt(1);
console.log('typeof "adding" before initialization is ' + typeof adding + ' and it equals "' + adding + '"');
var adding = adding + sum;
console.log('typeof "adding" after initialization is ' + typeof adding + ' and it equals "' + adding + '"');
BTW, you don't need parseInt in order to put manually a number, sum = parseInt(1) is the same as sum = 1 but the later is faster.
And now here's how to accomplish your task :
/**
* btn: the button to be clicked to increment the counting.
* counterTxt: the "p#counter" element that prints the counting.
* counter: keeps track of the number of the clicks made.
**/
const btn = document.getElementById('btn'),
counterTxt = document.getElementById('counter');
let counter = 0; /** holds the number of clicks **/
/** click event handler for the "button" **/
btn.addEventListener('click', () => counterTxt.textContent = ++counter); /** update the "p#counter" text and increment the counter **/
<button id="btn">click to increment</button>
<p id="counter">0</p>

JS increase index number array by function

I trying to make a small text based rpg game, but I came across array in js and then I came to problems, I failing to increase the index number by using i instead of 0 like myArray[i]
I made a jsfiddle so you guys can see what I mean.
jsfiddle
When you press the button til you get a warming, it should increase the i to 2, but it don't, but still comes with warming and increasing the attack variable.
This is your attackUp function:
function attackUp(){
var i = 0;
var attackCost = xpforlevel[i];
if (attackCost < attackxp) {
alert("WARMING!");
attack++;
document.getElementById('attack').innerHTML = attack;
i++;
document.getElementById('i').innerHTML = i;
}
}
Notice that your var i = 0 statement doesn't really make sense (because everytime attackUp is called, i will be reset to = 0 at the beginning). To fix that, erase this var i = 0 statement from your function and put in the beginning of your JS code:
var i = 0;
var attackxp = 0;
var attack = 1;
Further, your function will only update i if attackCost < attackxp, otherwise it will change nothing. You need to put the i++; statement outside your if-block, like this:
function attackUp(){
//erase this line: var i = 0;
var attackCost = xpforlevel[i];
i++; //added this line
if (attackCost < attackxp) {
alert("WARMING!");
attack++;
document.getElementById('attack').innerHTML = attack;
//erase this line: i++;
document.getElementById('i').innerHTML = i;
}
}
As your i is a local variable, it is initiated as 0 every time you call attackUp(). You should put it besides attackxp and attack.
For more information about the scope of variable in JavaScript, see w3schools or this question.

Printing out for loop upon user input

I'm having issues with displaying my for loop on my page. There is a button which upon the click prompts the user to enter a number then display the iterations of said number through a for loop. I've looked at similar questions that have been asked on here but seem to still be running into a problem.
<!doctype hmtl>
<html>
<head></head>
<button onclick="getNumber()">Click!</button>
<p id="demo"></p>
<script>
function getNumber() {
var i;
var num;
var n = prompt("Please enter a number");
for(i = 0; i < n.length; i++){
num += n[i];
document.getElementById("demo").innerHTML += num + " ";
}
}
</script>
</body>
</html>
You were trying to get the length property of the users inputted value instead of the value directly.
Also, there are several unnecessary bits in your code and several bad practices that adversely affect performance.
// Get a reference to the HTML (DOM - Document Object Model) elements that
// you will need access to at this level of scope
var btn = document.getElementById("btn");
// Don't set up event handling code in the HTML (a.k.a. inline event handling) as it
// makes the HTML harder to read (two languages on a single line), it doesn't follow
// the standard for event handling, and it causes anonymous Global JavaScript functions
// to be made as wrappers around the HTML attribute values. Instead, do it in JavaScript
// like this:
btn.addEventListener("click", getNumber);
function getNumber() {
// Just scan for the element once, not each time the loop iterates
var el = document.getElementById("demo");
// Get the user's input and convert it to a number
var n = parseInt(prompt("Please enter a number"), 10);
// Set up a string that will become the output.
var output = "";
for(var i = 0; i < n; i++){
// NEVER alter an HTML (DOM) element within a loop as performance suffers
// because the browser must recreate the entire DOM structure.
// Instead, set up a variable that holds the results
output += " " + i;
}
// Once loop is done, update element with the variable. But, this way,
// you are doing it just once, instead of each time the loop iterates.
// Also, if the new content does not include HTML, then use textContent
// instead of innerHTML as it lets the browser know that the data does
// not have to be parsed, which results in a quicker update.
el.textContent = output;
}
<button id="btn">Click!</button>
<p id="demo"></p>
It should be i < n not i < n.length. Because what you are doing is looping as much times as there is characters in your variable n (which is a string by the way). So if the user types 9 only one number is printed because "9".length is 1 and there is only one iteration between 0 and 1 (excluded). Try this:
function getNumber() {
var num = 0; // this should be initialized
var n = prompt("Please enter a number");
for(var i = 0; i < n; i++){
num += i; // add i
document.getElementById("demo").innerHTML += num + " ";
}
}
Not Sure what exactly you are trying, but if you want repeat for loop till the user entered input, you can do it as following
check this snippet
function getNumber() {
var i;
var num;
var n = prompt("Please enter a number");
for (i = 0; i < n; i++) {
document.getElementById("demo").innerHTML += i + " ";
}
}
<button onclick="getNumber()">Click!</button>
<p id="demo"></p>
Hope it helps
The problem lies in n.length part. Imagine user provides number "10". The length property for number 10 is 2 so the code inside the loop is executed 2 times instead of 10 times.
<html>
<head>
</head>
<button onclick="getNumber()">Click!</button>
<p id="demo"></p>
<script>
function getNumber() {
var i;
var num;
var n = parseInt(prompt("Please enter a number"));
for(i = 1; i <= n; i++){
document.getElementById("demo").innerHTML += " " + i;
}
}
</script>
</body>
</html>

Fibonacci Sequence Implementation Not Behaving As Expected

I want to print the first 5 numbers in the Fibonacci sequence starting with 1 and 2. I expect this code to print 1,2,3,5,8 when I click the button, but somehow it only prints the last number which is 8 in this case. And if I click the button many times after that, it always prints 2. Why does it behave that way?
/*
Fibonacci sequence is calculated by the formula An = An-1 + An-2
#param prev An-2
#param next An-1
#param n the first n numbers to print
*/
var count = 0; // keeps track of which number we are on
function fibonacci(prev, next, n) {
// Need to subtract 2 or else it will print the first 7 numbers instead of 5
return count++ < n - 2 ? fibonacci(Math.max(prev,next), prev+next, n) + "," : next;
}
document.querySelector('button').addEventListener('click', function() {
console.log(fibonacci(1, 2, 5));
});
<button>Click me</button>
You only use console.log with the last result. If you want to log all of them, you should use it inside the recursive function.
And the second time you click the button, it doesn't work because count is global. You could reset it to 0 inside the event listener, but better avoid globals.
function fibonacci(current, next, n) {
if(n > 0) {
console.log(current);
fibonacci(next, current + next, n-1);
}
}
document.querySelector('button').addEventListener('click', function() {
fibonacci(1, 2, 5);
});
<button>Click me</button>
You console.log() the return value of fibonacci(1,2,5), which is exactly one number. You do not print anything anywhere in your recursive function calls. So, obvioulsly, only tha final result of your function will be printed.
If you want intermediary results, console.log(prev) before your return statement in fibonacci().
This solves your first issue.
For the second issue, you need to keep in mind how your variables work. countis defined outside of the fuction fibonacci, and therefore not automatically reset or anything just because the function ends. This means: after the funciton ran for the first time (and as a side effect, setting count to 3), the variable count will keep it's value 3. The next time you run the function, count++ < n - 2 will evaluate to false right away, because 4 < 3 is false. So it will return next, which is 2 on the first iteration.
To fix this, restrucutre your function in a way that it resets count to 0 when the last recursion is done, before it returns next ( you cannot do this within the ternary statement, you need to refractore it to a regular if-else)
Let's use newest technologies.
<!DOCTYPE html>
<html>
<head>
<title>Fibonacci</title>
<meta charset="utf-8" />
<script type="text/javascript">
'use strict';
function* fibonacci(cur, nxt) {//generator function
//let cur=0,nxt=1;
yield cur;
yield nxt;
while(true){
[cur,nxt]=[nxt,cur+nxt];//swap
yield nxt;
}
}
function getNumbers(){
var a = document.getElementById('cur').value-0;//instead of parseInt
var b = document.getElementById('nxt').value-0;
var n = document.getElementById('cnt').value-0;
var fi = fibonacci(a,b);//init generator
var fiNums = [];//init result array
for (var i = 0; i < n; i++) {
var tmp=fi.next();//{value:1, done:false}
fiNums.push(tmp.value);
}
//output result
document.getElementById('output').innerHTML = fiNums.join(', ');
}
//get all series in once
function getNumbersOld(){
var a = document.getElementById('cur').value-0;
var b = document.getElementById('nxt').value-0;
var n = document.getElementById('cnt').value-0;
var fiNums = [b,a];
for (var i = 2; i < n; i++) {
fiNums.unshift(fiNums[0]+fiNums[1]);
}
document.getElementById('output').innerHTML = fiNums.reverse().join(', ');
}
</script>
</head>
<body>
Generate Fibonacci series <br />
Current:<input type="number" id="cur" value="1" />
Next:<input type="number" id="nxt" value="1" />
Count:<input type="number" id="cnt" value="5" />
<button onclick="getNumbersOld()">Get Numbers</button>
<div id="output"></div>
</body>
</html>
Based on the answers regarding the global variable and how I didn't print the result of each recursive call from others, I was able to obtain a final correct solution to my problem.
function fibanocci(prev, next, n) {
/*
n - 2 is here so it will print the first n numbers in the Fibonacci sequence
instead of n + 2 numbers because we have to account for the 2 initial numbers,
1 and 2 in this case, and I don't want the client to account for these 2 initial
numbers themselves. Math.abs(n-2) so the recursion will stop when n is 1 so the
call stack will not get bloated and throw an exception.
*/
return n > Math.abs(n-2) ? prev + "," + fibanocci(Math.max(prev,next), prev + next, --n) : prev;
}
document.querySelector('button').addEventListener('click', function() {
console.log(fibonacci(1, 2, 5));
});

setInterval() change image

The goal: When the page is loaded, display the image andy_black.jpg. After two seconds, change the image source, and the thus image in the browser, to a second image called andy_white.jpg. This will change back and forth every 2 seconds.
I checked out this article:
SetInterval function calls
(I searched other as well, with the tags [javascript] [function] and the word "setinterval", but most were using jQuery and my intention here is not to use any jQuery, it's an experiment in JavaScript after all).
which was quite helpful for before I had read it my code was much longer and the function was not called in the setInterval() function.
So here's some code:
Suggestions?
var i = 1;
function change_pic() {
i + 1;
if (i == 5) {
i = 1;
}
//I suspect the computer will read i as 5 for some
//tiny amount of time before reverting back to 1
//which I suspect could cause a further problem, but
//is it the source of the current issue?
if (i == 1 || i == 2) {
document.getElementById('img_to_flip').src = "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg";
} else {
document.getElementById('img_to_flip').src = "https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg";
}
}
var pic_src = setInterval(change_pic, 2000);
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
You forget to actually reassign the new value to i.
Either use:
i = i + 1;
or
++i;
Also, why count to five when you only have two states? A common paradigm to have an auto-resetting counter is to use modulo arithmetic:
i = (i + 1) % 2;
which guarantees that i will only ever have values of 0 or 1.
FWIW, here's an alternate way of writing the entire feature that'll work for any number of images - just populate the pics array:
(function() { // function expression closure to contain variables
var i = 0;
var pics = ["https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg", "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg"];
var el = document.getElementById('img_to_flip'); // el doesn't change
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
setInterval(toggle, 2000);
})(); // invoke the function expression
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
If you want to avoid the delay in first time setInterval call the function before the setInterval as shown in the top answer:
(function() { // function expression closure to contain variables
var i = 0;
var pics = [ "andy_white.jpg", "andy_black.jpg" ];
var el = document.getElementById('img_to_flip');
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
toggle()
setInterval(toggle, 2000);
})(); // invoke the function expression

Categories

Resources