I will explain each step at a higher level than in my previous tutorials, so if you have trouble following, try doing the Random Quote Machine and Wikipedia Search App tutorials in that order, then come back to this one at a later date.
Here’s a live demo of the complete project.
Before you begin
You can find the starting point for this tutorial on JSFiddle. It contains all the necessary markup to build the calculator layout.
The markup is almost identical to the final state of the previous tutorial but I made a few minor changes so go with this one instead.
Start by forking the code to a new fiddle, and follow along by typing each step out all the way to the end. Feel free to do this tutorial on another online playground or on your local machine if you prefer.
Anyone should be able to perform the four most common arithmetic operations (addition, subtraction, multiplication and division) on our calculator by constructing a valid expression using the input buttons, and have the result displayed on the screen.
An example is:
12 + 10.
To construct a valid arithmetic expression, we need to keep track of a few things: the first operand (
12), the operator (
+) and the second operand (
Let’s start by creating an object to help us keep track of these values.
calculator object holds all the data that we need to construct a valid expression.
displayValueholds a string value that represents the input of the user or the result of an operation. This is what will be shown on the screen.
firstOperandwill hold the first operand for any expression. This is set to
operatorkey will hold the operator for an expression. Also set to
waitingForSecondOperandis essentially a flag that checks whether an expression can be evaluated or whether the second operand needs to be inputed.
Updating the display
Right now, the calculator screen shows nothing. We need to display the value of
displayValue on the screen (‘0’ by default). We will create a function for this purpose so that anytime an operation is performed in the app, we can always invoke it to update the screen with the contents of
Go ahead and type this below the
Our “screen” is really just a disable text input.
updateDisplay function does.
Now you should see ‘0’ displayed on the screen of the calculator.
Handling key presses
We have four sets of keys: digits (0-9), operators (+, -, *, /, =), a decimal point (.) and a reset key (AC). Let us listen for clicks on the calculator and determine what type of key was clicked.
Here, we listen for a
click event on
.calculator-keys. Since all the keys on the calculator are children of this element, the
click event filters down to them too. This is known as event delegation.
Inside the callback function of the event listener, we extract the
target property of the click event using object destructuring which makes it really easy to unpack object properties into distinct variables.
target variable is an object that represents the element that was clicked. If this element is not a button (such as if you click the spaces between the buttons), we will exit the function early.
That’s what the first
if statement does:
Otherwise, we log the type of button that was clicked as well as its value.
Try it out. Open up your browser console and click any of the buttons. The appropirate key type and value should be logged to the console.
Inputting the digits
Next, let us make the digit buttons work so that when they are clicked, feedback is displayed to the user on the screen.
displayValue property of the
calculator object represents the input of the user, we need to modify the value of this property when any of the digits is clicked.
Create a new function called
inputDigit below the
console.log('digit', target.value); with the following:
inputDigit function, we use the ternary operator (
?) to check if the current value displayed on the calculator is ‘0’ (the default).
If so, we overwrite
calculator.displayValue with whatever digit was clicked. Otherwise, if the number is a non-zero number, we append to it. Finally we call
updateDisplay() to update the information on the screen after each button is clicked.
Try it out by clicking any of the digit buttons. The display should be updated with whatever digit you clicked.
Inputting a decimal point
When the decimal point key is clicked, we need to append a decimal point to whatever is displayed on the screen except if it already contains a decimal point.
Here’s how we can achieve that. Create a new function called
console.log('decimal', target.value); with the following code:
inputDecimal function, we use the
includes method to check if
displayValue does not already contain a decimal point. Then we append the dot to the number. Otherwise, we do nothing.
Try it out:
The next step is to get the operators (+, -, x, /, =) on the calculator working. There are three scenarios to account for:
1. When the user finishes entering the first operand and hits an operator
This indicates that he/she is ready to enter the second operand. What we need to do here is store the first operand and update the display with the new string of numbers.
Create a new function called
console.log('operator', target.value) with the following code:
When an operator key is pressed, we convert the current number displayed on the screen to a number (
parseFloat(displayValue)) and then store the result in
calculator.firstOperand if it does not exist already.
We also set
true which indicates that the first operand has been entered and the second one is ready to begin, and
calculator.operator to whatever operator key was clicked.
At this point, it is useful to see how the properties of the
calculator object is being updated on each button press. Add the following code to the end of both
Now, try to construct a valid arithmetic operation by clicking the following keys in turn:
12 + 10. Notice that when the
+ key is pressed, the values of
operator is updated to
+ respectively while
waitingForSecondOperand is set to true indicating that the calculator is waiting for the second operand (10) to be inputted.
However, there’s a bug here. The second operand does not overwrite the first operand which is currently displayed on the screen. Instead, it is appended to it.
Let’s fix that by updating the
inputDigit function to look like this:
Here, we check if
true and set
displayValue to the key that was clicked. Otherwise, we perform the same check as before, overwriting or appending to
calculator.displayValue as appropriate.
Now, try out the expression as before. It should update the
2. When the user finishes the second operand and hits an operator
The second scenario we want to handle is if the user has finished entering the second operand and an operator key is clicked. At this point, all the ingredients to perform a valid calculation is present so we need to display the result of the calculation to the user.
12 + 10, let’s say the user hits the
= button. What should happen?
22 should be presented on the screen as the result of the calculation and the
firstOperand should be updated to the result so that it can be used in the next calculation.
handleOperator to look like this:
Then create a new object called
handleOperator with the following properties:
else if block added to
handleFunction checks if an
operator already exists. If so, property lookup is performed for the operator in the
performCalculation object and the function that matches the operator is executed.
This function returns the result which is then stored in the
result variable. We then display the result to the user by updating the
displayValue with this result and also set the
firstOperand to the result.
Try it out. Enter
12 + 10 = and notice that the correct result is displayed on the screen.
It also works when you chain a string of operations. So
5 * 20 - 14 = should give
86 as the result.
This is because hitting the
- key triggers the calculation of the first operation (
5 * 20) whose result (
100) then set as the
firstOperand for the next calculation so by the time we enter
14 as the second operand and hit the
= key, the function that is defined in the
- property of
performOperation is executed giving
86 as the result which is also set as the
firstOperand for the next operation.
Try out other expressions and confirm that the calculator works as expected.
3. When a user enters two or more operators consecutively
It’s quite common to change one’s mind about the type of operation one wants to perform so the calculator must handle this properly.
Let’s say you want to add 7 and 2 together, you will click
7 + 2 = which will produce the correct result. But let’s assume after hitting
7 +, you change your mind and decide to subtract 2 from 7. Instead of clearing the calculator and starting all over, you should be able to hit
- to override the
+ that was previously entered.
Remember that at this point (
waitingForSecondOperand will be set to
true since the calculator expects a second operand to be entered after the operator key. We can use this quality to update the operator key and prevent any calculations until the second operand has been inputted.
handleOperator function to look like this:
This is the relevant change:
if statement checks if an
operator already exists and if
waitingForSecondOperand has a truthy value. We then update
operator and exit from the function by using an early
return statement so that the rest of the function is not executed and no calculations are performed.
Try it out. Click multiple operators after entering some digits and monitor the calculator object in the console. Notice that the
operator property is updated each time and no calculations are performed until you provide the second operand.
Resetting the calculator
The final task is to make sure the user can reset the calculator to its initial state by pressing a key. In most calculators, The
AC button is used to reset the calculator to its default state so that’s what we’re going to use here.
Go ahead and create a new function below
performCalculation as shown below:
console.log('all clear', target.value) with the following:
resetCalculator function sets all the properties of the
calculator object to their original values. Now click the
AC key on your calculator. It should work as expected. You can check the
calculator object in the console to confirm.
One more thing…
There’s a bug that allows you to add a decimal point to the
displayValue after clicking on an operator.
Although this bug does not affect the result of the expression, it’s not ideal for a calculator to behave like that. We can write a fix by making a modification to
Here’s the relevant change:
We prevent the decimal point from being appended to the
waitingForSecondOperand is true by using an early return statement just like we’ve done a few times now.
Note that you can execute one statement in an
if block without enclosing it within curly braces.
Here’s the final state of the calculator:
That concludes my tutorial. This calculator can be enhanced in a lot of ways though. Here are a few ideas that you can implement to improve upon what we’ve covered here:
- Add the
- Add the square root and square functions.
- Make it possible to clear an entry without resetting the calculator.
- Make it possibe to type in negative numbers (e.g -3).
Take a stab at implementing those features in your application.
Thanks for reading.