I have defined a function plusOne() which is supposed to add +1 to a variable (and then set the innerHTML of an element to be that variable). The function is called when a button is clicked.
However, the adding of +1 only works once. How do I have to change my function in order to add +1 to the variable every time the button is clicked?
Here's how my function and HTML are looking right now, along with a JSFiddle:
function plusOne() {
var number = 1;
var count = document.getElementById('count');
number++;
count.innerHTML = number;
}
<div>
<span id="count">1</span>
</div>
<div>
<button onclick="plusOne()">
+
</button>
</div>
Link to the JSFiddle: https://jsfiddle.net/johschmoll/hLymhak7/1/
Minimal solution: Move the state variable outside of the click handler's scope
Change your JavaScript to put the number variable outside of the click handler. Otherwise, you are resetting the number variable to 1 everytime the click handler is called.
var number = 1;
function plusOne() {
var count = document.getElementById('count');
number++;
count.textContent = number.toString();
}
Example: https://jsfiddle.net/hLymhak7/6/
Move the element reference outside the click handler's scope
It is also a good idea to keep the element reference outside of the click handler's scope if the element is never destroyed.
var number = 1;
var count = document.getElementById('count');
function plusOne() {
number++;
count.textContent = number.toString();
}
DOM query lookups are cheap nowadays, but a lot of them will negatively affect your app's performance.
Example: https://jsfiddle.net/hLymhak7/8/
Make the element dependency explicit
We can even pass the count element to the click handler to make it easier to test.
JavaScript
var number = 1;
function plusOne(count) {
number++;
count.textContent = number.toString();
}
HTML
<div>
<span id="count">1</span>
</div>
<div>
<button onclick="plusOne(count)">
+
</button>
</div>
The span element is actually assigned to a global variable which is within the scope of the button element just like the plusOne click handler. This means that in all examples, we could just as easily have used count or window.count to access the span element.
Example: https://jsfiddle.net/hLymhak7/12/
Best practice: Add as event listener
It is not recommended to bind the click handler by using the onclick attribute of the button element. One of the reasons is that we are only ever allowed to add one onclick handler, which is not the case with Element#addEventListener.
HTML
<div>
<span id="count">1</span>
</div>
<div>
<button id="incrementor">
+
</button>
</div>
JavaScript
var number = 1;
var count = document.getElementById('count');
var incrementor = document.getElementById('incrementor');
incrementor.addEventListener('click', plusOne);
function plusOne() {
number++;
count.textContent = number.toString();
}
See more discussions about onclick
Example: https://jsfiddle.net/hLymhak7/13/
Combine best practice with explicit element dependency
We can add a click listener that also passes the count element explicitly to the plusOne function.
var number = 1;
var count = document.getElementById('count');
var incrementor = document.getElementById('incrementor');
incrementor.addEventListener('click', function onClick() {
plusOne(count);
});
function plusOne(count) {
number++;
count.textContent = number.toString();
}
Now we are one step closer to maintainable code that is easily tested.
Example: https://jsfiddle.net/hLymhak7/14/
Final solution that is maintainable and easily tested
We can complete our solution by making the second dependency explicit, namely the number state variable.
When we pass this variable to the plusOne function, we now have a pure function which makes it easy to test and reason about.
HTML
<div>
<span id="count">1</span>
</div>
<div>
<button id="incrementor">
+
</button>
</div>
JavaScript
var number = 1;
var count = document.getElementById('count');
var incrementor = document.getElementById('incrementor');
incrementor.addEventListener('click', function onClick() {
number = plusOne(count, number);
});
function plusOne(count, number) {
number++;
count.textContent = number.toString();
return number;
}
While this is more verbose, the dependendencies are clear and the actual business logic, i.e. the plusOne function, can be extracted to a separate file and unit tested to verify that it does what it is supposed to.
Test suite
import { plusOne } from './plus-one';
describe('plusOne', () => {
let countElement;
let initialState;
let state;
beforeEach(() => {
initialState = 1;
state = initialState;
countElement = {
textContent: initialState.toString(),
};
})
it('returns an incremented state', () => {
state = plusOne(countElement, state);
expect(state).toBe(initialState + 1);
});
it('does not mutate the state', () => {
plusOne(countElement, state);
expect(state).toBe(initialState);
})
it('reflects the state in the count element', () => {
state = plusOne(countElement, state);
expect(countElement.textContent).toEqual(state.toString());
});
});
Example: https://jsfiddle.net/hLymhak7/15/
Test suite example: https://stackblitz.com/edit/stack-overflow-javascript-jquery-repeatedly-add-1-to-variable-o?file=src%2Fplus-one.spec.ts
Anti-pattern: Keep state in DOM
A lot of web apps keep the state in the DOM. While this is easy and we have less mutable state in our code, usually we want access to the state in multiple places of our apps.
Having to extract the state from the DOM in all places where we need it is not how it is supposed to be. We are supposed to keep our business logic in JavaScript and let the DOM reflect the state, not the other way around.
It also adds to a tight coupling to the DOM, making it more difficult to maintain and test.
// Keeping state in DOM is NOT recommended, but here we go...
var count = document.getElementById('count');
function plusOne() {
var number = Number(count.textContent);
number++;
count.textContent = number.toString();
}
Example: https://jsfiddle.net/hLymhak7/9/
<!-- Using inline js-->
<div>
<span id="count">1</span>
</div>
<div>
<button onclick="document.getElementById('count').innerHTML++">
+
</button>
</div>
function plusOne(){
var count = document.getElementById('count');
count.innerHTML++
}
<div>
<span id="count">1</span>
</div>
<div>
<button onclick="plusOne()">
+
</button>
</div>
Related
I need create button which count click but make every time new string. I have that function with scope which make count every time when I click, but I cannot understand, why in HTML it every time count zero, should be like this:
(Verticaly every click make new string with updated count)
1
2
3
4
...
<form action="#">
<input type="button" value="Count" onclick="add_count()">
</form>
function add_count() {
let integer = (function () {
let counter = 0;
return function() {return counter++;};
}());
let tag = document. createElement("p");
let text;
text = document. createTextNode(integer());
tag. appendChild(text);
let element = document. getElementsByTagName("body")[0];
element. appendChild(tag)};
You just need to move the counter initialization outside of the function scope
I've tweaked your code a bit.
Note: try not using inline event listeners, instead use event listeners in JavaScript file
let counter = 0;
const button = document.querySelector('input');
function add_count() {
let integer = (() => counter++);
const tag = document.createElement("p");
const text = document.createTextNode(integer());
tag.appendChild(text);
const element = document.body
element.appendChild(tag)
};
button.addEventListener('click', add_count)
<form action="#">
<input type="button" value="Count">
</form>
I am still learning and I like to know why certain codes happen the way they do. So, created a code to increment by 1 when a button is clicked and have that displayed on the screen. However, when using addEventListener, it didnt work. It only added 1 and never increased by 1 again.
But when I used onclick Event in html, it worked fine and incremented. What could be the issue? Here are the codes:
HTML
<div class="score container">
<h3 class="firstScore">0</h3>
<h3 class="to">To</h3>
<h3 class="secondScore">0</h3>
Player One
JS code with addEventLister. This doesnt increment, But when I used consol.log(count), it increased by 1 but grayed out. Kindly check the attached screenshot
var playerOne = document.querySelector('.playerOne')
playerOne.addEventListener('click', () => {
count = 0;
function countNum() {
count++;
document.querySelector('.firstScore').innerHTML = count;
}
countNum()
})
This is the JS code that I used onclick and added the function to the button directly. This is working fine. I want to know what made the addEventListener not to work?
count = 0;
function countNum() {
count++;
document.querySelector('.firstScore').innerHTML = count;
console.log(count)
}
The button with the html:
<button onclick="countNum()" class="playerOne">Player One</button>
You're resetting count to 0 every time the function is called.
You need to use the inner function as the event listener, not the outer function. You can do this with an IIFE that returns the inner function.
var playerOne = document.querySelector('.playerOne')
playerOne.addEventListener('click', (() => {
count = 0;
function countNum() {
count++;
document.querySelector('.firstScore').innerHTML = count;
}
return countNum;
})())
<div class="score container">
<h3 class="firstScore">0</h3>
<h3 class="to">To</h3>
<h3 class="secondScore">0</h3>
<button class="playerOne">Player One</button>
You should move your var count = 0 outside from addEventListener function. Otherwise on each click you will reset your counter and then immediately increment it, which means you always assign to innerHTML value equal to 1.
Fixed example with addEventListener:
var playerOne = document.querySelector('.playerOne');
var firstScore = document.querySelector('.firstScore');
var count = 0;
var countNum = function() {
count++;
firstScore.innerHTML = count;
};
playerOne.addEventListener('click', countNum);
Working example.
I know this might be pretty simple but I cannot see the tree from the wood atm.
Please can you help?
I have a variable whose initial value is 1 and I want to increment it by 1 every single time the user clicks on a button.
I have this code:
let counter = 0;
dPadRight.addEventListener("click", function increment() {
counter++;
}
);
console.log(counter);
We don't have your html markup, so below I just created a div with ID of 'dPadRight' to add the listener to. I then referenced this in a variable in the javascript code. I assume you're already doing something like this to have a variable called 'dPadRight'.
Based on your comment describing your need to "use [the counter] for other things", I added another "pad" identified as "otherPad". "dPadRight" can serve to increment the counter. "otherPad" can serve to do something with the counter. In the code below, I just log it.
The lesson here is that if you want to use the counter after it's been incremented -- well -- then you can't be referencing it the main javascript body because that's before it's ever had the chance to increment.
let dPadRight = document.querySelector('#dPadRight');
let otherPad = document.querySelector('#otherPad');
let counter = 0;
dPadRight.addEventListener("click", () => {
counter++;
});
otherPad.addEventListener("click", () => {
console.log(counter);
});
<div id="dPadRight">
click to increment counter
</div>
<br/>
<div id="otherPad">
click to log counter
</div>
Try this
let counter = 1;
let dPadRight = document.getElementById('dPadRight');
dPadRight.addEventListener("click", function() {
console.log(counter);
counter++;
if(counter > 5){
// just to show that counter is available outside the annonymous
// function
let bla = getCounterValue();
console.log("Bla Value " + bla);
}
}
);
function getCounterValue(){
return counter;
}
<button id="dPadRight">Increment Me </button>
I am writing a little clicking game with javascript at the moment and I am currently stuck with a little challenge. I need it so that whenever i have clicked a button 10 times. my second value should increase by one. Maybe a little bit hard to understand, I'll try to explain it in code.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
Amount = 0;
// Whenever I click the button..The Amount increases like this.
Amount++;
// so after one click the amount should be..
Amount = 1;
// I need it so that when the button has been clicked 10 times I want to display //that. Something like this.
timesThatTheButtonHasBeenClickedTenTimes = 1;
Should I do this with a while loop or what.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
var amount = 0;
var counter = function () {
amount++;
if (amount === 10) {
amount = 0;
timesThatTheButtonHasBeenClickedTenTimes++;
}
document.getElementById('clicks').innerHTML = amount;
document.getElementById('hits').innerHTML = timesThatTheButtonHasBeenClickedTenTimes;
};
document.getElementById("mybutton").addEventListener("click", counter);
<button id='mybutton'>
Click me!
</button>
<p>
Clicks = <span id='clicks'>0</span>
</p>
<p>
10 times hits = <span id='hits'>0</span>
</p>
Hope it helps!
You could do something like:
var timesButtonClicked = 0;
var secondValue = 0;
if (timesButtonClicked === 10) {
secondValue++;
timesButtonClicked = 0;
} else {
timesButtonClicked++;
}
This is the very simple solution for you problem:
var clicks = 0;
Clicker = function() {
clicks++;
console.log('You clicked '+clicks+' times already.');
if(clicks == 10){
alert('Something what you want to alert.')
clicks = 0;
}
}
<button onclick="Clicker()">
Click me 10x times pls
</button>
One approach I'd suggest is:
function increment() {
// find the current number of times the <button> has been clicked,
// if the <button> has a data-current attribute we retrieve that
// attribute-value and parse it as a number in decimal format;
// if it does not have that custom data-* attribute we set the
// variable to 0:
let currentValue = this.dataset.current ? parseInt(this.dataset.current, 10) : 0;
// here we update the data-current attribute to the incremented value
// of the currentValue:
this.dataset.current = ++currentValue;
// we retrieve the element with the id of 'clicks', and set
// its textContent to the value held by the currentValue:
document.getElementById('clicks').textContent = currentValue;
// here we retrieve the element with an id of 'numberOfTens',
// and set its textContent to the floored value of the currentValue
// divided by 10:
document.getElementById('numberOfTens').textContent = Math.floor(currentValue / 10);
}
// here we retrieve the element with the id of 'clicker':
document.getElementById('clicker')
// and bind the increment() function (note the deliberate lack of
// parentheses) as the event-handler for the 'click' event:
.addEventListener('click', increment);
div:empty::before {
content: '0';
}
#clicks::after {
content: ' clicks.';
}
#numberOfTens::after {
content: ' tens of clicks.';
}
<button id="clicker">Click</button>
<div id="clicks"></div>
<div id="numberOfTens"></div>
References:
CSS:
:empty pseudo-class.
Pseudo-elements, ::before, ::after.
content property.
JavaScript:
document.getElementById().
EventTarget.addEventListener().
HTMLElement.dataset.
parseInt.
Pre-increment variable ++variableName.
Could anyone please help me sort out a bug in my beginner code? I am trying to add an list item to a list and trying to change the id of what list i'm adding it to in javascript. Thanks in advance.
<html>
<head>
<script>
window.onload = init;
function init() {
var button = document.getElementById("submit");
button.onclick = changeDiv;
}
function changeDiv() {
var counter=1
var name = "ul";
var textInput = document.getElementById("textInput");
var userInput = textInput.value;
alert("adding " + userInput);
var li = document.createElement("li");
li.innerHTML = userInput;
var ul = document.getElementById("ul" + loop());
ul.appendChild(li);
}
function loop() {
return counter;
if (counter==3){
counter==0;
}
counter++;
}
</script>
</head>
<body>
<form id="form">
<input id="textInput" type="text" placeholder="input text here">
<input id="submit" type="button">
</form>
<ul id="ul1">
</ul>
<ul id="ul2">
</ul>
<ul id="ul3">
</ul>
</body>
i think you want is one of these:
Give the scope of counter to be global (yuk)
create a closure around everything and declare counter there
you could pass counter into loop() when you call it.
define loop() in changeDiv().
I think you want #2 though so I fiddled it with several corrections in your code:
fiddle
The reason that I went with #2 is:
that a closure allows your logic to gain application to the resources it needs
but protect the scope at which other applications might be running (now or in the future) from being affected by any changes your application might attempt to that scope. For example, if you declared the counter as a global then all other javascript would potentially have read/write access to it which could negatively affect your demonstrated code, the other code, or both
keeps your current beginner code as unchanged as possible
gets you programming with an extremely important aspect of javascript that will help you today and in future as you learn
Answer #4 is similar in that it would create a closure for both changeDiv and loop whereby they both have access to what they need. However, I didn't want to change your existing logical blocks too much to stall incremental learning. But one could definitely make an argument for the loop() (which isn't really a loop but rather a setter) being enclosed in changeDiv() -- albeit you would likely remove the separate function call at that point and integrate the code more.
Essentially, you need to:
declare counter in a global scope (loop() cannot access it otherwise)
in loop(), the return statement must be the LAST thing. Anything after it won't get executed.
I altered the logic a bit and the final code is this:
window.onload = init;
var counter=1;
function init(){
var button = document.getElementById("submit");
button.onclick = changeDiv;
}
function changeDiv(){
var name = "ul";
var textInput = document.getElementById("textInput");
var userInput = textInput.value;
var id = "ul" + loop();
alert("adding " + userInput + " to " + id);
var li = document.createElement("li");
li.innerHTML = userInput;
var ul = document.getElementById(id);
ul.appendChild(li);
}
function loop(){
var tmp = counter++;
if (counter==4){
counter=1;
}
return tmp;
}
Note the changes in the loop() function.
I also altered the changeDiv() function to display the list ID in the alert.