How do I add two functions using javascript? - javascript

I'm creating a choose your own adventure game that uses a health bar and changing texts.
My health bar is able to change with my current code but the text does not. Is there something I am missing? What can I do?
The two buttons are identified with "btn q1" and it reads "Question1", and "btn q2" and it reads "Question2". I would like to change "Question1" to "Question1A", etc.
Here is my html for the buttons:
<div class="click">
<span class="btn q1" id="btn q1" onclick="remove(); change();">
Question1
</span>
<span class="btn q2" id="btn q2" onclick="remove(); change();">
Question2
</span>
</div>;
And my javascript:
var _Health = 100;
function remove() {
let addHealth = document.getElementById("health");
_Health += 20;
if (addHealth) {
addHealth.style.width = _Health + "%";
addHealth.innerHTML = _Health + "ep";
}
}
function remove() {
let damage = document.getElementById("health");
_Health -= 10;
if (damage) {
damage.style.width = _Health + "%";
damage.innerHTML = _Health + "ep";
}
}
function change() {
var elem = document.getElementById("btn q1");
if ((elem.value = "Question1")) elem.value = "Question1A";
else elem.value = "Question1B";
}
function change() {
var elem = document.getElementById("btn q2");
if (elem.value == "Question2") elem.value = "Question2A";
else elem.value = "Question2B";
}

You can’t create functions with same name. You should create remove1() and remove2() for example, and call them into the button. But it is not the right way: you need to generalise the functions. Consider the example of Manuel in the comment: it is enough to pass the parameter with the name of the button, and execute all the stuffs with the name passed.
<span class="btn_q1" id="btn_q1" onclick= "remove(10); change(“btn_q1”, “Question1A”);">Question1</span>
<span class="btn_q2" id="btn_q2" onclick= "remove(20); change(“btn_q2”,”Question1B”);">Question2</span>
</div>
And In the js:
function change(btn,value)
{
var elem = document.getElementById(btn);
elem.value = value;
}
function remove(n) {
let addHealth = document.getElementById('health')
_Health += n;
if (addHealth) {
addHealth.style.width = _Health + '%';
addHealth.innerHTML = _Health + 'ep';
}
}
Last thing: don’t use namespaces in the ids. Use underscore instead of space (same in classes)

Related

Draw in two tables vanilla JS

