Building a JavaScript Calculator from scratch? - javascript

I am trying to build a JavaScript calculator from scratch, without following a tutorial, as a learning exercise. Much of the functionality is working, except if a calculation is performed right after another. ie:
7 x 6 + 42
In that case, it resets the display to 0 but seems to keep the variable anyways.
Is it necessary to store the numbers in 3 values, instead of 2? Currently I'm using:
-currentValue, which holds the previous total of the calculation.
-newValue, which is the number the user is currently entering.
function newNum(pressed) { //Adds digit of key pressed to new number being entered.
//console.log ("Button pressed " + pressed);
if (newValue == 0) { //If new calculation, newValue is set to key pressed.
newValue += pressed;
} else { //Else if continuing calculation, key pressed is added to end of newValue.
newValue = newValue.toString();
newValue = newValue + pressed; //Adds digit at end of String, then converts back to Number.
newValue = parseFloat(newValue);
}
document.getElementById('result').innerHTML = newValue;
}
function newCalc(pressed) { //Will use this mathematical operation to find the value.
if (!currentValue) {
currentValue = newValue;
} else {
document.getElementById('result').innerHTML = newValue;
}
newOperation = pressed;
newValue = 0;
}
function equals() { //Resolves calculation.
newValue = parseFloat(newValue);
switch(newOperation) {
case "/":
currentValue = (currentValue / newValue);
break;
case "*":
currentValue = (currentValue * newValue);
break;
case "-":
currentValue = (currentValue - newValue);
break;
case "+":
currentValue = (currentValue + newValue);
break;
}
currentValue = parseFloat(currentValue);
newValue = 0;
document.getElementById('result').innerHTML = currentValue;
}
https://codepen.io/adam_weiler/pen/aRNppX
I'm still learning and I know the code is a bit bloated. Any suggestions how to streamline it would be helpful too!
EDIT: I gave a bad example. I'm just coding a basic calculator, where you tap buttons to enter numbers. It doesn't use BEDMAS; the order of operations is "the order the user inputs them". So yeah, just a basic tapping calculator.

If you input
7 | x | 8 | = | + | 5 | = |
it works without problems. I guess you want to execute equals() whenever an operation button is pressed, not only on =...
Is it necessary to store the numbers in 3 values, instead of 2?
No you don't have to. The trick is to perform one operation after another so you always work with only two values:
7
7 x
7 x 8
7 x 8 +
46 + // merged
46 + 5
46 + 5 =
51 // merged

In your example, the code tries to calculate the 7*6 and the 6+42 at the same time, but there is no 6 which can be added to the 42 because it was multiplied by 7, so it can't be calculated with. You should make rules to the operation preference, when there is a multiplying or a dividing the sorrounding numbers should be calculated as the new number and then you can operate further with your adding or substracting. Also, you should define the left-to-right rule as well, so if you have 2*3/4 then the error won't occur again.

Related

JavaScript adding additional actions after receiving the result

