Let’s Make A JavaScript Calculator
I know what you’re thinking: how come Ethan Ryan hasn’t blogged about making a JavaScript calculator yet?
Well here you go, you unbelievably specific hypothetical internet reader.
Getting Started
First, let’s start with our HTML and CSS. Thanks to CSS grid, we can get a nice calculator shape on the page quickly. Calculator shape? Ooh la la! As the French nerds would say.
I’m gonna model my calculator on the calculator on my iPhone:
I’m gonna call that top row one row, so six rows total. Four columns across.
Round One
Here’s my HTML:
<div class="container">
<div class="item item-header">header header header header</div>
<div class="item item-main-1">main main main main</div>
<div class="item item-main-2">main main main main</div>
<div class="item item-main-3">main main main main</div>
<div class="item item-main-4">main main main main</div>
<div class="item item-footer">footer footer footer footer</div>
</div>
And here’s my CSS:
.container {
display: grid;
justify-content: center;
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas:
"header header header header"
"main main main main"
"main main main main"
"main main main main"
"main main main main"
"footer footer footer footer";
}.item-header {
grid-area: header;
}.item-footer {
grid-area: footer;
}
And here’s the result:
And there you have it folks! A calculator! It’s that easy.
Thanks for reading.
Alright, that’s a solid first step.
Let’s style it up a little more before adding some functionality.
Round Two
I wanna make all those items buttons, so let’s do that.
Note: why not use a table in the HTML, instead of CSS Grid? I don’t know, that’s a great question. I just spent a few minutes googling that, and then said fuck, I’m using CSS Grid, cuz CSS Grid is cool, and I’m a cool ass guy.
Here’s my next iteration:
HTML:
<div class="container">
<button class="btn">header</button>
<button class="btn">header</button>
<button class="btn">header</button>
<button class="btn">header</button>
<button class="btn">AC</button>
<button class="btn">=/-</button>
<button class="btn">%</button>
<button class="btn">÷</button>
<button class="btn">7</button>
<button class="btn">8</button>
<button class="btn">9</button>
<button class="btn">X</button>
<button class="btn">4</button>
<button class="btn">5</button>
<button class="btn">6</button>
<button class="btn">-</button>
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<button class="btn">+</button>
<button class="btn">0</button>
<button class="btn">0</button>
<button class="btn">.</button>
<button class="btn">=</button>
<div class="item item-footer">footer footer footer footer</div>
</div>
CSS:
.container {
display: grid;
justify-content: center;
grid-template-columns: 80px 80px 80px 80px;
grid-template-rows: 80px 80px;
grid-template-areas:
"header header header header"
"main main main main"
"main main main main"
"main main main main"
"main main main main"
"main main main main"
"footer footer footer footer";
}.item-header {
grid-area: header;
}.item-footer {
grid-area: footer;
}.btn {
background-color: green;
border: none;
color: white;
padding: 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
margin: 4px 2px;
border-radius: 50%;
}
And here’s the result:
Alright, that’s looking a little better. I don’t know what the hell “footer footer footer footer” is doing down there, I could probably get rid of that. And I want to make those two zeros one big zero. And I want to make that header one big header. And I want to recolor the buttons. But otherwise, pretty, pretty good!
Step Three
Here’s my next draft:
HTML:
<div class="container"> <div class="item item-header">0</div>
<button class="btn silver">AC</button>
<button class="btn silver">+/-</button>
<button class="btn silver">%</button>
<button class="btn orange">÷</button>
<button class="btn">7</button>
<button class="btn">8</button>
<button class="btn">9</button>
<button class="btn orange">X</button>
<button class="btn">4</button>
<button class="btn">5</button>
<button class="btn">6</button>
<button class="btn orange">-</button>
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<button class="btn orange">+</button>
<button class="btn">0</button>
<button class="btn">0</button>
<button class="btn">.</button>
<button class="btn orange">=</button>
</div>
CSS:
body {
font-size: 64px;
background-color: black;
}.container {
display: grid;
justify-content: center;
grid-template-columns: 80px 80px 80px 80px;
grid-template-rows: 80px 80px;
grid-template-areas:
"header header header header"
"main main main main"
"main main main main"
"main main main main"
"main main main main"
"main main main main";
}.item-header {
grid-area: header;
grid-row-start: 1;
grid-row-end: 1;
background-color: black;
color: white;
text-align: right;
}.btn {
background-color: dimgray;
border: none;
color: white;
padding: 20px;
text-align: center;
margin: 4px 2px;
border-radius: 50%;
}.silver {
background-color: silver;
color: black;
}.orange {
background-color: orange;
}button {
font-size: 26px;
}
Result:
That’s pretty god damn good, if I do say so myself.
Alright, that’s enough styling for today. Let’s give these buttons something to do instead of just sitting there looking pretty.
JavaScript, Step 1 — Clicks
I like to start small. Break the problem down into steps, and then even smaller steps, and then take one itty bitty step, and then take a long nap.
We need these buttons to respond to clicks. Right now, clicking them does nothing. Let’s change that.
$(".btn").click(function(event) {
console.log("you clicked: ", this.innerHTML)
})
Yes, yes, React app’s are the hottest ish ever, but I’m using old school jQuery instead of vanilla JavaScript with some JSX, cuz this is a super simple app, so sue me.
Now, whenever I click a button, I get a log in the console, like:
you clicked: 7
you clicked: 8
you clicked: 9
And there you have it folks! A calculator! It’s that easy.
Thanks for reading.
Alright, that’s a solid first step. Time for a cookie, a 12 hour nap, a two week bender, a week in rehab, a couple days of rehab detox, followed by a relapse, a big ole binge, wake up under a bridge, eat a box of Saltines, by which I mean, eat the actual cardboard, and then take a long, rambling walk to nowhere.
Alright, now that we’ve got that out of the way, let’s move on to the next step!
Let’s output out clicks to the DOM, instead of the console. Why not. As good a next step as any.
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("you clicked: ", thingClicked)
$(".item-header").html(thingClicked)
})
Cool. Now as you click buttons, the content of whatever button you clicked appears in the top row of our calculator. We’ve got a working app, in the sense that it now does something. You can click buttons, and see the state change. Cool! Cool cool cool. Cool cool cool cool cool cool cool. Cool.
Now let’s have our app do a little more than just show us what buttons got clicked. Not that there’s anything wrong with that.
JavaScript, Step 2 — Math (Addition)
Let’s start with addition, since I’m a big Violent Femmes fan, and I like to Add It Up.
Now let’s add it up!
I’m gonna give that top row item-header div an id, #currentValue. That’s an important component of our app, since it’ll be showing the output of the calculations our users perform. I could call it #state or #answer or #result but I like #currentValue, so I’m going with that.
So that first function now says:
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("you clicked: ", thingClicked)
$("#currentValue").html(thingClicked)
})
Our addition function will take in two numbers as arguments, and the first number will always be the currentValue of the app. The addition function will then add that amount with whatever number is entered after the user clicks the “+” button.
Update: I made some updates.
Still haven’t gotten to adding yet.
I had to work out some things with the currentValue. I want to be able to append numbers, so I could type the number 100, or 52, and not just replace each number with the new button pressed. I did a lot of console.log()ing.
I had to figure out when things were strings and when they were numbers using typeof.
Then I had to decide when I wanted to make numbers strings, and vice versa.
I’ll need to refactor this, it’s very messy, but here’s where I’m at now:
function getCurrentValue() {
var currentValue = document.getElementById("currentValue").innerHTML
//console.log('0. typeof currentValue is: ', typeof currentValue)
currentValue = parseInt(currentValue, 10) //remove leading 0, make number
//console.log('0. typeof currentValue is now: ', typeof currentValue)
//console.log('0. currentValue is: ', currentValue)
return currentValue //returning currentValue will be a number
}
//getCurrentValue()function clearCurrentValue(event) {
$("#clear").click(function(event) {
console.log('calling clearCurrentValue... currentValue === 0')
$("#currentValue").html(0)
getCurrentValue()
})
}
clearCurrentValue(event)function clickButton(event) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("1. you clicked: ", thingClicked)
console.log('1. typeof thingClicked is: ', typeof thingClicked)if ($(this).hasClass("num")) {
console.log(`2. ${thingClicked} is a num class!`)
var currentValue = getCurrentValue()
//console.log('2. typeof currentValue is: ', typeof currentValue)
currentValue = currentValue.toString() //make number a string
var newString = currentValue + thingClicked //add into newString
var newNumber = parseInt(newString, 10) //remove leading 0, make number
console.log('2. replace currentValue with newNumber: ', newNumber)
//console.log('2. typeOf newNumber is: ', typeof newNumber)
$("#currentValue").html(newNumber)
}
})
return thingClicked
}
clickButton(event)
Oh boy. That’s a lot of code to simply output some numbers on click.
OK, now let’s get back to trying to add some numbers together.
Alright, I’ve got my basic addition working, but it’s sloppy.
var globalAnswer //declaring global variable here... this is bad practicefunction storeAnswer(value) {
var value = value
console.log('xxxx. storeAnswer is:::', value)
globalAnswer = value //bad practice
return value
}function getCurrentValue() {
var currentValue = document.getElementById("currentValue").innerHTML
//console.log('0. typeof currentValue is: ', typeof currentValue)
currentValue = parseInt(currentValue, 10) //remove leading 0, make number
//console.log('0. typeof currentValue is now: ', typeof currentValue)
//console.log('0. currentValue is: ', currentValue)
return currentValue //returning currentValue will be a number
}
//getCurrentValue()function clearCurrentValue(event) {
$("#clear").click(function(event) {
console.log('calling clearCurrentValue... currentValue === 0')
$("#currentValue").html(0)
getCurrentValue()
})
}
clearCurrentValue(event)function equals(event) {
$("#equals").click(function(event) {
console.log('=== equals btn pressed!!!')
var answer = globalAnswer //bad practice!!! fix this.
$("#currentValue").html(answer) //set currentValue to answer
console.log('answer is:::', answer)
return answer
})
}
equals(event)function addition(event, num1) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
if ($(this).hasClass("num")) {
var nextNum = parseInt(thingClicked)
console.log('nextNum is: ', nextNum)
$("#currentValue").html(nextNum) //set currentValue to nextNum
var result = num1 + nextNum
console.log('result of addition is: ', result)
storeAnswer(result) //pass result to storeAnswer
return result
} else {
console.log('forget it, a non-num was pressed!')
return thingClicked
}
})
}function clickButton(event) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("1. you clicked: ", thingClicked)
console.log('1. typeof thingClicked is: ', typeof thingClicked)if ($(this).hasClass("add")) {
var num1 = getCurrentValue()
console.log('add button clicked!!!!')
console.log('num1 is: ', num1)
console.log('calling addition, awaiting nextNum....')
addition(event, num1)
}if ($(this).hasClass("num")) {
console.log(`2. ${thingClicked} is a num class!`)
var currentValue = getCurrentValue()
//console.log('2. typeof currentValue is: ', typeof currentValue)
currentValue = currentValue.toString() //make number a string
var newString = currentValue + thingClicked //add into newString
var newNumber = parseInt(newString, 10) //remove leading 0, make number
console.log('2. replace currentValue with newNumber: ', newNumber)
//console.log('2. typeOf newNumber is: ', typeof newNumber)
$("#currentValue").html(newNumber)
}
})
return thingClicked
}
clickButton(event)
You could see all my commented out //console.log()s. I can’t imagine getting anything done in JavaScript without console.logging the hell out of it!
The above code is messy, and can and will be refactored. But it’s working. I’ve got the basic functionality down of a calculator capable of doing addition. Now repeating that function and replacing the addition with subtraction or multiplication or division shouldn’t be too hard.
Right now I’m using a global variable, var globalAnswer, which I was trying to avoid. But I couldn’t figure out how to pass the value of that function without storing it in a global variable. Oh well. At least my math is working for now. Red, green, refactor, baby!
JavaScript, Step 3— Math (Subtraction)
Since my addition function is working, adding a subtraction function is easy.
Copy and paste, baby!
var globalAnswer //declaring global variable here... this is bad practicefunction storeAnswer(value) {
console.log('xxx. storeAnswer is:::', value)
globalAnswer = value //bad practice
return value
}function getCurrentValue() {
var currentValue = document.getElementById("currentValue").innerHTML
currentValue = parseInt(currentValue, 10) //remove leading 0, make number
//console.log('0. typeof currentValue is now: ', typeof currentValue)
//console.log('0. currentValue is: ', currentValue)
return currentValue //returning currentValue will be a number
}
//getCurrentValue()function clearCurrentValue(event) {
$("#clear").click(function(event) {
console.log('calling clearCurrentValue... currentValue === 0')
$("#currentValue").html(0)
getCurrentValue()
})
}
clearCurrentValue(event)function equals(event) {
$("#equals").click(function(event) {
console.log('=== equals btn pressed!!!')
var answer = globalAnswer //bad practice!!! fix this.
$("#currentValue").html(answer) //set currentValue to answer
console.log('answer is:::', answer)
return answer
})
}
equals(event)function addition(event, num1) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTMLif ($(this).hasClass("num")) {
var nextNum = parseInt(thingClicked)
console.log('nextNum is: ', nextNum)
$("#currentValue").html(nextNum) //set currentValue to nextNum
var result = num1 + nextNum
console.log('result of addition is: ', result)
storeAnswer(result) //pass result to storeAnswer
return result
} else {
console.log('forget it, a non-num was pressed!')
//return thingClicked
}
return thingClicked
})
}function subtraction(event, num1) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTMLif ($(this).hasClass("num")) {
var nextNum = parseInt(thingClicked)
console.log('nextNum is: ', nextNum)
$("#currentValue").html(nextNum) //set currentValue to nextNum
var result = num1 - nextNum
console.log('result of subtraction is: ', result)
storeAnswer(result) //pass result to storeAnswer
return result
} else {
console.log('forget it, a non-num was pressed!')
//return thingClicked
}
return thingClicked
})
}function clickButton(event) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("1. you clicked: ", thingClicked)
console.log('1. typeof thingClicked is: ', typeof thingClicked)if ($(this).hasClass("add")) {
var num1 = getCurrentValue()
console.log('add button clicked!!!!')
console.log('num1 is: ', num1)
console.log('calling addition, awaiting nextNum....')
addition(event, num1)
}if ($(this).hasClass("subtract")) {
var num1 = getCurrentValue()
console.log('subtract button clicked!!!!')
console.log('num1 is: ', num1)
console.log('calling subtraction, awaiting nextNum....')
subtraction(event, num1)
}if ($(this).hasClass("num")) {
console.log(`2. ${thingClicked} is a num class!`)
var currentValue = getCurrentValue()
//console.log('2. typeof currentValue is: ', typeof currentValue)
currentValue = currentValue.toString() //make number a string
var newString = currentValue + thingClicked //add into newString
var newNumber = parseInt(newString, 10) //remove leading 0, make number
console.log('2. replace currentValue with newNumber: ', newNumber)
$("#currentValue").html(newNumber)
}
})
return thingClicked
}
clickButton(event)
Note: the above is about 120 lines of JavaScript.
The subtraction function works. It even accounts for negative numbers, which is awesome! I thought that was something I’d have to implement, but JavaScript is smart, or my computer is smart, or something is smart, I’m not sure what cuz I’m a dumb dumb.
There’s an obvious issue with my code above, which doesn’t pass the smell test, as they say. I’ve never loved that “smell test” expression but if you want code with the big boys you gotta talk their talk. Anyway, the obvious issue with my copy and paste is that I’ve got a lot of repeated code. My code is not very DRY. It’s not very DRY at all. In fact, it’s WET. That’s why it’s not passing the smell test, cuz it’s like a dead fish, soaking wet in its own putrid repeating rot, a rot of rotting repeating repetition that keeps repeating repeating itself.
DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY DRY.
That’s my motto. Don’t repeat yourself. Yup. My motto! Don’t repeat yourself.
So let’s refactor that, get it looking niiiiiiiice, and then add in our multiplication and division functions.
OK, after some refactoring and abstractoring, here’s what I got:
…… refactored code here….
OK, if this blog post were a novel, this chapter would say: “The next day…”
I’ve done a good bit of refactoring. My code got pretty ugly before it got beautiful. Truth be told, it’s still pretty ugly. I had to rethink some things. The code above had a lot of issues. The code below does too, but it’s progress!
Since I was doing a lot of work in the console, I decided to add a placeholder for my globalAnswer variable, to more easily see what I was working with.
The flow of my functions had a lot of issues. It’s better now.
Perhaps most importantly:
Order of Operations
AKA 2+3x4=14 (not 20)
I want to be able to chain commands, like 2+4*52/6+16+3*5.
To do that, I need to consider the order of operations. Remember learning the order of operations back in the day? Yeah, I had to google it too.
Basically it means multiplication and division before addition and subtraction. JavaScript does this automatically, which is awesome!
My problem though was that I had a global variable collecting a long string, like “2+4*52/6+16+3*5”, and I couldn’t easily turn that into a number. I did a good bit of googling, then started the complicated process of creating a function that would parse through a string and deal with the applying math functions to integers, converting strings to integers in order, back and forth. It was painful. But then, luckily, I found the extremely easy answer to this problem!
Long story short: eval(string) is the shit.
JavaScript — Step Infinity: eval(string)
eval(string) can take in a string, like: “2+3*4”, and return the result, 14, like that string were a number. No need for any complicated parsing function!
Finding eval(string) meant tremendous progress towards finishing my calculator app.
Now I didn’t have to worry about making function addition(num1, num2)
or function addition(num1, num2)
or any of that. I just had to make strings!
Here’s the code now:
var globalAnswer = "0" //declaring global variable here... this is bad practicefunction removeLeadingZero(string) {
var newString = string
if (newString[0] === '0') {
console.log('removeLeadingZero-1: remove leading 0 from newString')
newString = newString.slice(1)
}
return newString
}function removeLeadingSymbol(string) {
var newString = string
var symbols = ["*", "/", "+", "-"]
if (symbols.includes(newString[0])) {
console.log('removeLeadingSymbol-1: remove leading symbol from newString')
newString = newString.slice(1)
}
return newString
}function storeAnswer(value) {
console.log('storeAnswer-1: storeAnswer is:::', value)
var value = removeLeadingZero(value)
globalAnswer = value //bad practice -- setting globalAnswer here
console.log('storeAnswer-2: globalAnswer is:::', globalAnswer)
$("#globalAnswer").html(globalAnswer) //set globalAnswer on calculator
console.log('storeAnswer-3: set globalAnswer on calculator')
return value //should be a STRING
}function getCurrentValue() {
var currentValue = document.getElementById("currentValue").innerHTML
console.log('getCurrentValue-- currentValue is a string: ', currentValue)
return currentValue //currentValue will be a STRING
}function clearCurrentValue() {
console.log('CLEAR-1: calling clearCurrentValue... currentValue === 0')
$("#currentValue").html("0") //set currentValue to "0"
console.log('CLEAR-2: call storeAnswer with "0", to reset globalAnswer')
return storeAnswer("0") //set globalAnswer to "0", a STRING
}function equals() {
var answer = globalAnswer //bad practice!!! fix this.
console.log('EQUALS-1: answer is:::', answer) //a STRING
var removeEqualSign = answer.split("=") //remove "=" from end...
var newAnswer = removeEqualSign[0] // //removing "=" from end...
newAnswer = replaceTimesAndDivides(newAnswer)
console.log('EQUALS-2: newAnswer is:::', newAnswer) //a STRING
var finalAnswer = eval(newAnswer) //pass answer to eval, turning it into a number
finalAnswer = finalAnswer.toString() //make a string again
storeAndReset(finalAnswer, finalAnswer)
console.log('EQUALS-3: finalAnswer is:::', finalAnswer)
return finalAnswer //returning finalAnswer, a STRING
}function clickButton(event) {
$(".btn").click(function(event) {
var thingClicked = this.innerHTML
console.log("0. you clicked: ", thingClicked)
if ($(this).hasClass("orange")) {
console.log(`clickButton-1. ${thingClicked} is in the orange class!`)
return addSymbolToAnswer(thingClicked)
}if ($(this).hasClass("num")) {
console.log(`clickButton-2. ${thingClicked} is in the num class!`)
return createNewNumber(thingClicked)
}if ($(this).hasClass("clear")) {
console.log('clickButton-3. clearCurrentValue called!')
return clearCurrentValue()
}if ($(this).hasClass("equals")) {
console.log('clickButton-4. equals pressed!')
addSymbolToAnswer(thingClicked) //thingClicked is "="
return equals()
}
})
}
clickButton(event)function replaceTimesAndDivides(string) {
string = string.replace("x", "*")
string = string.replace("÷", "/")
return string
}function addSymbolToAnswer(string) {
var symbolString = string
symbolString = replaceTimesAndDivides(symbolString)
console.log('ORANGE-1. symbolString is: ', symbolString)
var currentValue = getCurrentValue()
var symbols = ["*", "/", "+", "-"]
console.log('ORANGE-2. globalAnswer is now: ', globalAnswer)if (globalAnswer === currentValue) { //after "=" was pressed...
console.log('ORANGE-3a. after "=" pressed, just need one symbol added to currentValue')
var newGlobalAnswer = currentValue + symbolString //add symbol to end of newGlobal
return storeAndReset(newGlobalAnswer, symbolString)
}
if (symbols.includes(currentValue)) { //if a symbol was already pressed...
console.log('Orange-3b: currentValue and symbolString are both symbols!')
currentValue = currentValue.replace(currentValue, symbolString)
console.log('Orange-3b: replaced currentValue with ', symbolString)
var newGlobalAnswer = globalAnswer.slice(0, -1) + currentValue
console.log('Orange-4b: replaced lastChar in newGlobalAnswer with', currentValue)
return storeAndReset(newGlobalAnswer, symbolString)
} else { //otherwise, adding new symbol to currentValue...
console.log('ORANGE-3c: adding new symbol to currentValue')
currentValue = currentValue + symbolString //add symbol to end of currentValue...
console.log('ORANGE-3c. new currentValue is: ', currentValue)
var newGlobalAnswer = globalAnswer + currentValue
return storeAndReset(newGlobalAnswer, symbolString)
}
}function storeAndReset(newGlobalAnswer, newCurrentValue) {
storeAnswer(newGlobalAnswer)
$("#currentValue").html(newCurrentValue)
console.log('storeAndReset: replaced currentValue with symbol: ', newCurrentValue)
return newCurrentValue
}function createNewNumber(string) {
var thingClicked = string
var currentValue = getCurrentValue()
var newString = currentValue + thingClicked //add into newString
newString = removeLeadingZero(newString)
newString = removeLeadingSymbol(newString)
console.log('createNewNumber-1: newString is: ', newString)
$("#currentValue").html(newString)
return newString
}
Whoa, that’s a lot of code.
I ended up with 12 functions and about 150 lines of code. Lots of those functions are smaller helper functions, and lots of those lines of code are console.logs, but my calculator works! For the most part. I still have to add some functionality to the +/- button and the % button. But otherwise, everything is working as expected. I can chain commands, and keep on pressing buttons until I want the answer by pressing =, and then chain more commands onto that number. Pretty cool.
For example, here’s my calculator at work, given the problem “2+3*4/2”:
And here’s the solution:
That ugly green and blue at the top was helpful in debugging issues. Sometimes it can be tough doing everything in the console, at which point it’s helpful to see all your inputs and outputs in the app’s frontend.
For my final two buttons, I added some additional functions.
For the +/- button:
function makeCurrentValueNegative() {
var currentValue = document.getElementById("currentValue").innerHTML
console.log('currentValue in makeInputNegative is: ', currentValue)
if(currentValue[0] === "-") {
currentValue = currentValue.slice(1)
$("#currentValue").html(currentValue)
} else {
$("#currentValue").prepend("-")
}
return currentValue
}
And I didn’t want users to be able to click the +/- button, AKA the “.negative” button, after a user clicked a function button, so I disabled the “.negative” button whenever addSymbolToAnswer was called:
function addSymbolToAnswer(string) {
$('.negative').prop('disabled', true) ...
...}
UPDATE: allowing negative numbers kept fucking up the functionality of my app, so I decided to disable it. That’s OK. This calculator’s all about positivity!
For the % button:
The % button was easier. I tested it in my console. I don’t totally understand how it works, no one does! But I realized I could add it to my string of characters, and let my JavaScript figure out the final answer with eval(string). Cool! Done and done.
Calculator — Final Version, Draft 1
Here’s my final version of my calculator, with the ugly green and blue spans at the top: https://codepen.io/ethanryan/full/dJGyMJ/
I like showing how the sausage is made, warts and all. Ew. Talk about a gross word salad.
Calculator — Final Version, Draft 2
And here’s my FINAL final draft, until I decide to do another even better draft.
Final draft: https://codepen.io/ethanryan/full/MryqXv/
I threw in some Easter eggs for whenever the calculator’s current value equals 420 or 666. Hey, stoners and Satanists have to do math too!
Also, there’s one last Easter egg for Prince fans who like to party like it’s the turn of the century.
Math is fun. Who knew making calculators could be fun too!
Making a calculator involved some math, but mostly it was all about string manipulation. And I like strings.
Thanks nerds.
Bye!