I am working with program that will randomly choose who is making a Christmas gift to whom.
I've created an empty array. When you add a "player" it's pushing the name into two different arrays. Players[] and Players2[].
When you start a draw. The program writes the names of the Players[] on the left hand side and on the right side it writes the drawn names from Players2[].
Every Player from Players2[], after being drawn, is being deleted from the array so in the end we have an empty Players2[] array and full Players[] array.
The problem is: I can't make a working if statement that is checking if the person will not draw himself...
let Players = [];
let Players2 = [];
const addBTN = document.getElementById('addBTN');
const onlyLetters = /^[a-zżźćóęśńłA-ZŻŹĆÓŁĘŚŃŁ ]+$/;
const refreshBTN = document.getElementById('refreshBTN');
const warningBTNyes = document.getElementById('warning-button-yes');
const warningBTNno = document.getElementById('warning-button-no');
const playersList = document.getElementById('playersList');
const playersList2 = document.getElementById('playersList2');
const startBTN = document.getElementById('startBTN');
const drawLotsBTN = document.getElementById('drawLotsBTN');
addBTN.addEventListener('click', function() {
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
console.log('error_empty_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Wpisz imię osoby!";
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Dodaj kolejną osobę.";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
});
refreshBTN.addEventListener('click', function() {
document.getElementById('warning').style.display = "block";
});
warningBTNyes.addEventListener('click', function() {
location.reload(true);
document.getElementById('addPLAYER').value = "";
});
warningBTNno.addEventListener('click', function() {
document.getElementById('warning').style.display = "none";
});
startBTN.addEventListener('click', function() {
drawLotsBTN.disabled = false;
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Zaczynasz losowanie!";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
document.getElementById('addPLAYER').disabled = true;
});
drawLotsBTN.addEventListener('click', function() {
for (let i = 0; i = Players2.length; i++) {
if (Players2.length > 0) {
randomPerson = Math.floor(Math.random() * Players2.length);
if (randomPerson != Players.indexOf(i)) {
console.log(Players2[randomPerson]);
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players2[randomPerson];
Players2.splice(randomPerson, 1);
}
} else {
console.log('error_empty_array');
}
}
});
<div id="warning" class="warning">
<div class="warning-flex">
<h1>Wszelkie wpisane imiona zostaną usunięte</h1>
<div class="warning-buttons">
<button id="warning-button-yes" class="warning-button-yes">Tak</button>
<button id="warning-button-no" class="warning-button no">Nie</button>
</div>
</div>
</div>
<div class="lotteryContainer">
<div class="left">
<p>dodaj osobę</p>
<div class="addPerson">
<input required id="addPLAYER" type="text">
<button id="addBTN">+</button>
<p id="errorMSG"></p>
<div class="refresh">
<button id="refreshBTN">Od nowa</button>
<button id="startBTN">Start</button>
</div>
</div>
</div>
<div class="right">
<p>Uczestnicy</p>
<div class="tables">
<div class="tableLeft">
<p id=playersList></p>
</div>
<div class="tableRight">
<p id="playersList2"></p>
</div>
</div>
<button id="drawLotsBTN">Losuj</button>
</div>
</div>
<script src="app.js"></script>
Now if I understand what your program aims to do, there is a simple algorithm for it.
How I understand your goal:
You have a list of persons who are going to give presents to each other. (like in secret Santa). It is random who will give to who, but each person gives and receives one gift.
How to implement it (i'd normaly use maps, but I am guessing you are more comfortable with arrays):
players = ["Adam", "Bret", "Clay", "Donald"];
players.sort(function(a, b){return 0.5 - Math.random()}); // shuffles array
gives_to = [...players]; // copy values of array
gives_to.push(gives_to.shift()); // let the first element be the last
Here the first player (players[0]) will give to gives_to[0] and the second to gives_to[1] etc.
I've created this JS script trying to use Trygve Ruud algorithm but it doesn't work like desired.
drawLotsBTN.addEventListener('click', function(){
if(Players.length > 0) {
console.log(Players)
Players.sort(function(a, b){
return 0.5 - Math.random();
});
for(let i = 0; i < Players.length; i++){
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players[i];
}
}
else{
console.log('error_empty_array');
}
});

All buttons only affect one input instead of respective input

I am making a little project for my self. So basically its main function is to create a base counter for each game.
For example: If there are two players it should create three bases. (This is for the card game "smash up" if that helps you understand better.) But when the Buttons populate they all only effect the last input. I can not figure out how to make them effect their respective inputs.
The problem I am having is that every button I click only effects the last input.
<html>
<title> Base Maker </title>
<body>
<div>
<hl> Score Keeper </h1>
<hr>
<input type = "text" placeholder = "How many players?">
<button id = "enter" onclick = "baseMaker()">
Enter
</button>
</div>
<p></p>
</body>
</html>
var parent = document.querySelector("p");
var input = document.querySelector("input");
var enter = document.getElementById("enter");
function baseMaker()
{
for(var i = 0; i <= input.value; i++)
{
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement( "input");
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement( "button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', function() {
score.value++; });
//downbutton
var downButton = document.createElement( "button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', function() {
score.value--; });
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
input.value = "";
}
This is a common thing to run into especially when not using a framework in javascript.
I am not sure why this happens but when a function is defined directly in a loop, the closure for these created functions becomes whatever it is after the last iteration. I believe it is because the closure for each callback function is only "sealed up" (for lack of a better word) at the end of the loop-containing-function's execution which is after the last iteration. It's really beyond me, though.
There are some easy ways to avoid this behavior:
use bind to ensure a callback gets called with the correct input (used in solution at bottom)
create a function which creates a handler function for you and use that in the loop body
function createIncrementHandler(input, howMuch){
return () => input.valueAsNumber += howMuch;
}
/// then in your loop body:
downButton.addEventListener('click', createIncrementHandler(score, 1));
get the correct input by using the event parameter in the handler
downButton.addEventListener('click', (event) => event.target.valueAsNumber += 1);
make the entire body of the loop into a function, for example:
function createInputs(i) {
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement("input");
score.type = "number";
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement( "button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', function() {
score.value++; });
//downbutton
var downButton = document.createElement( "button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', function() {
score.value--; });
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
Here is a full example of one of the possible fixes.
<html>
<title> Base Maker </title>
<body>
<div>
<hl> Score Keeper </h1>
<hr>
<input type="text" placeholder="How many players?">
<button id="enter" onclick="baseMaker()">
Enter
</button>
</div>
<p></p>
<script>
var parent = document.querySelector("p");
var input = document.querySelector("input");
var enter = document.getElementById("enter");
function incrementInput(input, byHowMuch) {
input.valueAsNumber = input.valueAsNumber + byHowMuch;
}
function baseMaker() {
for (var i = 0; i <= input.value; i++) {
//base
var base = document.createElement("p");
base.textContent = "Base " + (i + 1) + ":";
//score
var score = document.createElement("input");
score.type = "number";
score.setAttribute("id", "score" + i);
score.value = 20;
//upbutton
var upButton = document.createElement("button");
upButton.textContent = "+";
upButton.setAttribute("id", "upButton" + i)
upButton.addEventListener('click', incrementInput.bind(null, score, 1));
//downbutton
var downButton = document.createElement("button");
downButton.textContent = "-";
downButton.setAttribute("id", "downButton" + i)
downButton.addEventListener('click', incrementInput.bind(null, score, -1));
//populate data
parent.appendChild(base);
parent.appendChild(score);
parent.appendChild(upButton);
parent.appendChild(downButton);
}
input.value = "";
}
</script>
</body>
</html>
I will do that this way :
const
AllBases = document.querySelector('#bases')
, bt_Start = document.querySelector('#game-go')
, bt_newGame = document.querySelector('#new-game')
, playerCount = document.querySelector("#play-start > input")
;
playerCount.value = ''
playerCount.focus()
playerCount.oninput = () =>
{
playerCount.value.trim()
bt_Start.disabled = (playerCount.value === '' || isNaN(playerCount.value))
playerCount.value = (bt_Start.disabled) ? ''
: (playerCount.valueAsNumber > playerCount.max) ? playerCount.max
: (playerCount.valueAsNumber < playerCount.min) ? playerCount.min
: playerCount.value
}
bt_newGame.onclick = () =>
{
playerCount.value = ''
playerCount.disabled = false
bt_Start.disabled = true
bt_newGame.disabled = true
AllBases.innerHTML = ''
playerCount.focus()
}
bt_Start.onclick = () =>
{
playerCount.disabled = true
bt_Start.disabled = true
bt_newGame.disabled = false
for(let i = 0; i <= playerCount.valueAsNumber; i++)
{
let base = document.createElement('p')
base.countValue = 20 // create a counter property on <p>
base.innerHTML = `Base ${i+1} : <span>${base.countValue}</span> <button>+</button> <button>−</button>\n`
AllBases.appendChild(base)
}
}
AllBases.onclick = ({target}) =>
{
if (!target.matches('button')) return // verify clicked element
let countElm = target.closest('p')
if (target.textContent==='+') countElm.countValue++
else countElm.countValue--
countElm.querySelector('span').textContent = countElm.countValue
}
#bases p span {
display : inline-block;
width : 6em;
border-bottom : 2px solid aqua;
padding-right : .2em;
text-align : right;
margin : 0 .3em;
}
#bases p button {
width : 2em;
margin : 0 .1em;
cursor : pointer;
}
<hr>
<hl> Score Keeper </h1>
<hr>
<div id="play-start" >
<input type="number" placeholder="How many players?" min="2" max="4">
<button id="game-go" disabled> Enter </button>
<button id="new-game" disabled> new </button>
</div>
<hr>
<div id="bases"></div>
If it helps, I can add more explanations

