Simple Calculator using Vue and Bootstrap 5
Tags: webdev, vue, bootstrap, javascript
Published: 2021-06-23 16:51:37

---
title: Simple Calculator using Vue and Bootstrap 5
published: true
description: How to create a calculator using Bootstrap 5 and Vue.js
tags: webdev, vue, bootstrap, javascript
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5d6ldraidazi5m1yrcvt.png
---


---

**The HTML Markup**

Bootstrap 5 provides all the UI styling and responsive behavior. It's a great fit with Vue now that it's no longer dependent on jQuery. The [Bootstrap grid](https://getbootstrap.com/docs/5.0/layout/grid/) `row` & `col-*` are used to responsively change the calculator width as screen size changes.


```html
<div class="row">
        <div class="col-xxl-2 col-lg-3 col-md-4 col-sm-6 mx-auto bg-dark rounded-3 shadow-sm p-3">
            <input class="form-control form-control-lg text-success" v-model="calculator.displayValue" />
            <!-- calculator number pad using grid -->
            <div class="row g-0 text-center mt-2">
                <div class="col-auto text-white">
                    <div class="row g-1 g-lg-1">
                        <div v-for="(key,i) in keypad" :key="i" class="ms-auto col-3 py-2">
                            <button class="btn btn-dark text-warning w-100" @click="processKey(key.value)">{{ key.label }}</button>
                        </div>
                        <div class="col-12 pt-2">
                            <button class="btn btn-dark border-secondary btn-lg text-warning w-100 fw-bold lead" @click="processKey('=')">=</button>
                        </div>
                        <div class="col-12">
                            <div v-if="errValue" class="alert alert-warning p-2 text-truncate small" role="alert">
                              {{ errValue }}
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
```

![Bootstrap 5 Vue Calculator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7rxqam8wr064qte264t.gif)

---

**The Vue App Data**

Calculator state is kept in it's own data `calculator` object to track the `displayValue`, `firstOperand` and `operator`. `waitingForSecondOperand` let's us know when it's ready to perform a calculation.

The `keypad` array is ordered by how I wanted the keys to render as columns inside the Bootstrap `row`...

```html
<div v-for="(key,i) in keypad" :key="i" class="ms-auto col-3 py-2">
   <button class="btn btn-dark w-100" @click="processKey(key.value)">{{ key.label }}</button>
</div>
```



```javascript
...
  data () {
      return {
        calculator: {
            displayValue: '0',
            firstOperand: null,
            waitingForSecondOperand: false,
            operator: null,
        },
        errValue: null,
        keypad: [
            {label:'7', value: 7},
            {label:'8', value: 8},
            {label:'9', value: 9},
            {label:'x', value: '*'},
            {label:'4', value: 4},
            {label:'5', value: 5},
            {label:'6', value: 6},
            {label:'+', value: '+'},
            {label:'1', value: 1},
            {label:'2', value: 2},
            {label:'3', value: 3},
            {label:'-', value: '-'},
            {label:'AC', value: 'AC'},
            {label:'.', value: '.'},
            {label:'0', value: 0},
            {label:'/', value: '/'},
        ],
  },
...
```
---

**The Vue App Methods**

Of course the calculator actually needs to *calculate* so I define a series of methods to watch the keystrokes and perform basic math functions. Most of them should be self-explanatory. You will see that `errValue` is used to store any errors, and resets upon keypress or clear.

When a key is pressed, `processKey()` is called to determine which key and then call the appropriate function...

- `inputDigit()` - when any digit is clicked
- `handleOperator()` - when any operator is clicked
- `equalPressed()` - when the equal sign is clicked 
- `inputDecimal()` - to handle the decimal point (.)
- `resetCalculator()` - to clear the calculator ('AC')


```javascript
...
  methods: {
    processKey: function(val) {
        this.errValue = null
        switch (val){
          case "AC": this.resetCalculator()
            break;
          case 0:
          case 1:
          case 2:
          case 3:
          case 4:
          case 5:
          case 6:
          case 7:
          case 8:
          case 9: this.inputDigit(val)
          break; 
          case "+": this.handleOperator("+")
            break;
          case "-": this.handleOperator("-")
            break;
          case "/": this.handleOperator("/")
            break;
          case "*": this.handleOperator("*")
            break;
          case "=": this.equalPressed();
            break;
          case ".": this.inputDecimal(".")
              break;
          default:
              this.errValue = 'KEY ERROR: in default'
        }
    },
    equalPressed() {
        const { firstOperand, displayValue, operator } = this.calculator
        try{
            this.calculator.displayValue = this.calculate(firstOperand, displayValue, operator)
        }
        catch (e){
            this.errValue = e
        }
    },
    inputDigit(digit) {
        const { displayValue, waitingForSecondOperand } = this.calculator
        console.log(waitingForSecondOperand)
        if (waitingForSecondOperand === true) {
            this.calculator.displayValue = digit
            this.calculator.waitingForSecondOperand = false
        } else {
            console.log(displayValue)
            this.calculator.displayValue =
                displayValue === '0' ? digit : displayValue + '' + digit
        }
    },
    inputDecimal(dot) {
        const { displayValue, waitingForSecondOperand } = this.calculator
        if (waitingForSecondOperand === true) {
            this.calculator.displayValue = '0.'
            this.calculator.waitingForSecondOperand = false
            return
        }

        // check for existing decimal
        if (displayValue % 1 === 0) {
            this.calculator.displayValue += dot
        }
    },
    handleOperator(nextOperator) {
        const { firstOperand, displayValue, operator, waitingForSecondOperand } = this.calculator
        const inputValue = parseFloat(displayValue)
        
        if (operator && waitingForSecondOperand) {
            this.calculator.operator = nextOperator
            return
        }
        
        if (firstOperand == null && !isNaN(inputValue)) {
            this.calculator.firstOperand = inputValue
        } else if (operator) {
            const currentValue = firstOperand || 0
            const result = this.calculate(currentValue, inputValue, operator)
            this.calculator.displayValue = String(result)
            this.calculator.firstOperand = result
        }
        
        this.calculator.waitingForSecondOperand = true
        this.calculator.operator = nextOperator
    },
    calculate(firstOperand, secondOperand, operator) {
        if (operator === '+') {
            return firstOperand + secondOperand
        } else if (operator === '-') {
            return firstOperand - secondOperand
        } else if (operator === '*') {
            return firstOperand * secondOperand
        } else if (operator === '/') {
            if (secondOperand == 0){
                this.errValue = 'ERROR: Cannot divide by 0'
            }
            else {
                return firstOperand / secondOperand
            }
        }
        
        return secondOperand
    },
    resetCalculator() {
      this.calculator.displayValue = '0'
      this.calculator.firstOperand = null
      this.calculator.waitingForSecondOperand = false
      this.calculator.operator = null
    },
  },
...
```

[Demo](https://codeply.com/v/XhWpdMVUwB) | [Source](https://codeply.com/p/XhWpdMVUwB)

---

As always, you can [play with the latest Bootstrap 5](https://www.codeply.com/p?starter=Bootstrap%205), and find more handy [Vue snippets and examples on Codeply](https://www.codeply.com/tagged/vue)!

Thanks for reading!