Emit Custom Events

vue.js logo

Lesson objectives

The App.vue is responsible for showing the EventForm modal:

<EventForm :show="showModal" />

It also contains the event data to render in our app, stored inside the eventData array. Therefore we will also use this file to:

  • Close the modal when the close button is clicked, or the user clicks off the modal area.
  • Update the eventData array with a new event from the form.

We will do this by making use of Vue.js custom events.

Closing the modal

Update the App.vue at the bottom of the script section:

const closeModal = () => {
    showModal.value = false;
    resetForm();
};

const resetForm = () => {
    formData.value = {
        name: "",
        details: "",
        date: "",
        background: "linear-gradient(135deg, #FF416C, #FF4B2B)",
    };
};
  • The closeModal function:
    • hides the modal by setting the showModal value to false.
    • calls a second function called resetForm.
  • The resetForm function clears the values of all the form inputs.

This now leaves a small issue. The function to close the modal is located in the App.vue, and the buttons to call this function are inside the EventForm.vue:

<button class="close-button">&times;</button>

<button type="button" class="cancel-button">Cancel</button>

To solve this, we can use Vue.js custom events.

What are custom events

Custom events in Vue 3 provide a way for child components to communicate with their parent components. When a child component needs to notify its parent that something has happened, like a button click, form submission, or data update, it emits a custom event that the parent can listen for.

An example would be a function in the parent to show/hide visibility of a section, and this function can be called from a child component.

Listening for custom events

This works by a child component emitting an event, and a parent component listening for the event. Since the App.vue renders the EventForm component, this will be the parent > child relationship.

The parent App.vue listens for the custom event as an attribute. Update as follows:

<EventForm :show="showModal" @close="closeModal" />
  • The @close="closeModal" attribute listens for a custom event named close emitted by the EventForm component
  • When the close event is emitted, it will call the closeModal function we just created
  • The @ symbol is Vue's shorthand syntax for v-on:
  • @close is equivalent to writing v-on:close
  • This allows the child component (EventForm) to communicate with the parent component (App.vue) by triggering the parent's function

Defining custom events

Over to the child component which is used to call (emit) the custom event. The Eventform currently defines which props the component should receive using defineProps():

<script setup>
const props = defineProps({
    show: {
        type: Boolean,
        required: true,
    },
});
</script>

In a similar way, we can also define which event the component should emit by using defineEmits():

<script setup>
const props = defineProps({
    show: {
        type: Boolean,
        required: true,
    },
});

// add
const emit = defineEmits(["close"]);
</script>
  • The defineEmits function declares which custom events this component can emit to its parent
  • It takes an array of event names as strings, ["close"] means the component can emit a close event
  • The function returns an emit function that we can use to actually trigger the event
  • This is similar to defineProps - while props define what data flows down from parent to child, defineEmits defines what events flow up from child to parent

Emitting custom events

To actually emit the event, you would call emit("close") when needed.

<template>
  <div v-if="show" class="modal-overlay">
    <div class="modal">
      <div class="modal-header">
        <h2>Add New Event</h2>
          <!-- emit the close event when clicked -->
          <button class="close-button" @click="emit('close')">&times;</button>

Try this out in the browser, the x button should now close the form!

This can also be added to the modal-overlay wrapper to allow the modal to be closed when clicking off the main area:

<div v-if="show" class="modal-overlay" @click="emit('close')">

And also to the cancel button:

<button type="button" class="cancel-button" @click="emit('close')">
    Cancel
</button>

Even though we have added the close event to specific elements, you will notice clicking anywhere on the modal will close it, we will resolve this in the next lesson.

Alternative syntax

Alternatively, emit('close') could also be called from inside a function:

const closeModal = () => {
  emit("close");
};

Triggering the function when the button is clicked:

<button @click="closeModal" class="close-button">&times;</button>

This may be useful if you want to run some additional code before emitting the event.