Calculating width of a element incorrectly

I'm trying to calculate the width of block, id="titleText" I am getting some luck, although it calculates incorrectly.
For example, when empty it still shows pixels (by default, it should be one), yet 18px remains in this example:
(using onkeydown)
(using onkeyup)
and...
Triggering my style logic before the number I specified, which is 585.
My HTML is:
<input type="text" autocomplete="off" id="serpTitle"
onkeydown="checkTitleValue()" class="form-control" />
<p class="d-block" id="titleText"></p>
and the Javascript
function checkTitleValue() {
var fontSize = 12;
var measureTitle = document.getElementById("titleText");
measureTitle.style.fontSize = fontSize;
var height = (measureTitle.clientHeight + 1) + "px";
var width = (measureTitle.clientWidth + 1) + "px"
var inputTitle = document.getElementById("serpTitle").value;
document.getElementById("titleText").innerText = inputTitle;
document.getElementById("titlePixels").innerText = width;
if (measureTitle.clientWidth + 1 > 585) {
document.getElementById("titlePixels").style.color = "red";
}
else if (measureTitle.clientWidth + 1 < 585)
{
document.getElementById("titlePixels").style.color = null;
}
}
Could you please try this code snippet. I don't get the point of this measureTitle.clientWidth + 1 or measureTitle.clientWidth + 1 < 585
const FONT_SIZE = 12;
const MAX_LENGTH = 585;
var serpTitle = document.getElementById('serpTitle');
var mesured = document.getElementById('measured');
var maxLength = document.getElementById('max-length');
var measureCont = document.getElementById('mesure-cont');
function init() {
measureCont.style.fontSize = FONT_SIZE;
maxLength.innerHTML = MAX_LENGTH + 'px';
updateMesure();
}
function updateMesure() {
measureCont.innerHTML = serpTitle.value;
mesured.innerHTML = measureCont.clientWidth;
}
function checkTitleValue() {
updateMesure();
if (measureCont.clientWidth > MAX_LENGTH) {
measured.style.color = 'red';
} else {
measured.style.color = null;
}
}
init();
<div>
<input type="text" autocomplete="off" id="serpTitle" onkeyup="checkTitleValue()"
class="form-control" />
<span id="measured"></span>/<span id="max-length"></span>
</div>
<div>
<span style="display: inline-block" id="mesure-cont">aaaaa</span>
</div>
You should probably try calling the function on keyup instead of keydown.
Since each keystroke is ACTUALLY executed in the input box at keyup: Meaning.. (after) the key has been "pressed".
So your HTML code probably should go like:
<input type="text" autocomplete="off" id="serpTitle"
onkeyup="checkTitleValue()" class="form-control" />
<p class="d-block" id="titleText"></p>
one of the issue, regarding changing color, is that you first updating color then calculating it. So swap
if (measureTitle.clientWidth > 585) {
document.getElementById("titlePixels").style.color = "red";
}
else if (measureTitle.clientWidth < 585)
{
document.getElementById("titlePixels").style.color = null;
}
document.getElementById("titleText").innerText = inputTitle;
document.getElementById("titlePixels").innerText = width;

