I’m a beginner at JS attempting to build a calculator for practice/learning. I’ve managed to cover the basic click functionality and now in the process of adding keyboard input. I’m having issues mimicking the behavior of a iOS calculator where once the operator key is pressed, the display area ‘holds’ operand 1 and then begins displaying operand 2 on the next number key press.
My issue lies in that I’ve managed to capture this behavior under my .number_key click handler, but not my keyboard input handler. In the keyboard input, it captures the operator string instead of clearing it, then concatenating e.key. i.e. it will show +44 for the second operand, whereas the click behavior will begin the new string without the operator. Even though the code is the same, and the only difference is the type of event, why is the behavior different? I feel I am overlooking something critical but can’t identify it.
source code:
// declaring variables
let n1;
let n2;
let operator;
let pressed = [];
let keydown = [];
//selectors
const calcDisplay = document.querySelector('#display');
const calcKeys = document.querySelectorAll('.buttons');
//selectors + event listeners
const numberClicked = document.querySelectorAll('.number_key').forEach((item) => {
item.addEventListener('click', (e) => {
if (pressed.slice(-1) == '+' || pressed.slice(-1) == '-' || pressed.slice(-1) == '*' || pressed.slice(-1) == '÷') {
calcDisplay.textContent = '' + e.target.textContent;
pressed.push(e.target.textContent);
} else {
calcDisplay.textContent += e.target.textContent;
pressed.push(e.target.textContent);
}
});
});
const operatorClicked = document.querySelectorAll('.operator').forEach((item) => {
item.addEventListener('click', (e) => {
n1 = calcDisplay.textContent;
operator = e.target.textContent;
pressed.push(e.target.textContent);
console.log(n1, operator);
});
});
const equalsClicked = document.querySelector('#equals').addEventListener('click', (e) => {
n2 = calcDisplay.textContent;
console.log(n2);
calcDisplay.textContent = calculate(n1, n2, operator);
});
// clear display
document.querySelector('#clear').addEventListener('click', () => {
clear();
});
// operation is performed
const calculate = (n1, n2, operator) => {
if (operator === '+') {
return parseInt(n1) + parseInt(n2);
} else if (operator === '-') {
return parseInt(n1) - parseInt(n2);
} else if (operator === '*') {
return parseInt(n1) * parseInt(n2);
} else if (operator === '÷' || operator === '/') {
return parseInt(n1) / parseInt(n2);
}
};
// clear function
const clear = () => {
calcDisplay.textContent = '';
n1 = '';
n2 = '';
operator = '';
pressed = [];
};
// listen for keyboard input
document.addEventListener('keydown', (e) => {
acceptableKeys = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '-', '*', '/'];
if (e.key in acceptableKeys) {
calcDisplay.textContent += e.key;
pressed.push(e.key);
}
//mimic 'operatorClicked behavior'
else if ((e.shiftKey && e.key === '+') || (e.shiftKey && e.key === '*') || e.key === '/' || e.key === '-') {
n1 = calcDisplay.textContent;
operator = e.key;
pressed.push(e.key);
console.log(n1, operator);
if (pressed.slice(-1) == '+' || pressed.slice(-1) == '-' || pressed.slice(-1) == '*' || pressed.slice(-1) == '/') {
calcDisplay.textContent = '' + e.key;
pressed.push(e.key);
}
}
if (e.key === 'Enter') {
n2 = calcDisplay.textContent;
console.log(n2);
calcDisplay.textContent = calculate(n1, n2, operator);
}
if (e.key === 'Backspace') {
calcDisplay.textContent = calcDisplay.textContent.slice(0, -1);
}
})
full code with HTML/CSS: https://jsfiddle.net/icycold/Laq1ers6/201/
I can ‘fix’ the issue by setting calcDisplay.textContent = '' + e.key; to calcDisplay.textContent = ''; however, then the first operand isn’t displayed until the next one is entered and is instead cleared fully. I would want it to behave exactly as when I use clicks.
I’d appreciate any and all help as this entry-level project has taught me a lot via trail/error.