How do I simplify my code by making one addAndSubtract function? - javascript

Like the title says, I would like to simplify this JavaScript so that I have one addAndSubtract function for the buttons.
I am quite new and I have no idea how to go about it.
Here is the code:
let add= document.querySelector("#add");
let subtract = document.querySelector("#subtract");
add.addEventListener("click",function(){
let output = document.querySelector("#output");
let result = Number(output.innerText) + 1;
if (result >10){
result = 10;
}
output.innerText = result;
});
subtract.addEventListener("click",function(){
let output = document.querySelector("#output")
let result = Number(output.innerText) - 1;
if (result<0){
result=0;
}
output.innerText = result;
});
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
<script defer src="script.js"></script>
<title>Counter</title>
</head>
<body>
<h1>Le Count!</h1>
<div class = "Counter_Container">
<button id="subtract">-</button><span id="output">0</span><button id="add">+</button>
</div>
</body>
</html>

You can read the ID of the button being clicked in the handler, and act accordingly. (The switch could be a series of ifs too.)
function handleClick(event) {
const action = event.target.id;
const output = document.querySelector("#output");
let value = parseInt(output.innerText);
switch (action) {
case "add":
value++;
break;
case "subtract":
value--;
break;
}
value = Math.min(10, Math.max(value, 0)); // clamp to 0..10
output.innerText = value;
}
document.querySelector("#subtract").addEventListener("click", handleClick);
document.querySelector("#add").addEventListener("click", handleClick);
<h1>Le Count!</h1>
<div class="Counter_Container">
<button id="subtract">-</button><span id="output">0</span><button id="add">+</button>
</div>

Create a single function which takes your result number and add/subtract as parameter.
function eventer(result_param, arithmat){
let output = document.querySelector("#output")
if(arithmat){
let result = Number(output.innerText) + 1;
}else{
let result = Number(output.innerText) - 1;
}
if (result<result_param){
result=0;
}
}
Always try to make your similar code converted to reusable functions and if_else to ternary operators.

You need to create a function as following
function operation(val,maxvalue,minvalue){
let output = document.querySelector("#output")
let result = Number(output.innerText) + val;
if (result<minvalue){
result=minvalue;
}
if (result>maxvalue){
result=maxvalue;
}
output.innerText = result;
}
And use as below
let subtract = document.querySelector("#subtract");
subtract.addEventListener("click",operation.bind(this,-1,10,0))
let add = document.querySelector("#add");
add.addEventListener("click",operation.bind(this,1,10,0))
Let me know if you face any issue

Just add a data attribute to each button that describes the operation that should be performed. Use the same click handler and check the attribute for which operation should be performed.
It's also easier to keep track of the value in a scoped variable too.
let value = 0;
const output = document.querySelector("#output");
const buttons = document.querySelectorAll(".operation");
const operations = {
add: () => value = Math.min(++value, 10),
subtract: () => value = Math.max(--value, 0)
};
const setOutput = () => {
output.innerText = value;
};
// set initial output value
setOutput();
[...buttons].forEach((button) => {
button.addEventListener('click', (e) => {
const operation = e.target.dataset.operation;
let func = operations[operation];
func && func();
setOutput();
});
});
<h1>Le Count!</h1>
<div class="Counter_Container">
<button id="subtract" class="operation" data-operation="subtract">-</button>
<span id="output"></span>
<button id="add" class="operation" data-operation="add">+</button>
<button id="multiply" class="operation" data-operation="multiply">*</button>
</div>

Related

I am trying to push a value onto an array with .push(), but it stops pushing values once the array length reaches two

