admin管理员组文章数量:1399963
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>
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/johschmoll/hLymhak7/1/
Share Improve this question edited Jan 24, 2018 at 15:49 TylerH 21.1k78 gold badges79 silver badges114 bronze badges asked Jan 24, 2018 at 9:24 JoSchJoSch 9902 gold badges20 silver badges40 bronze badges 5-
5
Move
var number = 1;
outside of the function. You're resetting it to 1 each time you call the function. – Andy Commented Jan 24, 2018 at 9:25 - 1 @Andy Ahhh, I see. Dumb mistake, should've figured that one out by myself. Thanks. – JoSch Commented Jan 24, 2018 at 9:26
-
2
Define
var number = 1;
as a global scope or useclosure
– Abhishek Pandey Commented Jan 24, 2018 at 9:26 -
2
you should also do the same with
var count = document.getElementById('count');
you dont need to call it everytime – Neji Soltani Commented Jan 24, 2018 at 9:28 - Close voters - this is not a typographical error. This is a conceptual problem in understanding that many people might repeat when new to programming. The typo reason is not a valid CV reason here. However, it is probably a duplicate. – TylerH Commented Jan 24, 2018 at 15:50
3 Answers
Reset to default 4Minimal 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/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/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/hLymhak7/12/
Best practice: Add as event listener
It is not remended 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/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/hLymhak7/14/
Final solution that is maintainable and easily tested
We can plete 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/hLymhak7/15/
Test suite example: https://stackblitz./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 remended, but here we go...
var count = document.getElementById('count');
function plusOne() {
var number = Number(count.textContent);
number++;
count.textContent = number.toString();
}
Example: https://jsfiddle/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>
本文标签: javascriptHow to repeatedly add 1 to variable on button clickStack Overflow
版权声明:本文标题:javascript - How to repeatedly add +1 to variable on button click? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744151838a2593091.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论