I'm making a calculator in JS that displays commands and the result in a prompt.
I want to add an action that, after receiving the result of the operation, makes it possible to multiply, divide, etc. by another number.
Action plan: First action... = result > choose selector ( +, -, *,/) > choose second number > result --- and so on until you stop pressing enter with a blank field.
I was thinking of starting with a while loop to add the ability to choose a character but I don't know if it will affect the result of the previous action, additionally I don't know how to add the ability to choose the next number
switch (operator) {
case '+':
alert(numb1 + numb2)
break
case '-':
alert(numb1 - numb2)
break
case '*':
alert(numb1 * numb2)
break
case '/':
alert(numb1 / numb2)
break
case '%':
alert(numb1 % numb2)
break
}
while (true) {
let result = +prompt('Enter an arithmetic operator or leave blank.')
if (!result) break
}
}
Yes you can use while loop with a new param to get the new value input with prompt, such that:
while (true) {
let result = +prompt('Enter an arithmetic operator or leave blank.')
if (!result) break
let newNumber = +prompt('Enter a new number')
// do the arithmetic operation
}
Additionally, the operation in switch seems to be quite redundant. i.e.: one case for alert in one character / operator change.
You might want to use eval() for the operation.
let numb1 = 1 // original number
while (true) {
let result = prompt('Enter an arithmetic operator or leave blank.')
if (!result) break
let newNumber = prompt('Enter a new number')
// do the arithmetic operation
// if numb1 = 1, new Number = 2, result = '+', it will show '1 + 2'
alert(`${numb1} ${result} ${newNumber}`)
// numb1 = 3
numb1 = eval(`${numb1} ${result} ${newNumber}`)
}
For converting string to operation, please refer to this answer:
https://stackoverflow.com/a/26551015/9067107
This seens like a learning exercise, so I'll try to explain some thought before showing some code.
Your switch case assumes num1 and num2 are already known, but what you described says that num2 will only come after the operator.
Also, you want that math being done inside the loop, else it will only run once.
What you want is:
type first number;
type operator;
type next number;
show result = first/old number (operator) next/last number input;
type operator;
type next number;
show result = first/old number (operator) next/last number input;
... and so on until the "end command" is input.
We have to respect that order, so we'll need to store results and actions. This way we can keep the loop "alive".
Another thing, to be a "good loop", it has to start and end with the same actions.
So, we'll leave the first number input out of the loop, that way it will be something liek this:
ask "first number"
ask "operator" -> (end?) -> ask "next number" -> store and show "result"
ask "operator" -> (end?) -> ask "next number" -> store and show "result"
... and so on ...
// start prompting the user for the first number.
let oldNum = +prompt("first number: ");
let continue = true; // this is the condition to continue or end our loop.
while(continue) {
// prompt the user for the operator
let op = prompt('operator: ');
if (!(op === "+" || op === "-" || op === "/" || op === "*")) break;
// if anything aside from the expected inputs, the loop breaks.
let num = prompt('next number: ');
switch(op) {
case '+':
oldNum += num; // we add the new value to the old one.
break;
case '-':
oldNum -= num;
break;
case '/':
oldNum /= num;
break;
case '*':
oldNum *= num;
break;
}
// show result to user
alert(oldNum);
}
BTW, there are better ways to write this particular code, tried to make it similar to what you shown.

A task in JavaScript

I need to create a sequence of numbers using while or for that consists of the sum of the symbols of the number.
For example, I have a sequence from 1 to 10. In console (if I've already written a code) will go just 1, 2,3,4,5,6,7,8,9,1. If I take it from 30 to 40 in the console would be 3,4,5,6,7,8,9,10,11,12,13.
I need to create a code that displays a sum that goes from 1 to 100. I don't know how to do it but in console I need to see:
1
2
3
4
5
5
6
7
8
9
1
2
3
4
etc.
I've got some code but I got only NaN. I don't know why. Could you explain this to me?
for (let i = '1'; i <= 99; i++) {
let a = Number(i[0]);
let b = Number(i[1])
let b1 = Boolean(b)
if (b1 == false) {
console.log ('b false', a)
}
else {
console.log ('b true', a + b)
}
}
I hope you get what I was speaking about.
Although I like the accepted answer however from question I gather you were asking something else, that is;
30 become 3+0=3
31 become 3+1=4
37 becomes 3+7=10
Why are we checking for boolean is beyond the scope of the question
Here is simple snnipet does exactly what you ask for
for (let i = 30; i <= 40; i++) {
let x=i.toString();
console.log( 'numbers from ' +i + ' are added together to become '+ (Number(x[0])+Number((x[1])||0)))
}
what er are doing is exactly what Maskin stated begin with for loop then in each increment convert it to string so we can split it, this takes care of NAN issue.
you don't need to call to string just do it once as in let x then simply call the split as x[0] and so on.
within second number we have created a self computation (x[1])||0) that is if there is second value if not then zero. following would work like charm
for (let i = 1; i <= 10; i++) {
let x=i.toString();
console.log( 'numbers from ' +i + ' are added together to become '+ (Number(x[0])+Number((x[1])||0)))
}
Did you observe what happens to ten
here is my real question and solution what if you Don't know the length of the digits in number or for what ever reason you are to go about staring from 100 on wards. We need some form of AI into the code
for (let i = 110; i <= 120; i++) {
let x= Array.from(String(i), Number);
console.log(
x.reduce(function(a, b){ return a + b;})
);
};
You simply make an array with Array.from function then use simple Array.reduce function to run custom functions that adds up all the values as sum, finally run that in console.
Nice, simple and AI
You got NaN because of "i[0]". You need to add toString() call.
for (let i = '1'; i <= 99; i++) {
let a = Number(i.toString()[0]);
let b = Number(i.toString()[1])
let b1 = Boolean(b)
if (b1 == false) {
console.log('b false', a)
} else {
console.log('b true', a + b)
}
}
So the way a for loop works is that you declare a variable to loop, then state the loop condition and then you ask what happens at the end of the loop, normally you increment (which means take the variable and add one to it).
When you say let i = '1', what you're actually doing, is creating a new string, which when you ask for i[0], it gives you the first character in the string.
You should look up the modulo operator. You want to add the number of units, which you can get by dividing by 10 and then casting to an int, to the number in the tens, which you get with the modulo.
As an aside, when you ask a question on StackOverflow, you should ask in a way that means people who have similar questions to you can find their answers.

