I have just started learning JavaScript and doing my first project by following Frontend Masters tutorial. Calculator is working perfectly fine except a problem. When i press any mathematical operator button (after passing the first number) the screen shows 0. I want it to show the last pressed number and not 0.
I just want to display the last entered number on screen when someone press any of maths operators like addition, subtraction.
let runningTotal = 0;
let bufferNumber = '0';
let previousOperator;
const display = document.querySelector('.display')
//initializing function to execute when a button is clicked
document
.querySelector(".calc-buttons")
.addEventListener("click", function(event) {
clickButton(event.target.innerText);
});
//This function checks if selected value is number or symbol
function clickButton(value) {
if (isNaN(parseInt(value))) {
handleSymbol(value);
} else {
handleNumber(value);
}
rerender()
}
//This function handles the display of number
//this is where initia displayed 0 will be handled
function handleNumber(value) {
if (bufferNumber === '0') {
bufferNumber = value;
} else {
bufferNumber += value;
}
console.log('buffer number is ', bufferNumber);
}
//This function executes different symbols.
function handleSymbol(value) {
switch(value) {
case 'C':
bufferNumber = "0";
runningTotal = 0;
previousOperator =null;
break;
case '←':
if (bufferNumber.length === 1) {
bufferNumber = "0";
} else {
bufferNumber = bufferNumber.substring(0, bufferNumber.length-1);
}
break;
case '=':
console.log('= operator displaying result')
if (previousOperator === null) {
return;
}
flushOperation(parseInt(bufferNumber));
previousOperator = null
bufferNumber = "" + runningTotal;
runningTotal = 0;
break;
default:
console.log('default');
handleMath(value);
break;
}
}
//handles DMAS
// We need to convert strings to integers before doing maths calculations on it
function handleMath(value) {
console.log('handle math function')
const intBuffer = parseInt(bufferNumber);
if (runningTotal === 0) {
runningTotal = intBuffer;
} else {
flushOperation(intBuffer);
}
previousOperator = value;
console.log('previous operator is', previousOperator)
bufferNumber = "0";
}
function flushOperation(intBuffer){
console.log('flush operation')
if (previousOperator === "+"){
runningTotal += intBuffer;
} else if (previousOperator === "−"){
runningTotal -= intBuffer;
} else if (previousOperator === "×"){
runningTotal *= intBuffer;
} else {
runningTotal /= intBuffer;
}
}
function rerender() {
display.innerText = bufferNumber;
}
* {
box-sizing: border-box;
}
body {
margin-left: 30%;
padding: 0;
}
.calc {
width: 400px;
background-color: black;
color: white;
}
.display {
font-family: 'Courier New', Courier, monospace;
font-size: 40px;
text-align: right;
padding: 20px 5px;
}
.calc-button {
background-color: rgb(206, 203, 203);
color: black;
height: 100px;
width: 24.5%;
border: none;
font-size: 40px;
cursor: pointer;
}
.calc-button:hover {
background-color: rgb(252, 249, 249);
}
.calc-button:active {
background-color: gray;
}
.calc-button:last-child {
background-color: rgb(209, 158, 62);
}
.calc-button:last-child:hover {
background-color: rgb(228, 189, 118);
}
.calc-button:last-child:active {
background-color:white;
}
.double {
width: 49.7%;
}
.triple {
width: 74.9%;
}
.calc-rows {
display: flex;
align-content: stretch;
justify-content: space-between;
margin-bottom: 0.5%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calculator</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- container for overall calculator-->
<div class='calc'>
<section class="display">
0
</section>
<section class="calc-buttons">
<div class="calc-rows">
<button class="double calc-button">C</button>
<button class="calc-button">←</button>
<button class="calc-button">÷</button>
</div>
<div class="calc-rows">
<button class="calc-button">7</button>
<button class="calc-button">8</button>
<button class="calc-button">9</button>
<button class="calc-button">×</button>
</div>
<div class="calc-rows">
<button class="calc-button">4</button>
<button class="calc-button">5</button>
<button class="calc-button">6</button>
<button class="calc-button">−</button>
</div>
<div class="calc-rows">
<button class="calc-button">1</button>
<button class="calc-button">2</button>
<button class="calc-button">3</button>
<button class="calc-button">+</button>
</div>
<div class="calc-rows">
<button class="calc-button triple">0</button>
<button class="calc-button">=</button>
</div>
</section>
</div>
<script src="script.js"></script>
</body>
</html>
I have solved this problem by changing a few things.
when clicking on any of the operator buttons the screen was showing 0 because when the operator was clicked handleSymbol() was called and then handleMath() get called from the default case and the handleMath() function assigned the bufferNumber value of 0.
Removing bufferNumber = "0"; in handleNumber() creates another problem which is bufferNumber is concatenating two numbers into one. for e.g, if we do 5 + 6, the bufferNumber would become 56
the bufferNumber should store only one number which is the number before clicking the operator and there must be another variable to store another number. I have named this var as newBufferNumber
in handleSymbol() function I have added these lines to make the calculator keep working if the calculation continues without clicking the = button.
const ifAnySymbolSelected = value == '÷' ||
value == '×' ||
value == '+' ||
value == '−';
if(bufferNumber && newBufferNumber && ifAnySymbolSelected ) {
console.log(value, bufferNumber, newBufferNumber)
flushOperation(parseInt(bufferNumber), parseInt(newBufferNumber));
}
handleNumber() function contains few changes
Replacing the line
if (bufferNumber === '0') {
bufferNumber = value;
}
with
if(symbolSelected) {
newBufferNumber = newBufferNumber + value
}
to store another digit which the number we click, after clicking calculating operators.
On the screen, I am displaying both numbers including the operator. you can always control what you want to show on the screen.
these are the major things I changed. I want you to go through all of it and observe.
hope this helps.
Working fiddle:
let runningTotal = 0;
let bufferNumber = '';
let newBufferNumber = '';
let previousOperator;
const display = document.querySelector('.display')
//initializing function to execute when a button is clicked
document
.querySelector(".calc-buttons")
.addEventListener("click", function(event) {
clickButton(event.target.innerText);
});
//This function checks if selected value is number or symbol
function clickButton(value) {
if (isNaN(parseInt(value))) {
handleSymbol(value);
}
else {
handleNumber(value);
}
rerender()
}
//This function handles the display of number
//this is where initia displayed 0 will be handled
let symbolSelected ;
function handleNumber(value) {
if(symbolSelected) {
newBufferNumber = newBufferNumber + value
}
else {
bufferNumber += value;
}
console.log(bufferNumber,newBufferNumber)
}
//This function executes different symbols.
function handleSymbol(value) {
// if calculation goes regularly without clicking '=' operator
const ifAnySymbolSelected = value == '÷' ||
value == '×' ||
value == '+' ||
value == '−';
if(bufferNumber && newBufferNumber && ifAnySymbolSelected ) {
console.log(value, bufferNumber, newBufferNumber)
flushOperation(parseInt(bufferNumber), parseInt(newBufferNumber));
}
if (ifAnySymbolSelected) {
symbolSelected = true;
newBufferNumber = ''
}
else{
symbolSelected = false;
}
switch (value) {
case 'C':
bufferNumber = "0";
runningTotal = 0;
previousOperator = null;
previousOperator = null;
break;
case '←':
if (bufferNumber.length === 1) {
bufferNumber = "0";
} else {
bufferNumber = bufferNumber.substring(0, bufferNumber.length - 1);
}
break;
case '=':
if (previousOperator === null) {
return;
}
flushOperation(parseInt(bufferNumber), parseInt(newBufferNumber));
previousOperator = null
bufferNumber = runningTotal;
break;
default: handleMath(value); break;
}
}
// handles DMAS
// We need to convert strings to integers before doing maths calculations on it
function handleMath(value) {
const intBuffer = parseInt(bufferNumber);
if (runningTotal === 0) {
runningTotal = intBuffer;
}
previousOperator = value;
}
function flushOperation(intBuffer,newBufferNumber){
console.log('flush operation')
if (previousOperator === "+"){
runningTotal = intBuffer + newBufferNumber;
} else if (previousOperator === "−"){
runningTotal = intBuffer - newBufferNumber;
} else if (previousOperator === "×"){
runningTotal = intBuffer * newBufferNumber;
} else {
runningTotal = intBuffer / newBufferNumber;
}
bufferNumber = runningTotal;
}
function rerender() {
const displayText = `${bufferNumber} ${previousOperator ? previousOperator : ''} ${ previousOperator ? newBufferNumber : ''}`
display.innerText = displayText;
}
* {
box-sizing: border-box;
}
body {
margin-left: 30%;
padding: 0;
}
.calc {
width: 400px;
background-color: black;
color: white;
}
.display {
font-family: 'Courier New', Courier, monospace;
font-size: 40px;
text-align: right;
padding: 20px 5px;
}
.calc-button {
background-color: rgb(206, 203, 203);
color: black;
height: 100px;
width: 24.5%;
border: none;
font-size: 40px;
cursor: pointer;
}
.calc-button:hover {
background-color: rgb(252, 249, 249);
}
.calc-button:active {
background-color: gray;
}
.calc-button:last-child {
background-color: rgb(209, 158, 62);
}
.calc-button:last-child:hover {
background-color: rgb(228, 189, 118);
}
.calc-button:last-child:active {
background-color:white;
}
.double {
width: 49.7%;
}
.triple {
width: 74.9%;
}
.calc-rows {
display: flex;
align-content: stretch;
justify-content: space-between;
margin-bottom: 0.5%;
}
.as-console-wrapper{display: none!important;}
<!-- container for overall calculator-->
<div class='calc'>
<section class="display">
</section>
<section class="calc-buttons">
<div class="calc-rows">
<button class="double calc-button">C</button>
<button class="calc-button">←</button>
<button class="calc-button">÷</button>
</div>
<div class="calc-rows">
<button class="calc-button">7</button>
<button class="calc-button">8</button>
<button class="calc-button">9</button>
<button class="calc-button">×</button>
</div>
<div class="calc-rows">
<button class="calc-button">4</button>
<button class="calc-button">5</button>
<button class="calc-button">6</button>
<button class="calc-button">−</button>
</div>
<div class="calc-rows">
<button class="calc-button">1</button>
<button class="calc-button">2</button>
<button class="calc-button">3</button>
<button class="calc-button">+</button>
</div>
<div class="calc-rows">
<button class="calc-button triple">0</button>
<button class="calc-button">=</button>
</div>
</section>
</div>
Related
<!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>Calculator</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.2/dist/css/bootstrap.min.css"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Calculator</h1>
<div class="calculator">
<div class="first-row">
<div id="screen">
<div class="previous"></div>
<div class="current"></div>
</div>
<button id="clear-btn" class="btn">C</button>
</div>
<div class="other-rows">
<button class="btn number seven">7</button>
<button class="btn number eight">8</button>
<button class="btn number nine">9</button>
<button class="btn operator division">/</button>
</div>
<div class="other-rows">
<button class="btn number four">4</button>
<button class="btn number five">5</button>
<button class="btn number six">6</button>
<button class="btn operator multiply">x</button>
</div>
<div class="other-rows">
<button class="btn number one">1</button>
<button class="btn number two">2</button>
<button class="btn number three">3</button>
<button class="btn operator minus">-</button>
</div>
<div class="other-rows">
<button class="btn decimal">.</button>
<button class="btn number zero">0</button>
<button class="btn equal">=</button>
<button class="btn operator plus">+</button>
</div>
</div>
</body>
</html>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
.btn {
height: 75px;
width: 75px;
margin: 15px;
font-size: 40px;
}
.number {
border: 1px solid blue;
border-radius: 10px;
}
.number:hover {
background-color: lightblue;
}
.operator {
border: 1px solid red;
border-radius: 10px;
}
.operator:hover {
background-color: lightcoral;
}
.decimal {
border: 1px solid peru;
border-radius: 10px;
}
.decimal:hover {
background-color: peachpuff;
}
.equal {
border: 1px solid green;
border-radius: 10px;
}
.equal:hover {
background-color: lightgreen;
}
#clear-btn {
border: 1px solid violet;
border-radius: 10px;
}
#clear-btn:hover {
background-color: lavender;
}
.first-row {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
#screen {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
width: 300px;
border: 3px solid rosybrown;
height: 75px;
margin: 15px;
}
.previous {
font-size: 20px;
}
.current {
font-size: 30px;
}
h1 {
font-family: cursive;
font-size: 80px;
color: salmon;
}
body {
background-color: lightyellow;
}
.calculator {
border: 1px solid black;
}
let operator = "";
let previousValue = "";
let currentValue = "";
document.addEventListener("DOMContentLoaded", () => {
let decimal = document.querySelector(".decimal");
let equal = document.querySelector(".equal");
let clear = document.querySelector("#clear-btn");
let operators = document.querySelectorAll(".operator");
let numbers = document.querySelectorAll(".number");
let previousScreen = document.querySelector(".previous");
let currentScreen = document.querySelector(".current");
numbers.forEach((number) => {
number.addEventListener("click", (e) => {
handleNumber(e.target.textContent);
currentScreen.textContent = currentValue;
});
});
operators.forEach((op) =>
op.addEventListener("click", function (e) {
handleOperator(e.target.textContent);
previousScreen.textContent = previousValue + " " + operator;
currentScreen.textContent = currentValue;
})
);
clear.addEventListener("click", () => {
previousValue = "";
currentValue = "";
operator = "";
previousScreen.textContent = currentValue;
currentScreen.textContent = currentValue;
});
equal.addEventListener("click", () => {
if (currentValue != "" && previousValue != "") {
calculate();
previousScreen.textContent = "";
if (previousValue.length <= 5) {
currentScreen.textContent = previousValue;
} else {
currentScreen.textContent = previousValue.slice(0, 5) + "...";
}
}
});
decimal.addEventListener("click", () => {
addDecimal();
});
});
function handleNumber(num) {
if (currentValue.length <= 5) {
currentValue += num;
}
}
function handleOperator(op) {
operator = op;
previousValue = currentValue;
currentValue = "";
}
function calculate() {
previousValue = Number(previousValue);
currentValue = Number(currentValue);
if (operator === "+") {
previousValue += currentValue;
} else if (operator === "-") {
previousValue -= currentValue;
} else if (operator === "x") {
previousValue *= currentValue;
} else if (operator === "/") {
previousValue /= currentValue;
}
previousValue = roundNum(previousValue);
previousValue = previousValue.toString();
currentValue = previousValue.toString();
}
function roundNum(num) {
return Math.round(num * 1000) / 1000;
}
function addDecimal() {
if (!currentValue.includes(".")) {
currentValue += ".";
}
}
window.onkeydown = function (e) {
e.preventDefault();
let x = e.key;
let choice;
let currentScreen = document.querySelector(".current");
switch (x) {
case "1":
choice = document.querySelector(".one");
choice.click();
break;
case "2":
choice = document.querySelector(".two");
choice.click();
break;
case "3":
choice = document.querySelector(".three");
choice.click();
break;
case "4":
choice = document.querySelector(".four");
choice.click();
break;
case "5":
choice = document.querySelector(".five");
choice.click();
break;
case "6":
choice = document.querySelector(".six");
choice.click();
break;
case "7":
choice = document.querySelector(".seven");
choice.click();
break;
case "8":
choice = document.querySelector(".eight");
choice.click();
break;
case "9":
choice = document.querySelector(".nine");
choice.click();
break;
case "0":
choice = document.querySelector(".zero");
choice.click();
break;
case "/":
choice = document.querySelector(".division");
choice.click();
break;
case "*":
choice = document.querySelector(".multiply");
choice.click();
break;
case "-":
choice = document.querySelector(".minus");
choice.click();
break;
case "+":
choice = document.querySelector(".plus");
choice.click();
break;
case ".":
choice = document.querySelector(".decimal");
choice.click();
break;
case "Enter":
choice = document.querySelector(".equal");
choice.click();
break;
case "Backspace":
currentScreen.textContent = currentScreen.textContent
.toString()
.slice(0, -1);
break;
}
};
The current screen in my calculator function responds to the keyboard input of backspace and removes the last value but when I input another value it shows up again. It seems to only temporarily remove it. Is this issue due to it being stored in memory ? I tried to use slicing but it does seem to work in case "Backspace".
In your switch case "Backspace", you only edit the text value on the HTML, but don't update the currentValue. When you press the other actions, it uses the currentValue, so your previous change gets overwritten.
case "Backspace":
currentValue = currentScreen.textContent
.toString()
.slice(0, -1);
currentScreen.textContent = currentValue;
break;
I added a working solution as well, so you can test it out.
let operator = "";
let previousValue = "";
let currentValue = "";
document.addEventListener("DOMContentLoaded", () => {
let decimal = document.querySelector(".decimal");
let equal = document.querySelector(".equal");
let clear = document.querySelector("#clear-btn");
let operators = document.querySelectorAll(".operator");
let numbers = document.querySelectorAll(".number");
let previousScreen = document.querySelector(".previous");
let currentScreen = document.querySelector(".current");
numbers.forEach((number) => {
number.addEventListener("click", (e) => {
handleNumber(e.target.textContent);
currentScreen.textContent = currentValue;
});
});
operators.forEach((op) =>
op.addEventListener("click", function (e) {
handleOperator(e.target.textContent);
previousScreen.textContent = previousValue + " " + operator;
currentScreen.textContent = currentValue;
})
);
clear.addEventListener("click", () => {
previousValue = "";
currentValue = "";
operator = "";
previousScreen.textContent = currentValue;
currentScreen.textContent = currentValue;
});
equal.addEventListener("click", () => {
if (currentValue != "" && previousValue != "") {
calculate();
previousScreen.textContent = "";
if (previousValue.length <= 5) {
currentScreen.textContent = previousValue;
} else {
currentScreen.textContent = previousValue.slice(0, 5) + "...";
}
}
});
decimal.addEventListener("click", () => {
addDecimal();
});
});
function handleNumber(num) {
if (currentValue.length <= 5) {
currentValue += num;
}
}
function handleOperator(op) {
operator = op;
previousValue = currentValue;
currentValue = "";
}
function calculate() {
previousValue = Number(previousValue);
currentValue = Number(currentValue);
if (operator === "+") {
previousValue += currentValue;
} else if (operator === "-") {
previousValue -= currentValue;
} else if (operator === "x") {
previousValue *= currentValue;
} else if (operator === "/") {
previousValue /= currentValue;
}
previousValue = roundNum(previousValue);
previousValue = previousValue.toString();
currentValue = previousValue.toString();
}
function roundNum(num) {
return Math.round(num * 1000) / 1000;
}
function addDecimal() {
if (!currentValue.includes(".")) {
currentValue += ".";
}
}
window.onkeydown = function (e) {
e.preventDefault();
let x = e.key;
let choice;
let currentScreen = document.querySelector(".current");
switch (x) {
case "1":
choice = document.querySelector(".one");
choice.click();
break;
case "2":
choice = document.querySelector(".two");
choice.click();
break;
case "3":
choice = document.querySelector(".three");
choice.click();
break;
case "4":
choice = document.querySelector(".four");
choice.click();
break;
case "5":
choice = document.querySelector(".five");
choice.click();
break;
case "6":
choice = document.querySelector(".six");
choice.click();
break;
case "7":
choice = document.querySelector(".seven");
choice.click();
break;
case "8":
choice = document.querySelector(".eight");
choice.click();
break;
case "9":
choice = document.querySelector(".nine");
choice.click();
break;
case "0":
choice = document.querySelector(".zero");
choice.click();
break;
case "/":
choice = document.querySelector(".division");
choice.click();
break;
case "*":
choice = document.querySelector(".multiply");
choice.click();
break;
case "-":
choice = document.querySelector(".minus");
choice.click();
break;
case "+":
choice = document.querySelector(".plus");
choice.click();
break;
case ".":
choice = document.querySelector(".decimal");
choice.click();
break;
case "Enter":
choice = document.querySelector(".equal");
choice.click();
break;
case "Backspace":
currentValue = currentScreen.textContent
.toString()
.slice(0, -1);
currentScreen.textContent = currentValue;
break;
}
};
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
.btn {
height: 75px;
width: 75px;
margin: 15px;
font-size: 40px;
}
.number {
border: 1px solid blue;
border-radius: 10px;
}
.number:hover {
background-color: lightblue;
}
.operator {
border: 1px solid red;
border-radius: 10px;
}
.operator:hover {
background-color: lightcoral;
}
.decimal {
border: 1px solid peru;
border-radius: 10px;
}
.decimal:hover {
background-color: peachpuff;
}
.equal {
border: 1px solid green;
border-radius: 10px;
}
.equal:hover {
background-color: lightgreen;
}
#clear-btn {
border: 1px solid violet;
border-radius: 10px;
}
#clear-btn:hover {
background-color: lavender;
}
.first-row {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
#screen {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: flex-end;
width: 300px;
border: 3px solid rosybrown;
height: 75px;
margin: 15px;
}
.previous {
font-size: 20px;
}
.current {
font-size: 30px;
}
h1 {
font-family: cursive;
font-size: 80px;
color: salmon;
}
body {
background-color: lightyellow;
}
.calculator {
border: 1px solid black;
}
<!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>Calculator</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.2/dist/css/bootstrap.min.css"
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Calculator</h1>
<div class="calculator">
<div class="first-row">
<div id="screen">
<div class="previous"></div>
<div class="current"></div>
</div>
<button id="clear-btn" class="btn">C</button>
</div>
<div class="other-rows">
<button class="btn number seven">7</button>
<button class="btn number eight">8</button>
<button class="btn number nine">9</button>
<button class="btn operator division">/</button>
</div>
<div class="other-rows">
<button class="btn number four">4</button>
<button class="btn number five">5</button>
<button class="btn number six">6</button>
<button class="btn operator multiply">x</button>
</div>
<div class="other-rows">
<button class="btn number one">1</button>
<button class="btn number two">2</button>
<button class="btn number three">3</button>
<button class="btn operator minus">-</button>
</div>
<div class="other-rows">
<button class="btn decimal">.</button>
<button class="btn number zero">0</button>
<button class="btn equal">=</button>
<button class="btn operator plus">+</button>
</div>
</div>
</body>
</html>
I'm creating a calculator using HTML, CSS, and JavaScript. I have one problem in my code. When a user clicks an operator after entering a number, the operator stays highlighted until the user enters the second number. The problem is, when the user enters the second number, the first number on the display does not disappear. So the second number gets concatenated to the first number. How can I solve this problem? When the user enters the second number, I want the display to clear the previous number and start displaying whatever the user is entering.
I have this in idea in pseudo code but don't know how to implement it because I don't know if pausing an element using JavaScript is possible:
After the operator is clicked, pause the display for the user but remove everything from the display under the hood.
When the user clicks one of the digits, stop pausing the display and show everything to the user.
By doing so, the first number would still be visible to the user while the operator is highlighted.
However, once the user has started entering the second number, the display would display only the second number.
I'm trying to achieve something like this: https://mrbuddh4.github.io/calculator/
In this example, when a user clicks an operator, the number on the display does not disappear. When a digit is clicked after the operator, the previous number disappears and the display starts showing the current number being entered.
// Basic math operations
function add(a, b) {
return parseInt(a) + parseInt(b);
}
function subtract(a, b) {
return parseInt(a) - parseInt(b);
}
function multiply(a, b) {
return parseInt(a) * parseInt(b);
}
function divide(a, b) {
return parseInt(a) / parseInt(b);
}
function operate(operator, a, b) {
if (operator === "+") {
return add(a, b);
} else if (operator === "-") {
return subtract(a, b);
} else if (operator === "*") {
return multiply(a, b);
} else if (operator === "/") {
return divide(a, b);
}
}
function displayValue(e) {
operators.forEach(operator => operator.classList.remove("active"));
if (display.textContent === "0") {
display.textContent = e.target.textContent;
} else if (display.textContent !== "0") {
display.textContent += e.target.textContent;
let paddingLeftValue = parseInt(window.getComputedStyle(display)
.getPropertyValue("padding-left")) - 30;
display.style.paddingLeft = `${paddingLeftValue}px`;
}
}
function getValue() {
if (firstDisplayValue) {
secondDisplayValue = display.textContent;
console.log(`second value: ${secondDisplayValue}`);
} else {
firstDisplayValue = display.textContent;
console.log(`first value: ${firstDisplayValue}`);
}
}
function getValueAndOp(e) {
operators.forEach(operator => operator.classList.remove("active"));
e.target.classList.add("active");
getValue();
if (e.target.getAttribute("id") === "divide") {
operator = "/";
} else if (e.target.getAttribute("id") === "multiply") {
operator = "*";
} else if (e.target.getAttribute("id") === "subtract") {
operator = "-";
} else if (e.target.getAttribute("id") === "add") {
operator = "+";
}
}
function calculate() {
operators.forEach(operator => operator.classList.remove("active"));
getValue();
let solution = operate(operator, firstDisplayValue, secondDisplayValue);
display.textContent = solution;
let solutionLength = solution.toString().length;
let paddingLeftValue = 440 - (solutionLength - 1) * 30;
display.style.paddingLeft = `${paddingLeftValue}px`;
}
// Declare the main variables
let firstDisplayValue;
let secondDisplayValue;
let operator;
// Create the display variable
const display = document.querySelector(".display");
// Add event listeners to the digits
const buttons = document.querySelectorAll("#one, #two, #three, #four, #five," +
" #six, #seven, #eight, #nine, #zero, #dot");
buttons.forEach(button => button.addEventListener("click", displayValue));
// Add event listeners to the operators
const operators = document.querySelectorAll(".operator");
operators.forEach(operator => operator.addEventListener("click", getValueAndOp));
// Add an event listener to =
const equal = document.querySelector("#equal");
equal.addEventListener("click", calculate);
* {
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 97vh;
}
.calc {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
border: 5px solid black;
border-radius: 25px;
height: 660px;
width: 500px;
padding: 5px 0 5px 0;
gap: 4px;
}
.calc>div {
width: 480px;
}
.display {
height: 130px;
font-size: 60px;
padding: 60px 0 0 440px;
}
.buttons {
display: flex;
flex-wrap: wrap;
max-height: 470px;
flex: auto;
gap: 12px;
padding: 8px 0 1px 8px;
}
.buttons>button {
font-size: 40px;
height: 75px;
width: 107px;
border-radius: 50%;
background-color: rgb(231, 230, 230);
border: none;
transition: 4ms;
}
.clear {
width: 345px !important;
background-color: rgb(62, 198, 251) !important;
color: white;
}
#zero {
width: 225px !important;
}
.clear, #zero {
border-radius: 50px !important;
}
.operator, #equal {
background-color: rgb(6, 118, 223) !important;
color: white !important;
}
button:active {
background-color: rgb(163, 163, 163);
}
.clear:active {
background-color: rgb(0, 162, 255) !important;
}
#equal:active {
background-color: rgb(0, 0, 204) !important;
}
.active {
background-color: rgb(0, 0, 204) !important;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Calculator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="calc">
<div class="display">0</div>
<div class="buttons">
<button class="clear">Clear</button>
<button class="operator" id="divide">÷</button>
<button id="seven">7</button>
<button id="eight">8</button>
<button id="nine">9</button>
<button class="operator" id="multiply">×</button>
<button id="four">4</button>
<button id="five">5</button>
<button id="six">6</button>
<button class="operator" id="subtract">−</button>
<button id="one">1</button>
<button id="two">2</button>
<button id="three">3</button>
<button class="operator" id="add">+</button>
<button id="zero">0</button>
<button id="dot">.</button>
<button id="equal">=</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
When the user enters the second number, I want the display to clear the previous number and start displaying whatever the user is entering.
So you just need to "remember" that a click on an operator button happened, so that you can react accordingly, when the next number button gets clicked.
Set a flag (clearDisplay or similar) to true, when one of the operator buttons gets clicked.
When one of the numbers gets clicked, check if that flag is set first, and if so, clear your display, before setting the flag to false again.
I'm working on a tictactoe Person vs Person game. As a bonus, we can try to implement a minimax algorithm to play against the computer. After numerous trials and errors, I think I have the function so far, that it goes through the calculation without an error. However, the return value for best Score is always -10, assuming the player and not the computer would win.
I have two problems in the code:
the minimax-function always returns the value -10, assuming the person would win.
I cant play the last turn. In the debugger I can see that my gameData array, that keeps track of the visible field, works normally like so: [0,"X","X","O","X","O","O",7,"X"]. But the arrays player.person and player.computer have already stored the 0 and the 7. This should not happen.
At this point I am stuck. And I would tell you what I have been trying so far, but the last couple hours were just poking in the dark pretty much. Therefore the least I can do is write down the steps the code takes till the end:
Important variables etc:
Computer is represented by "O", person by "X"
Array gameData: Starts as [0,1,2,...,8] and replaces the numbers with "X" or "O". It tries to prevent that the tictactoe fields can be selected more than once.
Object player with .person-Array and .computer-Array both start as empty. I use these to check if either of them won the game.
isWinner(PLAYER) iterates through the winning conditions and checks if person or computer match it. The function returns the object ({win:true}) if so.
isTie() checks if there is a tie. It returns the object ({tie:true]), if the conditions isWinner(player.computer) = false, isWinner(player.person) = false and emptySpaces(gameData).length = 0 are met.
the function bestMove() searches for the bestMove of computer. Here's where minimax gets executed.
Code Logic overall:
the code starts at line 140 with function vsComputerGame()
next step is function personMove() in line 301
the player's choice "X" gets stored in the gameData Array. EG gameData = [0,"X",2,...,8]. And the position of "X" (in the exp 1`) gets pushed into player.person.
next it checks, if the person won the game or the game is a tie.
next the function bestMove() gets executed. It chooses a tictactoe-field for the computer.
next player.person and player.computer get updated. Without this step, minimax keeps pushing numbers in those arrays.
Code logic bestMove() and minimax():
bestMove() starts at line 190
the initial player.person and player.computer are saved, to restore them, right after the minimax() function returns a value. Same problem as above: Otherwise, isWinner() returns true on the second click of the player.
for loop gets executed. It selects the first available spot in gameData and replaces it with an "O". player.computer gets updated with this possible move from the computer.
then minimax gets executed, which basically has the same code for both player.computer and player.person, as described in this for loop.
when minimax() returns a value, it get stored in the variable score.
now the gameData Array, player.person and player.computer are reset, so the next iteration of the for loop does not flood them.
at last the if (score.eval > bestScore) checks for the highest score. If highest, the index of the current iteration gets stored in the move variable and is then used to place the "O" on the visible field and inside gameData.
"use strict"
// this function stores the chosen players (condition: player1, player2, computer). The start-game is in another module
let menupage = (function() {
let playerSelection = document.querySelectorAll(".player-selection");
let modalContainer = document.querySelector(".modal-bg");
let submitName = document.querySelector("#submit");
let btnColorPlayerTwo = document.querySelector("#player-two");
let btnColorComputer = document.querySelector("#computer");
let btnColorplayerOne = document.querySelector("#player-one");
let modalClose = document.querySelector(".modal-close");
let inputField = document.querySelector("#name");
let isplayerOne;
let gameModeData = {
playerOne : "",
playerTwo : "",
computer : false,
}
function closeModal() {
inputField.value = "";
modalContainer.classList.remove("bg-active");
}
function submitPlayer() {
if (isplayerOne === true) {
if (inputField.value === "") {
alert("Please enter your battle-tag");
} else if (inputField.value !== "") {
btnColorplayerOne.style.backgroundColor = "#4CAF50";
gameModeData.playerOne = inputField.value;
inputField.value = "";
modalContainer.classList.remove("bg-active");
}
}
if (isplayerOne === false) {
if (inputField.value === "") {
alert("Please enter your battle-tag");
} else if (inputField.value !== "") {
gameModeData.playerTwo = inputField.value;
btnColorPlayerTwo.style.backgroundColor = "#f44336";
gameModeData.computer = false;
btnColorComputer.style.backgroundColor = "#e7e7e7";
inputField.value = "";
modalContainer.classList.remove("bg-active");
}
}
}
function definePlayer(id, color) {
modalClose.addEventListener("click", closeModal);
if (id === "player-one") {
if (color.backgroundColor === "" || color.backgroundColor === "rgb(231, 231, 231)") {
isplayerOne = true;
modalContainer.classList.add("bg-active");
submitName.addEventListener("click", submitPlayer);
} else if (color.backgroundColor === "rgb(76, 175, 80)") {
color.backgroundColor = "#e7e7e7";
gameModeData.playerOne = "";
}
}
if (id === "player-two") {
if (color.backgroundColor === "" || color.backgroundColor === "rgb(231, 231, 231)") {
isplayerOne = false;
modalContainer.classList.add("bg-active");
submitName.addEventListener("click", submitPlayer);
}
}
}
function defineOponent(target) {
if (target.backgroundColor === "rgb(0, 140, 186)") {
return;
} else if (target.backgroundColor === "rgb(231, 231, 231)" || target.backgroundColor === "") {
target.backgroundColor = "#008CBA";
btnColorPlayerTwo.style.backgroundColor = "#e7e7e7";
gameModeData.playerTwo = "";
gameModeData.computer = true;
}
}
let setupPlayers = function setupPlayers() {
if (this.id === "player-one" || this.id === "player-two") {
definePlayer(this.id, this.style);
} else if (this.id === "computer") {
defineOponent(this.style);
}
}
playerSelection.forEach(button => button.addEventListener("click", setupPlayers))
return gameModeData;
}())
let startRound = (function startRound() {
let startGameBtn = document.querySelector("#start-game");
let startScreen = document.querySelector(".start-screen");
let gameboard = document.querySelector(".gameboard");
let selectionMenu = document.querySelector(".window-container");
let frame = document.querySelector(".frame");
let scoreboardPlayer = document.querySelector(".scoreboard-left");
let scoreboardOponent = document.querySelector(".scoreboard-right");
let scorePlayer = document.querySelector(".scoreboard-player");
let scoreOponent = document.querySelector(".scoreboard-oponent");
function displayScore() {
scorePlayer.innerText = menupage.playerOne;
menupage.computer === false ? scoreOponent.innerText = menupage.playerTwo : scoreOponent.innerText = "Computer";
}
function startGame() {
if (menupage.playerOne === "") {
alert("Please choose your profile.");
} else if (menupage.playerTwo === "" && menupage.computer === false) {
alert("Please choose an opponent.")
} else {
startScreen.style.display = "none";
gameboard.style.display = "grid";
scoreboardPlayer.style.display = "grid";
scoreboardOponent.style.display = "grid";
frame.style.display = "none";
selectionMenu.style.gridTemplateAreas = '"header header header" "scoreboard-left gameboard scoreboard-right" "frame frame frame"';
displayScore();
game();
}
}
startGameBtn.addEventListener("click", startGame);
}())
/* ***************************** GAME VS COMPUTER FUNCTION STARTS HERE ************************* */
let vsComputerGame = (function vsComputerGame() {
let player = {
person : [],
computer : [],
}
let gameData = [0, 1, 2, 3, 4, 5, 6, 7, 8]
let isWinner = function isWinner(PLAYER) {
let check = PLAYER.join();
let condition = {
1 : ["0","1","2"],
2 : ["3","4","5"],
3 : ["6","7","8"],
4 : ["0","4","8"],
5 : ["2","4","6"],
6 : ["0","3","6"],
7 : ["1","4","7"],
9 : ["2","5","8"]
}
for (const property in condition) {
if (condition[property].every(v => check.includes(v)) === true) {
return ({win : true});
}
}
return ({win : false });
};
let isTie = function isTie() {
if (emptySpaces(gameData).length === 0 && isWinner(player.computer).win === false && isWinner(player.person).win === false) {
return ({tie: true});
} else {
return ({tie : false});
}
}
function emptySpaces(gameData) {
let updatedBoard = [];
for (let i = 0; i < gameData.length; i++) {
if (gameData[i] !== "X") {
if (gameData[i] !== "O") {
updatedBoard.push(gameData[i]);
}
}
}
return updatedBoard;
}
function bestMove() {
let bestScore = -Infinity;
let move;
// the object player with the values {player:[], computer:[]} is used in isWinner to check who won,
// storedComputer and storedPlayer is needed, to reset both arrays after they go through minimax,
// without, the two object-arrays get fludded
let storedComputer = player.computer.map(x => x);
let storedPlayer = player.person.map(x => x);
// first round of the for loop sets a field for the computer,
// first execution of minimax jumps to player.person
for (let i = 0; i < 9; i++) {
// gameData is the Array, that stores the players' moves. Example: [0, 1, 2, "X", 4, 5, "O", 7, 8]
if (gameData[i] !== "X") {
if (gameData[i] !== "O") {
gameData[i] = "O";
player.computer.push(i);
let score = minimax(gameData, player.person);
gameData[i] = i;
player.person = storedPlayer;
player.computer = storedComputer;
if (score.eval > bestScore) {
bestScore = score.eval;
move = i;
console.log(bestScore);
}
}
}
}
// after a move is found for the computer, O gets logged in the gameData Array and on the visible gameboard
let positionO = document.getElementsByName(move);
gameData[move] = "O";
positionO[0].innerText = "O";
}
function minimax(gameData, PLAYER) {
// the BASE of minimax.
// ************ console.log shows, that it always returns -10 ***************
if (isWinner(player.person).win === true) { return ({eval:-10});}
if (isWinner(player.computer).win === true) { return ({eval:10});}
if (isTie().tie === true) {return ({eval:0});};
/*
PLAYER.push pushes the index-number into either player.computer or player.person
This is needed to check the isWinner function
After that, these Arrays get stored in storedComputer and storedPlayer
*/
if (PLAYER === player.computer) {
let bestScore = -Infinity;
for (let i = 0; i < 9; i++) {
if (gameData[i] !== "X") {
if (gameData[i] !== "O") {
PLAYER.push(i);
//let storedComputer = player.computer.map(x => x);
//let storedPlayer = player.person.map(x => x);
gameData[i] = "O";
let score = minimax(gameData, player.person);
//player.person, player.computer and gameData are resetted, after minimax returns a value
gameData[i] = i;
//player.person = storedPlayer;
//player.computer = storedComputer;
if (score.eval > bestScore) {
bestScore = score.eval;
}
}
}
}
return bestScore;
} else {
let bestScore = Infinity;
for (let i = 0; i < 9; i++) {
if (gameData[i] !== "X") {
if (gameData[i] !== "O") {
PLAYER.push(i);
//let storedComputer = player.computer.map(x => x);
//let storedPlayer = player.person.map(x => x);
gameData[i] = "X";
let score = minimax(gameData, player.computer);
//player.person = storedPlayer;
//player.computer = storedComputer;
gameData[i] = i;
if (score.eval < bestScore) {
bestScore = score.eval;
}
}
}
}
return bestScore;
}
}
let cells = document.querySelectorAll(".cell");
cells.forEach(cell => cell.addEventListener("click", personMove));
function personMove() {
if (this.innerText === "X" || this.innerText === "O") {
return;
} else {
let playersChoice = this.getAttribute("data-parent");
player.person.push(Number(this.getAttribute("data-parent")));
this.innerText = "X";
gameData[playersChoice] = "X";
if (isWinner(player.person).win === true) {
console.log("Win");
};
isTie();
bestMove();
player.computer = [];
player.person = [];
for (let i = 0; i < 9; i++) {
if (gameData[i] === "X") {
player.person.push(i);
} else if (gameData[i] === "O") {
player.computer.push(i);
}
}
}
}
})
/* ***************************** GAME VS COMPUTER FUNCTION ENDS HERE ************************* */
let vsPersonGame = (function vsPersonGame() {
let i = 1;
let player = [];
let oponent = [];
let buttons = document.querySelectorAll(".cell");
buttons.forEach(button => button.addEventListener("click", selection));
function selection() {
let newLocal = this
storeSelection(newLocal);
checkWinner();
}
function storeSelection(input) {
if (i >= 10 || input.innerText !== "") {
return;
} else if (i % 2 === 0) {
return input.innerText = "O", oponent.push(input.dataset.parent),
i++;
} else if (i % 2 !== 0) {
return input.innerText = "X", player.push(input.dataset.parent),
i++;
}
}
function checkWinner() {
let condition = {
1 : ["0","1","2"],
2 : ["3","4","5"],
3 : ["6","7","8"],
4 : ["0","4","8"],
5 : ["2","4","6"],
6 : ["0","3","6"],
7 : ["1","4","7"],
9 : ["2","5","8"]
}
for (const property in condition) {
let toStringplayer = player.join();
let toStringoponent = oponent.join();
if (condition[property].every(v => toStringplayer.includes(v)) === true) {
return alert(menupage.playerOne + " won");
} else if (condition[property].every(v => toStringoponent.includes(v)) === true) {
return alert(menupage.playerTwo + " won");
} else if (i === 10) {
if (condition[property].every(v => toStringplayer.includes(v)) === true) {
return alert(menupage.playerOne + " won");
} else if (condition[property].every(v => toStringoponent.includes(v)) === true) {
return alert(menupage.playerTwo + " won");
} else {
return alert("You tied");
}
}
}
}
})
let game = (function() {
if (menupage.computer === true) {
vsComputerGame();
} else {
vsPersonGame();
}
});
html, body {
display: grid;
height: 100%;
margin: 0;
padding: 0;
}
.window-container {
display: grid;
height: 100%;
grid-template-rows: 10% 80% 10%;
grid-template-areas:
"header header header"
". start-screen ."
"frame frame frame";
}
.header {
grid-area: header;
margin-top: 50px;
font-size: 30px;
text-align: center;
color: red;
font-weight: bolder;
}
.start-screen {
grid-area: start-screen;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 30%;
}
.selection-menu {
flex: 1;
display: grid;
grid-template-rows: 40% 20% 40%;
grid-template-areas:
". . player-two"
"player-one vs ."
". . computer"
}
#player-one {
grid-area: player-one;
background-color: #e7e7e7;
}
#player-two {
grid-area: player-two;
background-color: #e7e7e7;
}
#computer {
grid-area: computer;
background-color: #e7e7e7;
}
#start-game {
display: flex;
cursor: pointer;
border: none;
color: white;
background-color: rgb(37, 36, 36);
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
#vs {
grid-area: vs;
text-align: center;
font-size: 30px;
font-weight: bold;
color: #4CAF50;
}
.player-selection {
cursor: pointer;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
.gameboard {
grid-area: gameboard;
margin-top: 10%;
display: none;
justify-content: center;
grid-template-rows: 150px 150px 150px;
grid-template-columns: 150px 150px 150px;
grid-template-areas:
"tL tM tR"
"mL mM mR"
"bL bM bR";
}
.frame {
grid-area: frame;
display: flex;
position: fixed;
height: 250px;
bottom: 0px;
left: 0px;
right: 0px;
margin-bottom: 0px;
justify-content: center;
align-items: center;
}
.cell {
display: flex;
justify-content: center;
align-items: center;
font-size: 40px;
cursor: pointer;
}
.unselectable {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#tL {
grid-area: tL;
border-bottom: 2px solid black;
border-right: 2px solid black;
}
#tM {
grid-area: tM;
border-bottom: 2px solid black;
border-right: 2px solid black;
}
#tR {
grid-area: tR;
border-bottom: 2px solid black;
}
#mL {
grid-area: mL;
border-bottom: 2px solid black;
border-right: 2px solid black;
}
#mM {
grid-area: mM;
border-bottom: 2px solid black;
border-right: 2px solid black;
}
#mR {
grid-area: mR;
border-bottom: 2px solid black;
}
#bL {
grid-area: bL;
border-right: 2px solid black;
}
#bM {
grid-area: bM;
border-right: 2px solid black;
}
#bR {
grid-area: bR;
}
.modal-bg {
position: fixed;
width: 100%;
height: 100vh;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
visibility: hidden;
opacity: 0;
transition: visibility 0s, opacity 0.5s;
}
.bg-active {
visibility: visible;
opacity: 1;
}
.modal {
position: relative;
background-color: white;
border-radius: 5px 5px 5px 5px;
width: 30%;
height: 20%;
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
}
.modal button {
padding: 10px 50px;
background-color: #2980b9;
color: white;
border: none;
cursor: pointer;
}
.modal-close {
position: absolute;
top: 10px;
right: 10px;
font-weight: bold;
cursor: pointer;
}
#modal-headline {
font-size: 20px;
}
#submit {
margin-top: 5px;
}
.scoreboard-left {
display: none;
}
.scoreboard-player {
grid-area: scoreboard-player;
display: flex;
}
.scoreboard-right {
display: none;
}
.scoreboard-oponent {
grid-area: scoreboard-oponent;
display: flex;
}
<!DOCTYPE html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8">
<link href="styles.css" rel="stylesheet" type="text/css" />
<script src="script.js" defer></script>
<title>Tic Tac Toe</title>
</head>
<body>
<div class="window-container">
<div class="header">Tic Tac Toe</div>
<div class="start-screen">
<div class="selection-menu">
<button class="player-selection" id="player-one">Player One</button>
<button class="player-selection" id="player-two">Player Two</button>
<div id="vs">vs</div>
<button class="player-selection" id="computer">Computer</button>
</div>
</div>
<div class="gameboard">
<div class="cell unselectable" id="tL" data-parent="0" name="0"></div>
<div class="cell unselectable" id="tM" data-parent="1" name="1"></div>
<div class="cell unselectable" id="tR" data-parent="2" name="2"></div>
<div class="cell unselectable" id="mL" data-parent="3" name="3"></div>
<div class="cell unselectable" id="mM" data-parent="4" name="4"></div>
<div class="cell unselectable" id="mR" data-parent="5" name="5"></div>
<div class="cell unselectable" id="bL" data-parent="6" name="6"></div>
<div class="cell unselectable" id="bM" data-parent="7" name="7"></div>
<div class="cell unselectable" id="bR" data-parent="8" name="8"></div>
</div>
<div class="modal-bg">
<div class="modal">
<h2 id="modal-headline">Choose a Name:</h2>
<input type="text" id="name">
<button id="submit" class="submit">Submit</button>
<span class="modal-close">X</span>
</div>
</div>
<div class="frame">
<button id="start-game">Start Game</button>
</div>
<div class="scoreboard-left">
<div class="display-player">
<div class="scoreboard-player"></div>
<div class="p-win">Wins: </div><div class="player-win">0</div>
<div class="p-loss">Losses: </div><div class="player-loss">0</div>
<div class="p-tie">Ties: </div><div class="player-tie">0</div>
</div>
</div>
<div class="scoreboard-right">
<div class="display-oponent">
<div class="scoreboard-oponent"></div>
<div class="o-win">Wins: </div><div class="oponent-win">0</div>
<div class="o-loss">Losses: </div><div class="oponent-loss">0</div>
<div class="o-tie">Ties: </div><div class="oponent-tie">0</div>
</div>
</div>
</div>
</body>
</html>
I appreciate any feedback and hints to solve the problem.
I would like to make the default display value '0' before inputting numbers into the calculator.
Also I would like to add the functionality to use the keyboard to input numbers and operations.
Here's a link to the Codepen
I've tried updating the this.currentOperand value to '0' but that hasn't worked.
I can only use vanilla JS
Thank you for taking a look.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calculator</title>
<link rel="stylesheet" href="styles.css">
<script src="script.js" defer></script>
</head>
<body>
<div class="calculator-grid">
<div class="output">
<!-- Using the data attribute for js selection to save confusion with css if I used class -->
<div data-previous-operand class="previous-operand"></div>
<div data-current-operand class="current-operand"></div>
</div>
<button data-all-clear id='clear' class="span-two">AC</button>
<button data-delete id='delete'>DEL</button>
<button data-operation id='divide'>÷</button>
<button data-number id='one'>1</button>
<button data-number id='two'>2</button>
<button data-number id='three'>3</button>
<button data-operation id='multiply'>x</button>
<button data-number id='four'>4</button>
<button data-number id='five'>5</button>
<button data-number id='six'>6</button>
<button data-operation id='add'>+</button>
<button data-number id='seven'>7</button>
<button data-number id='eight'>8</button>
<button data-number id='nine'>9</button>
<button data-operation id='subtract'>-</button>
<button data-number id='decimal'>.</button>
<button data-number id='zero'>0</button>
<button data-equals id='equals' class="span-two">=</button>
</div>
</body>
</html>
Javascript
class Calculator {
constructor( previousOperandTextElement, currentOperandTextElement){
this.previousOperandTextElement = previousOperandTextElement;
this.currentOperandTextElement = currentOperandTextElement;
// Call the clear function to start with a clear display
this.clear();
}
clear(){
this.previousOperand = '';
this.currentOperand = '';
this.operation = '';
}
delete(){
this.currentOperand = this.currentOperand.slice(0, -1)
}
appendNumber(number) {
// If there is a '.' in the number and the currentOperand already contains a '.', end the function by returning. I.E do not append a '.'
if (number === '.' && this.currentOperand.includes('.')) return;
// Coverting the numbers to a string as JS will try to add the numbers together instead of appending ie putting onto the end
this.currentOperand = this.currentOperand.toString() + number.toString();
}
chooseOperation(operation) {
if (this.currentOperand === '') return;
// This will compute the equation berofe appling another operation such as +, etc
if (this.currentOperand !== ''){
this.compute()
}
this.operation = operation;
this.previousOperand = this.currentOperand;
this.currentOperand = ''
}
compute() {
let computation;
// parseFloat() converts the string into a number, until it reaches a value that is not a number
const prev = parseFloat(this.previousOperand);
const current = parseFloat(this.currentOperand);
if (isNaN(prev) || isNaN(current)) return;
// Switch statement for the calculation programming
switch (this.operation) {
case '+':
computation = prev + current;
break;
case '-':
computation = prev - current;
break;
case 'x':
computation = prev * current;
break;
case '÷':
computation = prev / current;
break;
default:
return;
}
this.currentOperand = computation;
this.operation = undefined;
this.previousOperand = '';
}
updateDisplay() {
// Displays text in the previous-operand div that is equal to currentOperand
this.currentOperandTextElement.innerText = this.currentOperand;
if (this.operation != null){
// Displays a concatenation of previous operand and the operation symbol
this.previousOperandTextElement.innerText = `${this.previousOperand} ${this.operation}`;
}
}
}
// Data attribute needs to be inside []
const numberButtons = document.querySelectorAll('[data-number]');
const operationButtons = document.querySelectorAll('[data-operation]');
const deleteButton = document.querySelector('[data-delete]');
const equalsButton = document.querySelector('[data-equals]');
const allClearButton = document.querySelector('[data-all-clear]');
const previousOperandTextElement = document.querySelector('[data-previous-operand]');
const currentOperandTextElement = document.querySelector('[data-current-operand]');
// Defining a new Calculator class. Function declaration?
const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement);
numberButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.appendNumber(button.innerText)
calculator.updateDisplay()
})
})
operationButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.chooseOperation(button.innerText)
calculator.updateDisplay()
})
})
equalsButton.addEventListener('click', button => {
calculator.compute();
calculator.updateDisplay();
})
allClearButton.addEventListener('click', button => {
calculator.clear();
calculator.updateDisplay();
})
deleteButton.addEventListener('click', button => {
calculator.delete();
calculator.updateDisplay();
})
CSS
*, *::before, *::after {
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
font-weight: normal;
}
body {
padding: 0;
margin: 0;
background: linear-gradient(to right, #7262B3, #CF98B6);
}
.calculator-grid {
display: grid;
justify-content: center;
align-content: center;
min-height: 100vh;
grid-template-columns: repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}
.calculator-grid > button {
cursor: pointer;
font-size: 2rem;
border: solid 1px #CF98B6;
/* border-radius: 10px; */
outline: none;
background-color: rgba(255,255,255, .75);
}
.calculator-grid > button:hover {
background-color: rgba(255,255,255, .91);
}
/* This causes any button within the span-two class to span over two squares */
.span-two {
grid-column: span 2;
}
.output {
/* This spans the output from the 1st column (1) to the last column (-1) */
grid-column: 1 / -1;
background-color: rgba(0, 0, 0, .75);
display: flex;
align-items: flex-end;
justify-content: space-around;
flex-direction: column;
padding: 10px;
word-wrap: break-word;
word-break: break-all;
}
.output .previous-operand {
color: rgba(255,255,255, .75);
font-size: 1.5rem;
}
.output .current-operand {
color: white;
font-size: 2.5rem;
}
The way I solved this was by using an if statement to reset to calculator to 0 and then setting the string to empty once the 0 condition had been met.
if (this.currentOperand === '0') {
this.currentOperand = '';
}
function someFunc(){
var integer = document.getElementById('email').value.toString().length;
var symbolCount = 0 + integer;
// var last2 = 100 - integer2;
if (symbolCount >= 100) {
document.querySelector('.hidden_block').style.color = 'green';
}
else if (symbolCount <= 100) {
document.querySelector('.hidden_block').style.color = 'black';
document.querySelector('.error').style.display = "block";
}
else {
document.getElementById('max').style.color = 'black';
}
document.getElementById('symbol_count').innerHTML = symbolCount;
}
email.addEventListener("click", function(){
document.querySelector('.hidden_block').style.display = 'block';
document.getElementById('max').style.display = 'none';
});
#max, #max2 {
text-align: right;
margin-right: 55px;
}
.hidden_block {
display: none;
text-align: right;
margin-right: 55px;
}
.error {
display: none;
color: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<label for="email">Positive</label>
<textarea type="email" class="form-control" id="email" oninput="someFunc()" placeholder="Tell people about your experience: describe the place or activity, recommendations for travelers?"></textarea>
<p id="max">Minimal length - symbols</p>
<div class="hidden_block">
<span id="count">Symbols : <span id="symbol_count">0 </span> (minimum:100)</span>
</div>
<span class="error">Your review must be at least 100 characters long. Adding details really helps travelers.</span>
Hi everyone.I have a that simple textarea field.I need to realize something like that.When u write less than 100 words and click the outside of the email id the border color must be red.And error class must displayed.And i need to if the textarea field is empty the tag p with id max must be display block if the user will write any symbol the id max must bu display none.Thanks for help
function someFunc(){
var integer = document.getElementById('email').value.toString().length;
var symbolCount = 0 + integer;
var integerValue = document.getElementById('email');
var hidden_block = document.querySelector('.hidden_block');
var max = document.getElementById('max');
var error = document.querySelector('.error');
var positive = document.getElementById("positive");
// var last2 = 100 - integer2;
if (integer >= 1) {
hidden_block.style.display = 'inline-block';
max.style.display = 'none';
integerValue.classList.add("form-control");
} else {
hidden_block.style.display = 'none';
max.style.display = 'block';
error.style.display = "none";
positive.style.color = "#002C38";
integerValue.classList.remove("form-redBorder");
}
integerValue.addEventListener("click", function(){
error.style.display = "none";
positive.style.color = "#002C38";
integerValue.classList.remove("form-redBorder");
});
//Red error and border
document.body.addEventListener("click", function(e) {
var target = e.target || e.srcElement;
if (target !== integerValue && !isChildOf(target, integerValue)) {
error.style.display = "inline-block";
integerValue.classList.add("form-redBorder");
positive.style.color = "red";
} if (integer >= 100) {
error.style.display = "none";
integerValue.classList.remove("form-redBorder");
positive.style.color = "#002C38";
}
}, false);
function isChildOf(child, parent) {
if (child.parentNode === parent) {
return true;
} else if (child.parentNode === null) {
return false;
} else {
return isChildOf(child.parentNode, parent);
}
}
//Finished Red error and border
//Start to count symbols
if (symbolCount >= 100) {
hidden_block.style.color = 'green';
}
else if (symbolCount <= 100) {
hidden_block.style.color = 'black';
}
else {
max.style.color = 'black';
// document.getElementById('max2').style.color = 'black';
}
document.getElementById('symbol_count').innerHTML = symbolCount;
}
#email {
display: block;
padding: 6px 12px;
margin: 0 auto;
width: 90% !important;
height: 120px !important;
/*border:1px solid #44A1B7 !important;*/
}
.form-control {
margin: 0 auto;
width: 90% !important;
height: 120px !important;
border:1px solid #44A1B7;
}
#positive, #negative {
padding: 14px 15px 1px 55px;
color: #002C38;
font-size: 18px;
}
.form-redBorder {
margin: 0 auto;
border:1px solid #FF0000 !important;
}
#max, #max2 {
position: absolute;
right: 1%;
margin-right: 55px;
}
.hidden_block {
position: absolute;
right: 1%;
display: none;
text-align: right;
margin-right: 55px;
}
.error {
margin-left: 55px;
display: none;
color: #FF0000;
}
<form role="form">
<div class="form-group">
<p class="help-block">About youre site.</p>
<label for="email" id="positive">Positive</label>
<textarea type="email" id="email" oninput="someFunc()" placeholder="Your review must be at least 100 characters long<br> Adding details really helps travelers"></textarea>
<p id="max">(100 character minimum)</p><div class="hidden_block">
<span id="count">Symbols : <span id="symbol_count">0 </span> (min:100)</span>
</div>
<span class="error">Your review must be at least 100 characters long.<br> Adding details really helps travelers..</span>
</div>
</form>