Categories
JavaScript Vue

Event Handling in Vue.js Components

Spread the love

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to handle events in Vue components, including how to use v-model with custom components and passing data between parent and child.

Listening to Child Components Events

We can send events from a child component to the parent to run code in the parent component.

For example, if we want to add a button to each post to change the font of the page, we can do that as follows:

src/index.js :

Vue.component("post", {  
  props: ["post"],  
  template: `  
    <div>  
      <h2>{{post.title}}</h2>  
      <div>{{post.content}}</div>  
      <button v-on:click="$emit('change-font')">  
        Change Font  
      </button>  
    </div>  
  `  
});

new Vue({  
  el: "#app",  
  data: {  
    posts: [{ title: "Foo", content: "foo" }, { title: "Bar", content: "bar" }],  
    font: ""  
  },  
  methods: {  
    changeFont() {  
      this.font = this.font === "" ? "courier" : "";  
    }  
  }  
});

We added the changeFont method to let us change the font in the Vue app. This will be called when the change-font event is emitted from the post component.

The change-font event is emitted from post when the Change Font button is clicked.

The event is emitted with the $emit method. The string we passed in is the name of the event.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div v-bind:style="{'font-family': font}">  
        <post  
          v-for="post in posts"  
          v-bind:post="post"  
          v-on:change-font="changeFont"  
        ></post>  
      </div>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the template, we have the v-bind:style attribute to set the font of the div dynamically with v-bind:style=”{‘font-family’: font}”.

When the change-font event is received, then the changeFont method will be called to toggle the font between Courier and the default.

The $emit method also takes a second argument with the value that we want to send back to the parent.

For example, we can rewrite the font change code as follows:

src/index.js :

Vue.component("post", {  
  props: ["post"],  
  template: `  
    <div>  
      <h2>{{post.title}}</h2>  
      <div>{{post.content}}</div>  
      <button v-on:click="$emit('change-font', 'courier')">  
        Change Font  
      </button>  
    </div>  
  `  
});

new Vue({  
  el: "#app",  
  data: {  
    posts: [{ title: "Foo", content: "foo" }, { title: "Bar", content: "bar" }],  
    font: ""  
  },  
  methods: {  
    changeFont(font) {  
      this.font = this.font === font ? "" : font;  
    }  
  }  
});

In the code above, we passed in 'courier' to the $emit function. The item in the second argument will be available as the $event in the parent component.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <div v-bind:style="{'font-family': font}">  
        <post  
          v-for="post in posts"  
          v-bind:post="post"  
          v-on:change-font="changeFont($event)"  
        ></post>  
      </div>  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the template, we pass in $template , which contains 'courier' to the changeFont method.

The changeFont method toggles the font between the font that we passed in as the argument and an empty string.

So it does the same thing as before.

This lets us pass data from a child component to a parent component.

Using v-model on Components

v-model is the same as the v-bind:value and v-on:input together. This means that:

<input v-model="text">

is the same as:

<input v-bind:value="text" v-on:input="text= $event.target.value" >

Since components take props and emit events, we can combine the value propr and the input event binding into the v-model directive.

For example, we can use it to make our own custom input as follows:

src/index.js :

Vue.component("styled-input", {  
  props: ["value"],  
  template: `  
    <input  
      v-bind:style="{'font-family':'courier'}"  
      v-bind:value="value"  
      v-on:input="$emit('input', $event.target.value)"  
    >  
  `  
});

new Vue({  
  el: "#app",  
  data: {  
    text: ""  
  }  
});

In the code above, we created the style-input component to change the font of the input to Courier.

Also, we use v-bind:value to get the value of the value prop and emit the input event as the text is inputted into the input box.

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <styled-input v-model="text"></styled-input>  
      <br />  
      {{text}}  
    </div> <script src="src/index.js"></script>  
  </body>  
</html>

In the code above, we can use v-model to bind to the text data field since v-model is the same as combining v-bind:value with v-on:input .

styled-input emitted the input event and takes the value prop, so we can merge them together into v-model .

Conclusion

We can emit events with the $emit from a child component to the parent. It takes 2 arguments. The first argument is the string for the event name, and the second argument is the object that we want to pass to the parent.

The parent can access the object passed from the child by listening to the event with the v-on directive and then retrieve them item pass from the child with the $event object.

v-bind:value and v-on:input is the same as v-model , so v-bind:value and v-on:input can be combined into one and v-model can be used with custom components.

This lets us create custom inputs easily.

Leave a Reply

Your email address will not be published.

If you like the content of this blog, subscribe to my email list to get exclusive articles not available to anyone else.