Spencer FengSpencer Feng

Attach multiple event handlers to an event in Vue.js

Vue.js is a very powerful JavaScript framework which gained lots of popularity in 2017 and I think it will continue to be used in more and more projects this year, so it really is the time to learn Vue.js. In this tutorial, we will learn how to attach multiple event handlers to an event in Vue.js.

In this tutorial, we will build a simple application which displays the current Bitcoin price and the time when the price is displayed when the user clicks on the ‘Show Current Price’ button. Please note: this is not a real-life application and it will not make API calls to get the Bitcoin price, but just uses hard-coded sample data. You can see how it work in the animated image below:

We will build this application using vue-cli. If you are not familiar with vue-cli, please read the instruction from here. Basically, vue-cli is a simple CLI tool to help you quickly scaffold Vue.js projects with opinionated, battery-included build setups.

Once the project is created with vue-cli, we will remove the existing ‘HelloWord.vue’ component in the ‘src/components’ directory and then create a component called ‘BitcoinPrice’ with the code below:

<template>
  <div>
    <div>
      <strong>Current Bitcoin price is: </strong>{{ pricePool[currentPriceIndex] }} AUD
    </div>
    <div>
      <button @click="getCurrentPrice">Show Current Price</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'BitcoinPrice',
  data () {
    return {
      pricePool: [
        '13676.86',
        '15764.21',
        '19439.80',
        '18905.46',
        '12897.65',
      ],
      currentPriceIndex: 0,
    }
  },
  methods: {
    getCurrentPrice() {
      let requestResultStatusSwitch = Math.floor(Math.random() * 2);

      // succeeded
      if (requestResultStatusSwitch === 1) {
        this.currentPriceIndex++;
        if (this.currentPriceIndex == this.pricePool.length) {
          this.currentPriceIndex = 0;
        }
        this.currentPrice = this.pricePool[this.currentPriceIndex];

        this.$emit('price-request-returned', {
          message: 'The current Bitcoin price has been successfully updated.',
          success: true,
        });
      }

      // failed
      if (requestResultStatusSwitch === 0) {
        this.$emit('price-request-returned', {
          message: 'Sorry, something is wrong. Please try again later.',
          success: false,
        });
      }

    }
  },
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
  font-weight: normal;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>

As you can see, this component contains the template to display the current Bitcoin price as well as the ‘Show Current Price’ button. In this component, we simulate API requests to get the current Bitcoin price. We also simulate the situation where requests might fail. Once the response returns, the application emits a custom event called ‘price-request-returned’ with a JSON object. The JSON object contains 2 keys. One is ‘message’ and the other is ‘success’. The values of these 2 keys in a successful response are different from those in a failed response, so that we can use them to decide what alert type to use later on when displaying the successful message or failed message to the user.

Now let’s open the ‘src/App.vue’ file and replace the existing code with the code below:

<template>
  <div id="app">
    <img id="logo" src="./assets/logo.png">
    <div class="alert" :class="[alertTypeClass]" v-if="alert.visible">
      {{ alert.message }}
    </div>
    <div class="updated-at">Last updated at {{ updatedAt }}</div>
    <BitcoinPrice @price-request-returned="displayAlertMessage($event); updateTime($event)"/>
  </div>
</template>

<script>
import BitcoinPrice from './components/BitcoinPrice'
import * as moment from 'moment'

export default {
  name: 'App',
  data() {
    return {
      alert: {
        message: '',
        type: '',
        visible: false,
      },
      updatedAt: moment().format('DD/MM/YYYY hh:mm:ss'),
    }
  },
  computed: {
    alertTypeClass() {
      return `alert-${this.alert.type}`;
    }
  },
  components: {
    BitcoinPrice
  },
  methods: {
    displayAlertMessage(data) {
      this.alert.message = data.message;
      this.alert.type = data.success ? 'success' : 'danger';
      this.alert.visible = true;
    },
    updateTime(data) {
      if (data.success) {
        this.updatedAt = moment().format('DD/MM/YYYY hh:mm:ss');
      }
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
#logo {
  margin-bottom: 30px;
}
.alert {
  border: 1px solid transparent;
  border-radius: 5px;
  text-align: center;
  padding: 5px 12px;
  margin-bottom: 30px;
}
.alert.alert-success {
  color: #155724;
  background-color: #d4edda;
  border-color: #c3e6cb;
}
.alert.alert-danger {
  color: #721c24;
  background-color: #f8d7da;
  border-color: #f5c6cb;
}
.updated-at {
  font-size: 11px;
  background: #ff9c44;
  color: #ffffff;
  width: 200px;
  text-align: center;
  margin: 10px auto;
  padding: 3px 0;
  border-radius: 3px;
}

</style>

Line 8 shows how we attach 2 event handlers to the custom ‘price-request-returned’ event emitted from the ‘BitcoinPrice’ component. One event handler is responsible for displaying the alert message and the other is responsible for updating the time when a successful request is made. The ‘$event’ argument passed to these 2 event handlers contains the payload of the custom event.

Please note, we also use ‘moment.js’ in the application, so please install it as well.

You can view the source code for thisĀ tutorialĀ on GitHub.

Please sign up to my Newsletter if you want to get notified when new tutorials are available.

×