Categories
Vue 3

Vue 3 — Component Events

Spread the love

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to listen to component events.

Listening to Child Components Events

We can listen to child components within the parent component.

Our child component has to emit the event so that the parent component can listen to it.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div :style="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="fontSize++"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        }
      }); 
      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text')">
              Enlarge text
            </button>
        </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We created a todo-item component with an ‘enlarge text’ button.

When we click it, the $emit function is run.

The argument is the event name.

Then in the parent component that holds the todo-item component, we have the @enlarge-text directive so that we can listen to the enlarge-text event that’s emitted from todo-item .

When that event is received, when we increase fontSize by 1.

Since we set fontSize as the font size of our div, then font size change will be applied across all the child elements.

Emitting a Value With an Event

The $emit function takes a second argument with the value we want to emit with the event.

Therefore, we can modify our code to pass the value into the $emit function.

Then we get the value emitted from the $event object.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div :style="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="fontSize += $event"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        }
      }); 

      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text', 1)">
              Enlarge text
            </button>
          </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

$emit takes a second argument that we emit with the enlarge-text event.

Now in the parent component, we get the value emitted with the $event variable.

In this case, $event is set to 1 since that’s what we emitted.

We changed the @enlarge-text ‘s value so that the fontSize updates from the $event instead of a constant value.

Also, we can put the expression we passed into @enlarge-text into a method.

This is handy if we have more code.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="[https://unpkg.com/vue@next](https://unpkg.com/vue@next)"></script>
  </head>
  <body>
    <div id="app">
      <div :style="{ 'font-size': `${fontSize}px` }">
        <todo-item
          @enlarge-text="onEnlargeText"
          v-for="t of todos"
          :todo="t"
          :key="t.id"
        ></todo-item>
      </div>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            fontSize: 15,
            todos: [
              { id: 1, name: "eat" },
              { id: 2, name: "drink" },
              { id: 3, name: "sleep" }
            ]
          };
        },
        methods: {
          onEnlargeText(amount) {
            this.fontSize += amount;
          }
        }
      }); 

      app.component("todo-item", {
        props: ["todo"],
        template: `
          <div>
            <p>{{ todo.name }}</p>
            <button @click="$emit('enlarge-text', 1)">
              Enlarge text
            </button>
        </div>
        `
      }); 
      app.mount("#app");
    </script>
  </body>
</html>

We changed @enlarge-text ‘s value to our onEnlargeText method.

amount would be automatically set to the $event variable’s value, which is 1.

So we get the same result.

Conclusion

We can listen to the child component’s events from the parent.

This way, we can pass data from child to parent.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *