In this tutorial series, we are learning how to add a calculator to a Django web application.
- The first part series saw us design the calculator layout using HTML and CSS.
- In this second series, we will wake up the web app from its long slumber by making it interactive using JavaScript.
Here are all three parts:
We are not building a calculator app because we don’t have one at home or because ours will be a sophisticated one. The purpose of creating this simple application is to improve our programming skills. Its importance becomes ever clearer in JavaScript, a language simple to learn but hard to master.
In this project, we will learn how to manipulate the DOM using JavaScript. Be sure to complete the first part before attempting this project. Create another file name script.js
in your current directory, and let’s get started.
Making some adjustments
Let’s make some minor changes to the markup file. Remove the operator class in the equal sign button. Also, remove the zero value we initially set to the input tag. Just set the value to an empty string. We will add it back using JavaScript.
Alright, we can now start.
Defining constant variables
We need to define some constant variables for calculator buttons and operations.
const keys = document.querySelector('.calculator-keys'), display = document.querySelector(.calculator-screen’), calculator = { displayValue: '0', firstOperand: null, waitingForSecondOperand: false, operator: null, };
The keys variable represents all the calculator keys wrapped inside the div
element with class
name as calculator-keys
. The display
variable is the input element that serves as the calculator screen.
A mathematical expression (20 + 10) consists of three main parts: the first operand (20), the operator (+) and the second operand (10). In the calculator object, we define these and other variables to keep track of everything necessary to create the calculator app.
The displayValue
will store whatever we want to be displayed on the screen. waitingForSecondOperand
is a Boolean that checks whether the first operand and the operator have been entered by the user. If so, it turns to be true.
Notice we didn’t define a second operand. This is because it is not finite. It can go on and on. Whatever is entered on the screen once the Boolean turns to true constitutes the second operand.
Using JavaScript switch case
The calculator consists of four components namely,
- Mathematical operators for performing basic operations;
- Display screen to display mathematical operations;
- Clear Screen button to clear all inputs;
- Decimal button for dealing with decimal numbers.
We will create a function for all these and use a JavaScript switch case to execute them. This is how the switch case will be.
switch (value) { case '+': case '-': case '*': case '/': case '=': handleOperator(value); break; case '.': addDecimal(value); break; case 'all-clear': calculatorReset(); break; default: addDigit(value) }
We will add it shortly and also define their respective callback functions.
The calculator screen
We removed the zero value in the markup file. Let’s add it back by creating a function for it. The updateScreen()
function will also be used to update the screen based on whatever is found in the displayValue
whenever an operation is performed.
Type this below the constant variables.
updateScreen = () => { display.value = calculator.displayValue; }; updateScreen();
Once you refresh the browser, you will see zero displayed.
Listening for clicks
We want to listen for clicks on all calculator keys. Depending on what type of key is clicked, we will then use the switch case to execute them. Notice that we did not define separate variables for the four sets of keys.
Since all the keys are children of the parent element (div
), we only select the parent because we know that the children will inherit the click event. Type this after the updateScreen()
function.
keys.addEventListener('click', event => { const target = event.target; const value = target.value; if (!target.matches('button')) { return; } switch (value) { case '+': case '-': case '*': case '/': case '=': handleOperator(value); break; case '.': addDecimal(value); break; case 'all-clear': calculatorReset(); break; default: addDigit(value) } updateScreen(); });
We define an anonymous function in the event listener that will be executed when a key is clicked. The target
variable represents the element that is clicked, and this will be logged into the console together with its value. If the element is not a button, the function will exit.
We now add the switch case inside the callback function. So, depending on the type of key clicked, the switch case will execute the respective function. Once executed, it will break out of the switch block, and the screen will be updated.
Responding to Clicks
(i) The Digits
Let’s start with the default value. The addDigit()
will execute if there is no case match. The function will make our buttons come to life and display on the screen whatever key is clicked.
addDigit = digit => { const displayValue = calculator.displayValue, calculator.displayValue = displayValue === '0' ? digit : displayValue + digit; } }
Inside the addDigit()
function, we use a ternary operator to check whether the value shown on the screen is zero. If so, we overwrite whatever is stored in the displayValue
with the digit clicked. Otherwise, it is not a zero number. In that case, we concatenate the digit with the value in the displayValue
variable.
Try it out by commenting out the first three functions inside the anonymous function.