Javascript calculator-emptying the field before typing input

I am trying to build a calculator using JavaScript
var btn5 = document.getElementById('btn5');
var btn2 = document.getElementById('btn2');
var btn5multiply = document.getElementById('btn5multiply');
var result = document.getElementById('result');
var calInput = document.getElementById('calInput');
var backSpace = document.getElementById('backSpace');
var C = document.getElementById('C');
var blank = "Please enter a number";
btn5.addEventListener('click', runFunction5);
btn2.addEventListener('click', runFunction2);
multiply.addEventListener('click', multiplyFunction);
result.addEventListener('click', resultFunction);
backSpace.addEventListener('click', backSpaceFunction);
C.addEventListener('click', clearFunction);
function runFunction5() {
if(calInput.value == blank) {
calInput.value = "";
calInput.value += btn5.value;
} else {
calInput.value += btn5.value;
}
}
function runFunction2() {
calInput.value += btn2.value;
}
function multiplyFunction() {
calInput.value += multiply.value;
}
function resultFunction() {
if(calInput.value == "") {
calInput.value = blank;
} else {
var storeVal = calInput.value;
var cal = eval(storeVal);
calInput.value = cal;
}
}
function backSpaceFunction() {
var storeVal = calInput.value;
calInput.value = storeVal.substr(0, storeVal.length - 1);
}
function clearFunction() {
calInput.value = "";
}
<body>
<input id="calInput" type="text" disabled="true" value=""><br><br>
<button id="backSpace"><-</button>
<button id="btn5" value="5">5</button>
<button id="btn2" value="2">2</button>
<button id="multiply" value="*">X</button>
<button id="result">=</button>
<button id="C">C</button>
</body>
. In my code if someone presses the =key, it displays the message that says Please enter a number. Now I figured out the way to clear the field first when pressing the number key after pressing =key and appending every key pressed afterwards to the input field but there is too much typing of code as I have to assigned that condition to every numeric key, so is there a better way to achieve that ? Right now I have added that condition to only when 5 is pressed.
All you need to do is assign a common function to each of the buttons for their click event and within that handler, you can determine which button was actually clicked using the event.target.
Now, there's no need for an input field here at all. You aren't getting any input directly from it, you are actually using it as an output mechanism. Since you want it placed on its own line, a regular div is the better UI choice.
Next, instead of getting the value of your buttons, just work with the text that is the content of the buttons via the .textContent property of the element. This will make the HTML much simpler as well.
Now, you have eval() in your code as a way of taking the string you've built up and running it as an expression. eval() should be avoided all the time. There is hardly a use-case that requires it. It opens up security and performance problems in an application. This is a topic of some debate, but in my opinion, anyone that advocates for it is under-informed about eval() or JavaScript. It will take a little more code, but you can do the math without it.
This example answers your question and demonstrates my suggestions. I've even extended your scenario to include all the basic math operators, but there is still more that would need to be flushed on on this before it was ready for production deployment.
// Get both number buttons in an array:
var btns = Array.prototype.slice.call(document.querySelectorAll(".number"));
// Get all operator buttons in an array:
var operators = Array.prototype.slice.call(document.querySelectorAll(".operator"));
var operator = null; // Will store the last operator pressed
var result = document.getElementById('result');
var output = document.getElementById('output');
var back = document.getElementById('backspace');
var clear = document.getElementById('clear');
var blank = "Please enter a number";
// Loop over the buttons in the numbers array
btns.forEach(function(btn){
// Assign an event handler to the button
btn.addEventListener("click", btnFunction);
});
// Loop over the buttons in the operators array
operators.forEach(function(op){
// Assign an event handler to the button
op.addEventListener("click", function (evt) {
operator = evt.target.textContent; // Get the operator and store it
output.textContent += operator; // Display the operator in the expression
});
});
// Set up event handlers:
result.addEventListener("click", doMath);
clear.addEventListener("click", function() { output.textContent = ""; });
back.addEventListener("click", function(){
output.textContent = output.textContent.substring(0, output.textContent.length - 1);
});
// All event handling functions are automatically passed
// a reference to the event that triggered the function
function btnFunction(evt) {
// And that event object exposes the actual DOM object
// that triggered the event via the target property
if(output.textContent == blank) {
output.textContent = evt.target.textContent;
} else {
output.textContent += evt.target.textContent;
}
}
function doMath() {
// Check for no math to do yet
if(output.textContent === ""){
output.textContent = blank;
}
// Break up the expression into an array with the operands serving to delimit the parts
var operands = output.textContent.split(/[+-/*]/);
// Do the math:
switch (operator){
case "+" :
// Operands is an array, so we want to do the math with the two items in the array which
// we get by passing indexes of 0 and 1 to the array.
output.textContent += " = " + (parseInt(operands[0], 10) + parseInt(parseInt(operands[1], 10)));
break;
case "-" :
output.textContent += " = " + (parseInt(operands[0], 10) - parseInt(parseInt(operands[1], 10)));
break;
case "*" :
output.textContent += " = " + parseInt(operands[0], 10) * parseInt(parseInt(operands[1], 10));
break;
case "/" :
output.textContent += " = " + parseInt(operands[0], 10) / parseInt(parseInt(operands[1], 10));
break;
}
}
#output { height:1em; padding:3px; }
<body>
<!-- No need for an input element here. -->
<div id="output"></div>
<button id="backspace">←</button>
<button class="number">5</button>
<button class="number">2</button>
<button class="operator">+</button>
<button class="operator">-</button>
<button class="operator">*</button>
<button class="operator">/</button>
<button id="result">=</button>
<button id="clear">C</button>
</body>
You could determine the value of the currently clicked button, like this:
function numberClickHandler() {
calInput.value += this.value;
}
Now we only need to assign this to all buttons, e.g.:
["btn2", "btn3"].forEach(id =>
document
.getElementById(id)
.onclick = numberClickHandler
);
A little modification in the HTML will solve your issue. I suggest you add a placeholder attribute in the input. Placeholder will disappear once there is a value in input and will reappear when there is none.
More about placeholder: https://www.w3schools.com/tags/att_input_placeholder.asp
Demo: http://jsfiddle.net/lotusgodkk/GCu2D/2194/
HTML:
<input id="calInput" type="text" disabled="true" value="" placeholder="Please enter a number">
<br>
<br>
<button id="backSpace">>
</button>
<button id="btn5" value="5">5</button>
<button id="btn2" value="2">2</button>
<button id="multiply" value="*">X</button>
<button id="result">=</button>
<button id="C">C</button>
JS:
var btn5 = document.getElementById('btn5');
var btn2 = document.getElementById('btn2');
var btn5multiply = document.getElementById('btn5multiply');
var result = document.getElementById('result');
var calInput = document.getElementById('calInput');
var backSpace = document.getElementById('backSpace');
var C = document.getElementById('C');
var blank = "Please enter a number";
btn5.addEventListener('click', runFunction5);
btn2.addEventListener('click', runFunction2);
multiply.addEventListener('click', multiplyFunction);
result.addEventListener('click', resultFunction);
backSpace.addEventListener('click', backSpaceFunction);
C.addEventListener('click', clearFunction);
function runFunction5() {
calInput.value += btn5.value;
}
function runFunction2() {
calInput.value += btn2.value;
}
function multiplyFunction() {
calInput.value += multiply.value;
}
function resultFunction() {
var storeVal = calInput.value;
var cal = eval(storeVal);
calInput.value = cal;
}
function backSpaceFunction() {
var storeVal = calInput.value;
calInput.value = storeVal.substr(0, storeVal.length - 1);
}
function clearFunction() {
calInput.value = "";
}
Once, you do that you will not have to add that condition in each case.
var numericValues = document.getElementById('numericValue');
var result = document.getElementById('result');
var calInput = document.getElementById('calInput');
var backSpace = document.getElementById('backSpace');
var C = document.getElementById('C');
var blank = "Please enter a number";
numericValues.addEventListener('click', pushNumericValue);
multiply.addEventListener('click', multiplyFunction);
result.addEventListener('click', resultFunction);
backSpace.addEventListener('click', backSpaceFunction);
C.addEventListener('click', clearFunction);
function pushNumericValue(event) {
var btnTarget = event.target
if(calInput.value == blank) {
calInput.value = "";
calInput.value += btnTarget.value;
} else {
calInput.value += btnTarget.value;
}
}
function multiplyFunction() {
calInput.value += multiply.value;
}
function resultFunction() {
if(calInput.value == "") {
calInput.value = blank;
} else {
var storeVal = calInput.value;
var cal = eval(storeVal);
calInput.value = cal;
}
}
function backSpaceFunction() {
var storeVal = calInput.value;
calInput.value = storeVal.substr(0, storeVal.length - 1);
}
function clearFunction() {
calInput.value = "";
}
<body>
<input id="calInput" type="text" disabled="true" value=""><br><br>
<button id="backSpace"><-</button>
<div id="numericValue">
<button id="btn5" value="1">1</button>
<button id="btn5" value="2">2</button>
<button id="btn5" value="3">3</button>
<button id="btn2" value="4">4</button>
</div>
<button id="multiply" value="*">X</button>
<button id="result">=</button>
<button id="C">C</button>
</body>
One way to do it
Is using event delegation instead of listening all numeric values and doing an specific action. Define a parent div that have as children all numeric values and listen to it thanks to the event.target attribute you can get its value of the clicked button

Why does my value keep returning as "NaN"?

Here is the link to the jsbin.
I was almost finished with my project (I thought I was) and then I tested it out. It is supposed to add buttons with the chosen title of the task and the number of points it awards. Every time the button is clicked the points would be added on to the "Points" section and every 500 points my "Level" would increase.
Upon finishing it, it worked. Then I went to clear the localStorage since that's what I used to save the information, but I wanted to start over. When I did that, the 'Points' section, or 'results' value, keeps returning as "NaN". The code is exactly the same as it was when it worked. Can someone please tell me how to fix this problem, thank you in advance.
Here is the code. (Used bootstrap for CSS)
HTML
<center>
<br>
<h2> Add task </h2>
<div class='well' style='width:500px' id="addc">
<div id="addc">
<input class='form-control' style='width:450px' id="btnName" type="text" placeholder="New Task" /><br>
<input class='form-control' style='width:450px' id="btnPoints" type="text" placeholder="Points" /><br>
<button id="addBtn">Add</button>
</div> </div>
<div class='well' style='width:230px' id="container">
</div>
<hr style="width:400px;">
<h3>Points </h3>
<div id="result">0</div>
</div>
<hr style="width:400px;">
<div style="width:400px;">
<h3>Level
<p id='lvl'>0</p>
</div>
<hr style="width:400px;">
</center>
JavaScript
var res = document.getElementById('result');
res.innerText = localStorage.getItem('myResult');
var level = document.getElementById('lvl');
level.textContent = localStorage.getItem('myLevel');
var btns = document.querySelectorAll('.btn');
for(var i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
}
var addBtn = document.getElementById('addBtn');
addBtn.className = "btn btn-default";
addBtn.addEventListener('click', function() {
var container = document.getElementById('container');
var btnName = document.getElementById('btnName').value;
var btnPoints = parseInt(document.getElementById('btnPoints').value);
if(!btnName)
btnName = "Button ?";
if(!btnPoints)
btnPoints = 50;
var newBtn = document.createElement('button');
var newPnt = document.createElement('span');
newBtn.className = 'btn btn-danger';
newBtn.innerText = btnName;
newBtn.setAttribute('data-points', btnPoints);
newBtn.addEventListener('click', function() {
addToResult(this.getAttribute('data-points'));
this.parentNode.removeChild(this.nextElementSibling);
this.parentNode.removeChild(this);
});
newPnt.className = 'label';
newPnt.innerText = "+" + btnPoints;
container.appendChild(newBtn);
container.appendChild(newPnt);
});
function addToResult(pts) {
var result = document.getElementById('result');
result.innerText = parseInt(result.innerText) + parseInt(pts);
var lvl = 0;
var a = 100;
while (result.innerText > 5*a) {
lvl+=1;
a+=100;
}
document.getElementById('lvl').innerText = lvl;
var res = document.getElementById('result');
localStorage.setItem("myResult", res.innerText);
var level = document.getElementById('lvl');
localStorage.setItem("myLevel", level.textContent);
}
You were parsing result.innerText as a number, but its value, initially, was actually either NaN or nothing, both which end up being NaN. One fix is to just check if it parsed to a number, and if it didn't, fall back to 0.
I just basically changed that and removed some getElementByIds that, in my opinion, were redundant, check the addToResult function:
http://jsfiddle.net/owc26a0p/1/
function addToResult(pts) {
// NaN is falsy, so you can just use || to make a fallback to 0
var result = parseInt(resDiv.innerText, 10) || 0,
lvl = 0,
a = 100;
result = result + parseInt(pts, 10) || 0;
while (result > 5 * a) {
lvl += 1;
a += 100;
}
resDiv.innerText = result;
levelDiv.innerText = lvl;
localStorage.setItem("myResult", result);
localStorage.setItem("myLevel", levelDiv.textContent);
}
I ended up using jsFiddle since I couldn't always get jsBin to save my changes. Good luck.

Categories