Search code examples
javascripthtmlcalculator

Javascript create a calculator and display the result


I'm currently working on a basic calculator project using JavaScript, and I'm encountering an issue with displaying the calculations on the calculator screen.

As a beginner in JavaScript, I've been trying to implement the functionality where clicking on the calculator buttons should display the corresponding calculations on the screen. However, despite my efforts, nothing seems to be appearing on the calculator screen.

I've checked my code and attempted to debug, but as a newcomer to JavaScript, I'm finding it challenging to identify the root cause of the problem.

I would greatly appreciate it if someone could take a look at my code and provide guidance on what might be going wrong. I'm open to any suggestions or corrections to my code.

Here's a simplified version of my JavaScript code:

let num1 = null;
let num2 = null;
let operator = null;
let result = null;
const calcBtn = document.querySelectorAll('.btn');
const outputNum = document.getElementById('outputNum');

//display the number clicked
const displayValue = () => {
  if (num1 !== null && operator !== null) {
    outputNum.innerHTML = `<p id="outputNum">${num1} ${operator} ${num2 !== null}</p>`
  }
}





//dertermine how calculator will work
const calcul = (num1, num2, operator) => {
  let result;

  switch (num1, num2, operator) {
    case '+':
      result = num1 + num2
      break;
    case '-':
      result = num1 - num2
      break;
    case '*':
      result = num1 * num2
      break;
    case '/':
      result = num1 / num2
      break;
    case '%':
      result = num1 % num2
      break;
  }
  return result;
}

//detect which button is clicked and assign it to a variable
const calculBtn = (e) => {

  const btn = e.target.textContent;

  if (btn >= '0' && btn <= '9') {
    if (num1 === null) {
      num1 = parseInt(btn);
    } else if (operator === null) {
      num1 * 10 + parseInt(btn);
    }
    if (num2 === null) {
      num2 = parseInt(btn);
    } else if (result === null) {
      num2 * 10 + parseInt(btn);

      displayValue();

    } else if (operator === 'C') {
      num1 = null;
      num2 = null;
      operator = null;
      outputNum.innerHTML = '';

    } else if (btn === '=') {
      const result = calcul(num1, num2, operator);
      outputNum.innerHTML = result;

      num1 = result;
      num2 = null;
      operator = null;

    } else {
      operator = btn;
      displayValue();
    }
  }

}




calcBtn.forEach(btn => {
  btn.addEventListener('click', calculBtn)
});
<div class="calculator">
  <div class="display">
    <div class="output">
      <p id="outputNum"></p>
    </div>
  </div>

  <div class="first-row">
    <div class="btn clear">C</div>
    <div class="btn operator">%</div>
    <div class="btn operator">/</div>
    <div class="btn operator">x</div>
  </div>

  <div class="second-row">
    <div class="btn ">7</div>
    <div class="btn">8</div>
    <div class="btn">9</div>
    <div class="btn operator">-</div>
  </div>

  <div class="third-row">
    <div class="btn">4</div>
    <div class="btn">5</div>
    <div class="btn">6</div>
    <div class="btn operator">+</div>
  </div>

  <div class="fourth-row">
    <div class="btn">1</div>
    <div class="btn">2</div>
    <div class="btn">3</div>
    <div class="btn result">=</div>
  </div>

  <div class="fifth-row">
    <div class="btn">0</div>
  </div>
</div>