JavaScript IF statement evaluating TRUE incorrectly - why?

I have a very, very simple logical test of the number of licenses a customer has purchased vs. the number they have used:
else if(utype == "3"){
var tech_lic = $("#technician_lic").val();
console.log('tech lic = ' + tech_lic)
var tech_allow = $("#technician_lic_allow").val();
console.log('tech allow = ' + tech_allow)
if(tech_lic >= tech_allow)
{
alert("You must purchase more licenses to create this Technician");
return false;
}
I threw in the console.log statements trying to debug this - normally they aren't there.
Console.log when I click "add" button:
tech lic = 4 application.js:262
tech allow = 100 application.js:264
Then we hit "You must purchase more licenses" alert in the window.
WHAT THE HECK?
How can 4 >= 100 evaluate true?
Because .val returns a string. '4' is indeed greater than or equal to '100'. Cast the values to numbers first (if you know that they are always numbers for the purposes of this comparison).
if (+tech_lic >= +tech_allow)
You are evaluating them as strings, so "4" IS greater than "100".
You will need to cast them as integers before comparison:
var tech_lic = parseInt($("#technician_lic").val(), 10);
var tech_allow = parseInt($("#technician_lic_allow").val(), 10);
The string "4" is greater than "100", whereas the number 4 is less than 100.
It's not that 4 >= 100 is true, it's that "4" >= "100" is true.
The values that you get are strings, so they will be compared lexically, not numerically.
Parse the values into numbers:
var tech_lic = parseInt($("#technician_lic").val(), 10);
var tech_allow = parseInt($("#technician_lic_allow").val(), 10);
Do this way:-
if(Number(tech_lic) >= Number(tech_allow))
{
// Do your stuff
}

ignoring empty strings when looping through an array in JavaScript

I am attempting to go through an array and add up all the numbers. I used console.log to show me what values the script was using as shown below. I keep trying different variations of things in the if() but nothing seems to be working properly.
var billycount = 0;
var billyTotalScore = billyScoreList.reduce(function(score, total) {
if(score === " ") {
billycount += 1;
}
return +total + +score;
});
console.log(billycount); //0
console.log(billyTotalScore); //30
console.log(billyScoreList); // ["12", " ", "18"]
console.log(billyAverageScore) //10
var billyAverageScore = billyTotalScore/(billyteamlist.length - billycount);
The answer to billyAverageScore should equal 15 (30/2).
I tried if(score === "0") which gives me the same answers as above and if (score !== true) which gives me a count of 2 and an average of 30. I think reduce() is treating the empty string as a 0. I want to be able to count all the empty strings so I can discount them from the length when finding the average.
I have been wrestling this forever and feel like I'm missing one key concept behind it. Any help would be great! Thanks!
UPDATE:
For anyone who stumbles across this, here is the code I got to work.
var billycount = 0;
var billyTotalScore = billyScoreList.reduce(function(total, score) {
if (score === " " || total === " ") {
billycount++;
}
return +total + +score;
});
var billyAverageScore = billyTotalScore/(billyteamlist.length - billycount);
When I was just checking if (score === " ") I was forgetting that score will never be equal to the first term in the array. I just added || total === " ". the only time this would break down would be if the first element was " " and the second element was 0. I would want to billycount++ for the first element but not for the second. I'll have to give that some more thought.
The callback function of reduce should be function(total, score) instead of function(score, total).
see MDN:
previousValue
The value previously returned in the last invocation of the callback, or initialValue, if supplied. (See below.)
currentValue
The current element being processed in the array.

I want spinner to display numbers properly

I have 2 questions:
Question 1: I have a spinner function and I have one slight problem with it. If a user types in 00000009 or 00021 in the spinner for example, if the user clicks away from the spinner, it will still display 00000009 or 00021 in the spinner. What I want is that if something like this happens, then what I want is that when the user clicks away, I want the spinner to display it as 9 or 21 rather than 00000009 or 00021. I don't know how to do this though. Does anyone know how to overcome this:
Question 2: If I used backspace to remove a number from a spinner and that is left with a blank spinner, what needs to be done so that if I click away from the spinner, the last number in the spinner re-appears in the spinner?
My main spinner function:
function Spinner(elem,min, max){
this.elem = elem;
this.elem.value = min;
this.min = min;
this.max = max;
this.timer;
this.speed = 150; //milliseconds between scroll values
var selfO = this;
this.elem.onkeyup = function(){
var regex = /^[0-9]*$/;
if(!regex.test(selfO.elem.value)){
selfO.elem.value = selfO.elem.value.substring(0,selfO.elem.value.length-1);
return;
}
selfO.validateValue();
}
this.validateValue = function(){
if(Number(selfO.elem.value) > selfO.max) {selfO.elem.value = selfO.max;}
if(Number(selfO.elem.value) < selfO.min) {selfO.elem.value = selfO.min;}
}
this.stopSpinning = function(){
clearTimeout(selfO.timer);
}
this.spinValue = function(dir){
selfO.elem.value = Number(selfO.elem.value) + dir;
selfO.validateValue();
selfO.timer = setTimeout(function(){selfO.spinValue(dir);},selfO.speed);
}
};
window.onload=function(){
//create the Spinner objects
var SpinnerHours = new Spinner(document.getElementById('txtHours'),0,23);
}
To return a number like 00000009 as 9 use parseInt();
alert( parseInt(000000009, 10) ); // returns 9
As pointed out by Jonathan Lonowski The second parameter is the radix.
The radix parameter is used to specify which numeral system to be used, for example, a radix of 16 (hexadecimal) indicates that the number in the string should be parsed from a hexadecimal number to a decimal number.
If the radix parameter is omitted, JavaScript assumes the following:
If the string begins with "0x", the radix is 16 (hexadecimal)
If the string begins with "0", the radix is 8 (octal). This feature is deprecated
If the string begins with any other value, the radix is 10 (decimal)
//question 2 answer
var input='';
document.getElementById('inputName').onkeydown=function(e){
e = e || window.event;
keycode = e.keyCode || e.which;
if(keycode !== 8 || keycode !== 46){//backspace and delete keycodes
input=this.value;
}
}
//question 1 answer
document.getElementById('inputName').onblur=function(){
var a=this.value;
if(isNaN(a)){
this.value=input-0;
}
else{
this.value=a-0;
}
}
What this does is when a user is entering a number it saves the value unless the are pressing delete or backspace. Then when the input loses focus it checks and if there is not a valid number there it changes it to the saved value. Also the onblur get rid of any extra zeroes. Also, you will need to add more to the part that checks the input. For instance changing any non-numeric input to ''. In other words it isn't idiot proof.

Categories

Resources