Take a look. Without 'eval'. Maybe, not optimal in some ways, but at least it is working as expected. It means that 12 + 7 - 5 * 3
will be 42
.
I've added comments to the code, but you can ask if something is not clear.
Note: I also added two new labels - one to show the operator and another one to show the expression. Why? Because it is more beautiful for me. If you do not need them - just say. We can remove them.
const numbers = document.querySelectorAll('[data-calc]'),
operators = document.querySelectorAll('[data-operator]:not([data-operator=AC])'),
prev = document.getElementById('prev-result'),
current = document.getElementById('current-number'),
resultBtn = document.querySelector('[data-result]'),
acButton = document.querySelector('[data-operator=AC]'),
operatorLabel = document.getElementById('operator'),
expression = document.getElementById('expression');
let firstNumber; // this is previous result
let secondNumber; // this is what we enter with keyboard
const setOperator = (x) => operatorLabel.innerHTML = x !== undefined ? x : '';
const getOperator = () => operatorLabel.innerHTML;
numbers.forEach(button => {
button.addEventListener('click', () => {
if (firstNumber !== undefined && getOperator() == '') {
// ignore previous result if we did not link it with operator
firstNumber = undefined;
}
if (isNaN(parseInt(current.innerHTML))) current.innerHTML = '';
current.innerHTML += button.innerText;
secondNumber = parseInt(current.innerHTML);
});
});
operators.forEach(button => {
button.addEventListener('click', () => {
if (secondNumber !== undefined) {
if (firstNumber !== undefined) {
// continue of expression
const result = processResult();
setOperator(button.innerText);
firstNumber = result.result;
} else {
// we have no previous result
firstNumber = secondNumber;
secondNumber = undefined;
current.innerHTML = '';
prev.innerHTML = firstNumber;
setOperator(button.innerText);
}
} else if (firstNumber !== undefined) {
// we have previous result, but empty next number
setOperator(button.innerText);
}
});
});
acButton.addEventListener('click', () => {
current.innerHTML = '';
secondNumber = undefined;
setOperator();
});
const getResult = () => {
const operator = getOperator();
if (firstNumber !== undefined && secondNumber !== undefined && operator != '') {
const str = String(firstNumber) + operator + secondNumber;
let result = {
result: NaN,
str
};
if (operator == '+') result.result = firstNumber + secondNumber;
if (operator == '-') result.result = firstNumber - secondNumber;
if (operator == '/') result.result = firstNumber / secondNumber;
if (operator == '*') result.result = firstNumber * secondNumber;
return result;
}
}
const processResult = () => {
const result = getResult();
if (result !== undefined) {
if (isNaN(result.result)) {
current.innerHTML = 'Error';
setOperator();
prev.innerHTML = '';
} else {
prev.innerHTML = result.result;
firstNumber = result.result;
current.innerHTML = '';
secondNumber = undefined;
setOperator();
}
expression.innerHTML = result.str + ' = ' + (isNaN(result.result) ? 'Undefined' : result.result);
}
return result;
}
resultBtn.addEventListener('click', () => {
processResult();
});
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.calculator .calculator-grid {
width: 300px;
height: 550px;
margin-top: 50px;
background-color: white;
border: 1px solid lightgrey;
border-radius: 30px;
padding: 10px;
}
.calculator {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.calculator .calculator__buttons {
display: grid;
width: 30px;
grid-template-columns: repeat(4, 1fr);
}
.calculator .calculator__buttons button {
margin: 5px;
width: 60px;
height: 60px;
border-radius: 50%;
border: none;
background-color: gainsboro;
color: black;
font-size: 30px;
}
.calculator .calculator__buttons button:active {
background-color: darkgray;
}
.calculator .calculator__input .calc-input {
margin: 0 0 15px 0;
padding: 10px;
width: 280px;
height: 100px;
border: none;
background-color: white;
font-size: 40px;
color: black;
text-align: right;
}
.calculator .calculator__input .calc-input:active {
border: none;
}
.calculator .calculator__input .calc-input .prev-result {
height: 40px;
font-size: 30px;
overflow: hidden;
white-space: nowrap;
}
.calculator .calculator__input .calc-input .current-number {
height: 60px;
}
.calculator .calculator__buttons .operator-btn {
font-size: 30px;
color: white;
background-color: darkturquoise;
}
.calculator .calculator__buttons .operator-btn:active {
background-color: aqua;
}
div.prev-container {
position: relative;
}
div.operator {
position: absolute;
top: 25px;
right: -10px;
font-size: 30px;
}
#expression {
position: absolute;
left: 4px;
right: 4px;
text-align: left;
top: -16px;
font-size: 14px;
overflow: hidden;
white-space: nowrap;
}
<section class="calculator">
<div class="calculator-grid">
<div class="calculator__input">
<div class="calc-input">
<div class="prev-container">
<div id="expression"></div>
<div class="prev-result" id="prev-result"></div>
<div class="operator" id="operator"></div>
</div>
<div class="current-number" id="current-number"></div>
</div>
</div>
<div class="calculator__buttons">
<button data-calc="7">7</button>
<button data-calc="8">8</button>
<button data-calc="9">9</button>
<button data-operator="-" class="operator-btn-minus operator-btn">-</button>
<button data-calc="4">4</button>
<button data-calc="5">5</button>
<button data-calc="6">6</button>
<button data-operator="+" class="operator-btn-plus operator-btn">+</button>
<button data-calc="3">3</button>
<button data-calc="2">2</button>
<button data-calc="1">1</button>
<button data-operator="*" class="operator-btn operator-btn-multiply">*</button>
<button data-calc="0">0</button>
<button data-operator="AC" class="operator-btn operator-btn-reset">AC</button>
<button data-result="=" class="operator-btn operator-btn-result">=</button>
<button data-operator="/" class="operator-btn operator-btn-divide">/</button>
</div>
</div>
</section>