Solution

  • In calculBtn(), it seems more intuitive to try to see if the textContent is an integer, instead of using greater/less than or equal to operators with strings. So consider instead of:

    const btn = e.target.textContent;
    
    if (btn >= '0' && btn <= '9') {
    

    Do:

    const btn = e.target.textContent;
    const maybeInt = parseInt(btn, 10);
    if (Number.isInteger(maybeInt)) {
    

    Furthermore, again in calculBtn(), it seems life the conditional branches are flawed:

    // This if limits this code branch to 0-9 only, meaning:
    if (Number.isInteger(maybeInt)) {
      if (num1 === null) {
        …
      } else if (operator === null) {
        …
      }
      if (num2 === null) {
        …
      } else if (result === null) {
        // This branch is never visited since the parent conditional `if` branch
        // has already limited this code branch to 0-9 only.
      } else if (operator === 'C') {
        // This is never visited.
      } else if (btn === '=') {
        // This is never visited.
      } else {
        // This is never visited.
      }
    }
    

    This means the code never visits the later conditional branches as indicated above which means the non-number buttons never do anything, meaning operator is never assigned a value. This in turn means that in displayValue():

    if (num1 !== null && operator !== null) {
    

    This conditional would never evaluate to a truthy value and thus nothing would ever be displayed in the HTML.

    Instead, we should have the operator conditionals in calculBtn() be branches from the initial if, not inside it:

    if (Number.isInteger(maybeInt)) {
      …
    } else if (operator === 'C') {
      …
    } else if (btn === '=') {
      …
    } else {
      …
    }
    

    With all these changes, there will at least be a display once num1 and operator are not null:

    let num1 = null;
    let num2 = null;
    let operator = null;
    let result = null;
    const calcBtn = document.querySelectorAll(".btn");
    const outputNum = document.getElementById("outputNum");
    
    //display the number clicked
    const displayValue = () => {
      if (num1 !== null && operator !== null) {
        outputNum.innerHTML = `<p id="outputNum">${num1} ${operator} ${num2 !== null}</p>`;
      }
    };
    
    //dertermine how calculator will work
    const calcul = (num1, num2, operator) => {
      let result;
    
      switch ((num1, num2, operator)) {
        case "+":
          result = num1 + num2;
          break;
        case "-":
          result = num1 - num2;
          break;
        case "*":
          result = num1 * num2;
          break;
        case "/":
          result = num1 / num2;
          break;
        case "%":
          result = num1 % num2;
          break;
      }
      return result;
    };
    
    //detect which button is clicked and assign it to a variable
    const calculBtn = (e) => {
      const btn = e.target.textContent;
      const maybeInt = parseInt(btn, 10);
      if (Number.isInteger(maybeInt)) {
        if (num1 === null) {
          num1 = parseInt(btn);
        } else if (operator === null) {
          num1 * 10 + parseInt(btn);
        }
        if (num2 === null) {
          num2 = parseInt(btn);
        } else if (result === null) {
          num2 * 10 + parseInt(btn);
          displayValue();
        }
      } else if (operator === "C") {
        num1 = null;
        num2 = null;
        operator = null;
        outputNum.innerHTML = "";
      } else if (btn === "=") {
        const result = calcul(num1, num2, operator);
        outputNum.innerHTML = result;
    
        num1 = result;
        num2 = null;
        operator = null;
      } else {
        operator = btn;
        displayValue();
      }
    };
    
    calcBtn.forEach((btn) => {
      btn.addEventListener("click", calculBtn);
    });
    <div class="calculator">
      <div class="display">
        <div class="output">
          <p id="outputNum"></p>
        </div>
      </div>
    
      <div class="first-row">
        <div class="btn clear">C</div>
        <div class="btn operator">%</div>
        <div class="btn operator">/</div>
        <div class="btn operator">x</div>
      </div>
    
      <div class="second-row">
        <div class="btn">7</div>
        <div class="btn">8</div>
        <div class="btn">9</div>
        <div class="btn operator">-</div>
      </div>
    
      <div class="third-row">
        <div class="btn">4</div>
        <div class="btn">5</div>
        <div class="btn">6</div>
        <div class="btn operator">+</div>
      </div>
    
      <div class="fourth-row">
        <div class="btn">1</div>
        <div class="btn">2</div>
        <div class="btn">3</div>
        <div class="btn result">=</div>
      </div>
    
      <div class="fifth-row">
        <div class="btn">0</div>
      </div>
    </div>