Inputting operators

The next step is to get the operators (+, -, x, /, =) on the calculator working.

If user hits an operator key, the operator should be highlighted so Mary knows the operator is active. To do so, we can add the is-depressed class to the operator key.

Update your js file like so:

1
2
3
4
5
6
7
8
if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  key.classList.add('is-depressed')
}

When a user hits a number key after an operator key

When user hits a number key again, the previous display should be replaced with the new number. The operator key should also release its pressed state.

To release the pressed state, we remove the is-depressed class from all keys through a forEach loop:

update your js file so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
keys.addEventListener('click', e => {
  if (e.target.matches('button')) {
    const key = e.target
    // ...

    // Remove .is-depressed class from all keys
    Array.from(key.parentNode.children)
      .forEach(k => k.classList.remove('is-depressed'))
  }
})

Next, we want to update the display to the clicked key. Before we do this, we need a way to tell if the previous key is an operator key.

One way to do this is through a custom attribute. Let’s call this custom attribute data-previous-key-type.

Update you js file like so

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const calculator = document.querySelector('.calculator')
// ...

keys.addEventListener('click', e => {
  if (e.target.matches('button')) {
    // ...

    if (
      action === 'add' ||
      action === 'subtract' ||
      action === 'multiply' ||
      action === 'divide'
    ) {
      key.classList.add('is-depressed')
      // Add custom attribute
      calculator.dataset.previousKeyType = 'operator'
    }
  }
})

If the previousKeyType is an operator, we want to replace the displayed number with clicked number.

Update your js file like so:

1
2
3
4
5
6
7
8
9
const previousKeyType = calculator.dataset.previousKeyType

if (!action) {
  if (displayedNum === '0' || previousKeyType === 'operator') {
    display.textContent = keyContent
  } else {
    display.textContent = displayedNum + keyContent
  }
}

Next, let’s say user decides to complete her calculation by hitting the equals key.

When a user hits the equals key

When user hits the equals key, the calculator should calculate a result that depends on three values:

  • The first number entered into the calculator

  • The operator

  • The second number entered into the calculator

After the calculation, the result should replace the displayed value.

update js file like so:

1
2
3
4
if (action === 'calculate') {
  const secondValue = displayedNum
  // ...
}

To get the first number, we need to store the calculator’s displayed value before we wipe it clean. One way to save this first number is to add it to a custom attribute when the operator button gets clicked.

To get the operator, we can also use the same technique.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
if (
  action === 'add' ||
  action === 'subtract' ||
  action === 'multiply' ||
  action === 'divide'
) {
  // ...
  calculator.dataset.firstValue = displayedNum
  calculator.dataset.operator = action
}

Once we have the three values we need, we can perform a calculation. Eventually, we want the code to look something like this:

1
2
3
4
5
6
7
if (action === 'calculate') {
  const firstValue = calculator.dataset.firstValue
  const operator = calculator.dataset.operator
  const secondValue = displayedNum

  display.textContent = calculate(firstValue, operator, secondValue)
}

That means we need to create a calculate function. It should take in three parameters: the first number, the operator, and the second number.

Functions.

User defined function

Mostly commonly used form of functiom in modern js is lambda function.So that will be our approach.

add this your js file:

1
2
3
const calculate = (n1, operator, n2) => {
  // Perform calculation and return calculated value
}

Note this would have been written like so

1
2
3
function calculate(n1, operator, n2){

}

If the operator is add, we want to add values together. If the operator is subtract, we want to subtract the values, and so on. Add this to your js file

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const calculate = (n1, operator, n2) => {
  let result = ''

  if (operator === 'add') {
    result = n1 + n2
  } else if (operator === 'subtract') {
    result = n1 - n2
  } else if (operator === 'multiply') {
    result = n1 * n2
  } else if (operator === 'divide') {
    result = n1 / n2
  } 

  return result
}

If you closely the data we passing are strings there if n1 = 1 and n2 = 1. If add two or more string this would be 11.

user inbuilt functions

So, before calculating the result, we want to convert strings to numbers. We can do so with the two functions parseInt and parseFloat.

  • parseInt converts a string into an integer.

  • parseFloat converts a string into a float (this means a number with decimal places)

Just like inbuilt functions in ruby they help us easy data manipulation without writing our own.

There is official documentation for javascript but you always rely on msdn

Let us tweak our to convert our string into number.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const calculate = (n1, operator, n2) => {
  let result = ''

  if (operator === 'add') {
    result = parseFloat(n1) + parseFloat(n2)
  } else if (operator === 'subtract') {
    result = parseFloat(n1) - parseFloat(n2)
  } else if (operator === 'multiply') {
    result = parseFloat(n1) * parseFloat(n2)
  } else if (operator === 'divide') {
    result = parseFloat(n1) / parseFloat(n2)
  }

  return result
}

By now our calculator should be able to basic arithmetics.If we are in happy path that is give only input it requires without breaking the rules. For instance 20/20 and not 20//20