We can see the buttons are responding to clicks. As always, hit Ctrl + Shift + I
to view the developer tools for debugging purposes.
B. The Decimal point
At this point, only the digits are working. Let’s ‘activate’ the decimal point by creating the addDecimal()
function.
addDecimal = decimal => { if (!calculator.displayValue.includes(decimal)) { calculator.displayValue += decimal; } }
If the displayValue
does not already have the decimal point, we include it to be displayed on the screen. The if
statement also makes sure that the decimal point is added only once. Uncomment the addDecimal()
function to test it out.

(i) The Operator Keys
The four operator keys and the equal buttons are not working. Let’s wake them up from their long slumber. You can now uncomment the handleOperator()
function.
handleOperator = nextOperator => { const firstOperand = calculator.firstOperand, displayValue = calculator.displayValue, operator = calculator.operator; const inputValue = parseFloat(displayValue); if (firstOperand == null && !isNaN(inputValue)) { calculator.firstOperand = inputValue; calculator.waitingForSecondOperand = true; calculator.operator = nextOperator; }
The function gets the input from the screen and converts it to a decimal number. This is because it is defined as a string. We could have converted it to a number using the Number
function. But we don’t know what our users may input.
Once the function has verified that the converted number has no NaN
value and that the firstOperand
is null as earlier defined, the firstOperand
becomes the inputValue
. This turns the Boolean to true signaling for the second operand and the next operator.
Can you see how the calculator object is dynamically changing?
Note that you can always console log the calculator object inside the last line of each function to observe what’s going on in the console.
(ii) Updating the addDigit() function
At this point, if you enter the second operand after inputting the operator, the value is appended to the first operand. This is not what we want. Let’s do something about it in the function responsible for adding digits.
Update the addDigit()
function with the following code:
addDigit = digit => { const displayValue = calculator.displayValue, waitingForSecondOperand = calculator.waitingForSecondOperand; if (waitingForSecondOperand === true) { calculator.displayValue = digit; calculator.waitingForSecondOperand = false; } else { calculator.displayValue = displayValue === '0' ? digit : displayValue + digit; }
We define what should happen once the handleOperator()
function turns the Boolean to true. The digit entered becomes the new value for displayValue
. Now instead of appending, the displayValue
is overwritten with whatever digit is entered.
C. (ii) Updating the handleOperator() function
We are not yet done with the handleOperator()
function. Looking at the switch case block, our aim is for the function to perform mathematical calculations on whatever operator is entered.
Back to the handleOperator()
function. The function keeps signaling for the next operator, but what does it do with the ones it received previously? It’s expected to perform some operations. We haven’t defined that. Therefore, update the function with the following:
handleOperator = nextOperator => { const firstOperand = calculator.firstOperand, displayValue = calculator.displayValue, operator = calculator.operator; const inputValue = parseFloat(displayValue); if (firstOperand == null && !isNaN(inputValue)) { calculator.firstOperand = inputValue; } else if (operator) { //add from here… const result = calculate(firstOperand, inputValue, operator); calculator.displayValue = String(result); calculator.firstOperand = result; //…to here } calculator.waitingForSecondOperand = true; calculator.operator = nextOperator; }
We define that using the else if
statement. If an operator is inputted by the user, the calculate()
function is called. Take note of what is passed as parameters to the function because we will use them to code the calculate()
function.
The result is then converted back to a string and displayed to the user through the displayValue
property. Do you remember we defined that in the updateScreen()
function?
The calculate() function
The calculate()
function is self-explanatory. Taking the first and second operands as well as the defined operator, it performs the calculation.
calculate = (firstOperand, secondOperand, operator) => { if (operator === '+'){ return firstOperand + secondOperand; } else if (operator === '-') { return firstOperand - secondOperand; } else if (operator === '*'){ return firstOperand * secondOperand; } else if (operator === '/'){ return firstOperand / secondOperand; } return secondOperand; }
The calculator app is now performing operations using the four operators. I entered 15 * 5 and you can see the result in the above screenshot. Also, the console shows the processes and how it was dynamically changing the calculator object.
As soon as we hit the =
key, the result displayed becomes the first operand for the next operation and the handleOperator()
functions keep waiting for the next operator.
(iii) Updating the handleOperator() function for the last time
What if the first operator entered is not what we have in mind and we decided to enter another operator, how will the calculator app handle it? It will lead to unexpected results. Let’s modify the handleOperator()
to give us the desired result.
handleOperator = nextOperator => { const firstOperand = calculator.firstOperand, displayValue = calculator.displayValue, operator = calculator.operator; const inputValue = parseFloat(displayValue); if (operator && calculator.waitingForSecondOperand) { //add from these … calculator.operator = nextOperator; console.log(calculator) return; } // to these … if (firstOperand == null && !isNaN(inputValue)) { calculator.firstOperand = inputValue; } else if (operator) { const result = calculate(firstOperand, inputValue, operator); calculator.displayValue = String(result); calculator.firstOperand = result; } calculator.waitingForSecondOperand = true; calculator.operator = nextOperator; console.log(calculator); }
Since the Boolean is set to true while waiting for the second operand, we use an if statement to ensure that the next operator must be received before performing a calculation

Test it out. The app should be working as expected. From the screenshot, I have clicked several operators but it didn’t perform any operation. It kept waiting for the second operand. We are good to call it a day as everything is now working as expected. Are we?
Resetting the calculator
All but one of the buttons are active. The AC button is still in its long slumber. We can’t just let it sleep forever. To awaken it, we will now uncomment the calculatorReset()
function and set all the properties of the calculator object to its default state.
calculatorReset = () => { calculator.displayValue = '0'; calculator.firstOperand = null; calculator.waitingForSecondOperand = false; calculator.operator = null; }
It is similar to the calculator object. Test it out once again to ensure the button is now working.
B. (ii) Updating the addDecimal() function
There is still a bug in our calculator app. See what happens when you entered a decimal point after inputting the operator sign. It gets appended to the first operand. It’s supposed to be part of the second operand. Let’s get it fixed!
addDecimal = decimal => { if (calculator.waitingForSecondOperand === true) { calculator.displayValue = '0.' calculator.waitingForSecondOperand = false; return; } if (!calculator.displayValue.includes(decimal)) { calculator.displayValue += decimal; } }
If a decimal point is entered and the Boolean is true, the function changes the display value to 0. and turns the Boolean to false. Remember, once the Boolean turns to true, it signals for the next operand.
So, in the event a decimal point is clicked, we set the Boolean be turned to false to allow for the current operand to be completely entered before proceeding. And we won’t worry about turning the Boolean to true because it will be done once we hit the operator keys, signaling that inputting the current operand is finalized and that the app can now proceed to the next operand.
Reducing decimal points
We don’t want to have this kind of display (see screenshot below) in our app when we perform decimal operations.

If it’s okay with you, you can ignore it and skip this step. Otherwise, use to.fixed()
method to restrict the number of decimal digits to any number of your choice. This will be done in the handleOperator()
function.
Replace the following snippet:
calculator.displayValue = String(result);
with the following:
calculator.displayValue = '${parseFloat(result.toFixed(7))}';
Test it out and you will see the floating-point number is reduced.
Conclusion
We have come a long way in creating a calculator app. In this tutorial, we use JavaScript to make the app interactive and respond to clicks. The full code is on my GitHub page. In the final series, we will see how to run the app on Django local server.
💡 Recommended: How I Created a Calculator App using Django