I'm trying to create a javascript calculator for The Odin Project. I finally felt like I was making a bit of progress, after headbutting my keyboard for hours, and then this weird bug arose.
In the function where I add event listeners to the operator buttons, I am trying to push the current operator (the last one which was clicked) on to an array which keeps track of the operator buttons which have been clicked ('newOperators.push(e.target.innerText)').
If I spam the operator button, it pushes on to the array just fine. But when I am trying to chain together a series of operations, the newOperators.push() method seems to quit after the array length reaches two.
To test, I added another dummy array and pushed letters onto it on using another push() method, which I put on the line above newOperators.push(), and that seems to work just fine. I've tried switching newOperators.push() to newOperators.unshift() and that has the same issue.
Losing my mind here, any help would be much appreciated!
Javascript:
let display = document.querySelector('.display');
let title = document.querySelector('.title');
let plus = document.querySelector('.plus');
let minus = document.querySelector('.minus');
let times = document.querySelector('.multiply');
let divide = document.querySelector('.divide');
let equal = document.querySelector('.equal');
let period = document.querySelector('.period');
let one = document.querySelector('.one');
let two = document.querySelector('.two');
let three = document.querySelector('.three');
let four = document.querySelector('.four');
let five = document.querySelector('.five');
let six = document.querySelector('.six');
let seven = document.querySelector('.seven');
let eight = document.querySelector('.eight');
let nine = document.querySelector('.nine');
let nought = document.querySelector('.nought');
let buttons = document.querySelectorAll('button');
let operators = document.querySelectorAll('.operator');
let numbers = document.querySelectorAll('.number');
let currentCalc = [];
let currentOp = '';
let firstNumber = 0;
let secondNumber = 0;
let thirdNumber = 0;
let firstStash = 0;
let secondStash = 0;
let total = 0;
let calculated = false;
let newOperators = [];
const add = function(a,b) {
return a + b;
};
const subtract = function(a,b) {
return a - b;
};
const multiply = function(a,b) {
return a * b
};
const division = function(a,b) {
return a / b
};
function operate(fnum,snum, op) {
if(op === '+') {
let sum = add(fnum,snum);
return sum;
} else if(op === '-') {
let sum = subtract(fnum,snum);
return sum;
} else if(op === 'x') {
let sum = multiply(fnum,snum);
return sum;
} else if(op === '/') {
let sum = division(fnum,snum);
return sum;
}
}
let fNumArr = [];
let sNumArr = [];
let tNumArr = [];
numbers.forEach((e) => {
e.addEventListener('click', (e) => {
console.log('numberFunc', newOperators)
if(newOperators.length < 1) {
fNumArr.push(e.target.innerText)
firstNumber = parseInt(fNumArr.join(''));
console.log('first',firstNumber);
display.textContent = firstNumber;
} else if( newOperators.length = 1) {
sNumArr.push(e.target.innerText);
secondNumber = parseInt(sNumArr.join(''));
console.log('second',secondNumber);
display.textContent = secondNumber;
} else if(newOperators.length > 1) {
tNumArr.push(e.target.innerText);
thirdNumber = parseInt(tNumArr.join(''));
console.log('third',thirdNumber);
display.textContent = thirdNumber;
}
})
})
operators.forEach((e) => {
e.addEventListener('click', (e) => {
console.log(currentOp)
newOperators.push(e.target.innerText);
console.log('topOfOp',newOperators)
display.innerText = '';
if(newOperators.length === 1) {
} else if(newOperators.length === 2) {
console.log(operate(firstNumber,secondNumber,newOperators[1]));
total = operate(firstNumber,secondNumber,newOperators[1]);
display.innerText = total;
firstNumber = total;
secondNumber = 0;
fNumArr = [];
fNumArr.push(total)
sNumArr = [];
}
})
})
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caculator</title>
<link rel="stylesheet" href="styles.css">
<script src="./app.js" defer></script>
</head>
<body>
<h1 class="title">Calculator</h1>
<div class="container">
<div class="calculator">
<div class="display">This will print result</div>
<button class="clear">Clear</button>
<button class="plus operator">+</button>
<button class="minus operator">-</button>
<button class="multiply operator">x</button>
<button class="divide operator">/</button>
<button class="equal ">=</button>
<button class="one number">1</button>
<button class="two number">2</button>
<button class="three number">3</button>
<button class="four number">4</button>
<button class="five number">5</button>
<button class="six number">6</button>
<button class="seven number">7</button>
<button class="eight number">8</button>
<button class="nine number">9</button>
<button class="nought number">0</button>
<button class="period number">.</button>
</div>
</div>
</body>
</html>
In your numbers.forEach loop you made the mistake of:
if( newOperators.length = 1)
You should fix that.
Also, a little advice as you are starting out (I am also starting out WebDev):
You should name your variables clearly even of they are too long.
Refractor your code into functions and files for example make it so you pass in a callback to your event listeners and get rid of repetitive code. Remember keep it DRY (Don't Repeat Your code)

How do I adjust the code so that the image appears when the website loads and the guess is guessing what I want it to guess?

<!DOCTYPE html>
<html>
<body>
<p id="Image"></p>
Basically what im tryijngto do s
One fix I'd recommend would be splitting your logic into two functions, one the user clicks to check their answer, and one they click to see the next question. This will allow you to display the congrats message on the screen rather than in an alert. Here is that in action:
let score = 0;
let questionsAsked = 0;
const button = document.querySelector('button');
const input = document.getElementById('userInput');
const gameScore = document.getElementById('game-score-inner');
gameScore.add = (pts = 1) => gameScore.innerHTML = parseInt(gameScore.textContent) + 1;
gameScore.subtract = (pts = 1) => gameScore.innerHTML = Math.max(parseInt(gameScore.textContent) - 1, 0);
const checkMessage = document.getElementById('check-message');
checkMessage.set = message => checkMessage.innerHTML = message;
checkMessage.clear = message => checkMessage.innerHTML = '';
const options = {
chad: 'https://via.placeholder.com/600x400/000000/efebe9/?text=Chad',
bob: 'https://via.placeholder.com/600x400/000000/efebe9/?text=Bob',
john: 'https://via.placeholder.com/600x400/000000/efebe9/?text=John'
}
function askQuestion() {
checkMessage.clear();
input.value = '';
const optionsNames = Object.values(options);
const randomPhoto = optionsNames[Math.floor(Math.random() * optionsNames.length)];
document.getElementById('image').innerHTML = `<img src="${randomPhoto}" id="question-image" width="250" height="250" />`;
button.setAttribute('onclick','checkAnswer()');
button.textContent = 'Check Your Answer!';
}
function checkAnswer() {
const userGuess = options[input.value.toLowerCase()];
const correctAnswer = document.getElementById('question-image').getAttribute('src');
if (options[input.value.toLowerCase()] === correctAnswer) {
checkMessage.set('CONGRATULATIONS!!! YOU GUESSED IT RIGHT');
gameScore.add();
} else {
checkMessage.set('SORRY, IT WAS INCORRECT');
gameScore.subtract();
}
questionsAsked++;
button.setAttribute('onclick','askQuestion()');
button.textContent = 'Next Question';
}
askQuestion();
<p id="image"></p>
<p id="game-score">Score: <span id="game-score-inner">0</span></p>
<button onclick="checkAnswer()">Start Game!</button>
<input id="userInput" type="text" />
<p id="check-message"></p>
If you would prefer to keep everything in one function and use alerts for the congrats message, you can do so by keeping track of then number of questions asked, and not instantly checking the answer on the first load, like this:
let score = 0;
let questionsAnswered = -1;
const imageContainer = document.getElementById('image');
const button = document.querySelector('button');
const input = document.getElementById('user-input');
const gameScore = document.getElementById('game-score-inner');
gameScore.add = (pts = 1) => gameScore.innerHTML = parseInt(gameScore.textContent) + 1;
gameScore.subtract = (pts = 1) => gameScore.innerHTML = Math.max(parseInt(gameScore.textContent) - 1, 0);
const options = {
chad: 'https://via.placeholder.com/250x250/000000/efebe9/?text=Chad',
bob: 'https://via.placeholder.com/250x250/000000/efebe9/?text=Bob',
john: 'https://via.placeholder.com/250x250/000000/efebe9/?text=John'
}
function askQuestion() {
questionsAnswered++;
const optionsNames = Object.values(options);
const randomPhoto = optionsNames[Math.floor(Math.random() * optionsNames.length)];
if (questionsAnswered) {
const userGuess = options[input.value.toLowerCase()];
const correctAnswer = document.getElementById('question-image').getAttribute('src');
if (options[input.value.toLowerCase()] === correctAnswer) {
gameScore.add();
alert('CONGRATULATIONS!!! YOU GUESSED IT RIGHT');
} else {
gameScore.subtract();
alert('SORRY, IT WAS INCORRECT');
}
questionsAnswered++;
}
imageContainer.innerHTML = `<img src="${randomPhoto}" id="question-image" width="250" height="250" />`;
input.value = '';
}
askQuestion();
<p id="image"></p>
<p id="game-score">Score: <span id="game-score-inner">0</span></p>
<button onclick="askQuestion()">Check Answer!</button>
<input id="user-input" type="text" />
Both solutions would work fine with alerts, though the first solution offers some greater flexibility for any functions you make want to perform in between questions. One other main fix there was to make here was to check change the image after checking the answer, and also making sure to actually fun the function in the beginning using askQuestion() in this case. I also added a couple of handy functions gameScore.add() and gameScore.subtract() to ease future use.
You can pass in other integers such as gameScore.add(2) if you every wanted to have double-weighted questions. I also added a Math.max() line to ensure the score never passes below 0. You can remove this if you would like the player's score to pass into negative numbers.
Here is a working version of your game. To begin: <br>
1.Your code was not modifying the src of the image (thus no image appears) <br>
1a. I am modifying the src attribute associated with the `img` tag now. <br>
1b. `document.getElementById("Image").src = randomPhoto;` <br>
2. `theArrayArray` does not exist. I updated the variable to `theArray` <br>
3. To display an image when the game begins you need a handler. <br>
3a. I added the `button` to handle that <br>
4. Unless you want the user to type out `.jpg` you need to remove .jpg <br>
4a. `randomPhoto = randomPhoto.replace(".jpg", "");` <br>
<img id="Image" src="#" width="250" height="250">
<br>
<br>
<input id="userInput" type="text">
<br>
<br>
<button type="button" id="btn" onclick="startGame()">Start Game</button>
<span id="GameScore">Score:</span>
<script>
let score = 10;
var Chad = "Chad.jpg";
let begin = 1;
let thePhoto;
var someArray = [ Chad, Bob
];
function startGame() {
if (start == 0) {
for (var l = 2; i < 3; i--) {
randomPhoto = theArray[Math.floor(Math.random()*theArray.length)];
document.getElementById("Image").src = randomPhoto;
document.getElementById("btn").innerHTML = "Submit";
start = 1;
}
} else {
randomPhoto = randomPhoto.replace(".jpg", "Insert");
}
else {
for (var x = 0; i < 3; i++) {
TheName = theArray[Math.floor(Math.random()*theArray.length)];
document.getElementById("Image").src = theName;
alert("No");
scorex = score-1;
}
document.getElementById("theScore").innerHTML="Score: "+score;
</script>
</body>
</html>

What can I do to mix operations ? with vanilla javascript [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm working on a simple calculator that implements a sum, rest, multiplication, and division.
I would like to take the inner text inside of any button with the class "number" to use it later like a number to pass through a function that does the math.
These are the functions to work with the calculator.
const add = (num1, num2) => {
return num1 + num2;
};
const subtract = (num1, num2) => {
return num1 - num2;
};
const multiply = (num1, num2) => {
return num1 * num2;
};
const divide = (num1, num2) => {
return num1 / num2;
};
// Our Buttons
const outPut = document.getElementById('output');
const num = document.getElementsByClassName('number');
const addBtn = document.querySelector('.addOperator');
const subtractBtn = document.querySelector('.subtractOperator');
const multiplyBtn = document.querySelector('.multiplyOperator');
const divideBtn = document.querySelector('.divideOperator');
const allClear = document.querySelector('.ac');
const equals = document.querySelector('.equals');
let plusFirsValue = '';
let secondValue = 0;
let subFirstValue = 0;
let multFirstValue = 0;
let divFirstValue = 0;
for(let i = 0; i < num.length; i++) {
num[i].addEventListener('click', () => {
outPut.innerText += num[i].innerText;
console.log(outPut.innerText);
});
};
addBtn.addEventListener('click', () => {
plusFirsValue = Number(outPut.innerText);
outPut.innerText = '';
console.log(plusFirsValue);
});
subtractBtn.addEventListener('click', () => {
subFirstValue = Number(outPut.innerText);
outPut.innerText = '';
console.log(plusFirsValue);
});
multiplyBtn.addEventListener('click', () => {
multFirstValue = Number(outPut.innerText);
outPut.innerText = '';
});
divideBtn.addEventListener('click', () => {
divFirstValue = Number(outPut.innerText);
outPut.innerText = '';
});
equals.addEventListener('click', () => {
secondValue = Number(outPut.innerText);
if (plusFirsValue && secondValue) {
outPut.innerText = add(plusFirsValue, secondValue);
console.log(add(plusFirsValue, secondValue));
} else if (subFirstValue && secondValue) {
outPut.innerText = subtract(subFirstValue, secondValue);
console.log(subtract(subFirstValue, secondValue));
} else if (multFirstValue && secondValue) {
outPut.innerText = multiply(multFirstValue, secondValue);
console.log(multiply(multFirstValue, secondValue));
} else if (divFirstValue && secondValue) {
outPut.innerText = divide(divFirstValue, secondValue);
console.log(divide(divFirstValue, secondValue));
}
});
allClear.addEventListener('click', () => {
outPut.innerText = '';
})
<div id="calculator-grid">
<div id="output"></div>
<button class="ac">AC</button>
<button class="sun">Sun</button>
<button class="divideOperator">÷</button>
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="multiplyOperator">*</button>
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="addOperator">+</button>
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="subtractOperator">-</button>
<button class="number">0</button>
<button class="number">.</button>
<button class="equals">=</button>
</div>
Some of the implementation I would like to do is a mix between operations that means, after a sum between 2 numbers I want to rest other. For example 3 + 3 = 6 but then 6 - 3 = 3 in the same operation. What can I do?
Notice that in your code the first selector (of button with class of 'number') you assign an array with less members than the second selector (where you select ALL the buttons) however in the loop you using the index of numbers.
const btn = document.getElementsByTagName('button');
const inp = document.getElementById('output');
for (let i = 0; i < btn.length; ++i) {
btn[i].addEventListener('click', () => {
inp.innerText += btn[i].innerText;
});
Event listeners added to all of the button and the innerText of the div with id of 'output' is modified by clicking one of the buttons.

Element text not changing when passing selected textContent and new value to an update function

I'm creating a CRUD page where the user can add, delete and edit text, but I have an issue in updating the text after I select it for edit.
In editText function when I click the edit button the text that was added will pop up inside the input field. When I click on the update button (triggering the updateText function), I can see the text in console log but the corresponding html is not updated.
HTML
<div class="main">
<form>
<input type="text" placeholder="search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">update</button>
</div>
</div>
Javascript
const inputsearch = document.querySelector('form input');
const addInputBtn = document.querySelector('#add');
const update = document.querySelector('#update');
addInputBtn.addEventListener('click', addtext);
function addtext(){
let li = document.createElement('li');
let inputadd = document.querySelector('.add-text');
let addedtext = inputadd.value;
let h1Tag = '<h1 id="text">'+addedtext+'</h1>';
let tags = h1Tag + '<button id="delete">Delete</button><button id="edit">Edit</button>';
if(addedtext == ''){
alert('please add some text');
return;
}else{
li.innerHTML = tags;
document.querySelector('ul').appendChild(li);
}
li.querySelectorAll('#delete')[0].addEventListener('click', deleteText);
li.querySelectorAll('#edit')[0].addEventListener('click', editText);
getlist(li, h1Tag);
inputadd.value = '';
}
function deleteText(e) {
e.target.parentNode.remove();
document.querySelector('.add-text').value = '';
}
function editText(e) {
let currentText = e.target.parentNode.firstChild.textContent;
let currentValue = document.querySelector('.add-text');
currentValue.value = currentText;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText = currentValue.value
console.log(currentText = currentValue.value);
}
}
function getlist(li, h1Tag) {
inputsearch.addEventListener('keyup', serchText);
function serchText(e) {
let typetext = e.target.value.toLowerCase();
if(h1Tag.toLowerCase().indexOf(typetext) != -1){
li.style.display = 'block';
}else{
li.style.display = 'none';
}
}
}
To solve the issue without changing your overall approach, your edit button click needs to get the corresponding element (not just its textContent) and pass it to your getupdate() function to be updated when your update button is clicked. Relatively minor changes to your current functions:
function editText(e) {
const currentText = e.target.parentNode.firstChild;
const currentValue = document.querySelector('.add-text');
currentValue.value = currentText.textContent;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText.textContent = currentValue.value;
}
}
There are some other issues with your code, particularly the creation of multiple elements with the same id (which is malformed and will likely become problematic as you add additional features). Following is a snippet that addresses that issue as well as simplifying some of your functions and fixing the search.
const search = document.querySelector('form input');
const input = document.querySelector('.add-text');
const container = document.querySelector('ul');
let items = null;
let currentItem = null;
const searchItems = (event) => {
if (items) {
const s = event.currentTarget.value.toLowerCase();
for (const item of items) {
if (item.firstChild.textContent.toLowerCase().indexOf(s) !== -1) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
}
}
};
const deleteItem = (event) => {
currentItem = null;
event.currentTarget.parentNode.remove();
};
const editItem = (event) => {
currentItem = event.currentTarget.parentNode.firstChild;
input.value = currentItem.textContent;
};
const updateItem = () => {
if (currentItem) {
currentItem.textContent = input.value;
}
};
const addItem = () => {
let val = input.value
if (val) {
const li = document.createElement('li');
let inner = '<h1 class="text">' + val + '</h1>';
inner += '<button class="delete">Delete</button>';
inner += '<button class="edit">Edit</button>';
li.innerHTML = inner;
container.appendChild(li);
val = '';
currentItem = li.firstChild;
items = document.querySelectorAll('li');
for (let del of document.querySelectorAll('.delete')) {
del.addEventListener('click', deleteItem);
}
for (let edit of document.querySelectorAll('.edit')) {
edit.addEventListener('click', editItem);
}
} else {
alert('please add some text');
return;
}
};
search.addEventListener('keyup', searchItems);
document.querySelector('#add').addEventListener('click', addItem);
document.querySelector('#update').addEventListener('click', updateItem);
<div class="main">
<form>
<input type="text" placeholder="Search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">Update</button>
</div>
</div>

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

Categories