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.