Setting up a Vue 3 parent component to emit events to a child component: a step-by-step guide

Seeking assistance with setting up a Vue 3 Tailwind parent component button to trigger a HeadlessUI transition event in a child component. The objective is for the button in the parent to emit an event, which the child will then watch for before triggering the transition event within a callback function. Currently, the parent component triggers the emit, but the child component fails to execute the event. It seems that the watch in the child component may not be set up correctly to monitor the button click in the parent. How can I enable the child component to detect the button click in the parent?

Current code:

Parent:

<!-- This example requires Tailwind CSS v2.0+ -->
<template>
  <div class="min-h-full">
    <Disclosure as="nav" class="bg-gray-800">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex items-center justify-between h-16">
          <div class="flex items-center">
            <div class="hidden md:block">
              <div class="ml-10 flex items-baseline space-x-4">
                <button type="button" @click="transition" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Click to transition</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Disclosure>

    <main>
      <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
        <div class="px-4 py-6 sm:px-0">
          <HelloWorld :event="transition" />
        </div>
      </div>
    </main>
  </div>
</template>

<script setup>
import { Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
import { BellIcon, MenuIcon, XIcon } from '@heroicons/vue/outline'
import HelloWorld from './components/HelloWorld.vue'
</script>

Child:

<template>
  <div class="flex flex-col items-center py-16">
    <div class="w-96 h-96">
      <TransitionRoot
        appear
        :show="isShowing"
        as="template"
        enter="transform transition duration-[400ms]"
        enter-from="opacity-0 rotate-[-120deg] scale-50"
        enter-to="opacity-100 rotate-0 scale-100"
        leave="transform duration-200 transition ease-in-out"
        leave-from="opacity-100 rotate-0 scale-100 "
        leave-to="opacity-0 scale-95 "
      >
        <div class="w-full h-full bg-gray-400 rounded-md shadow-lg" />
      </TransitionRoot>
    </div>
  </div>
</template>

<script setup>
import { ref, toRefs, defineProps, watch } from 'vue'
import { TransitionRoot } from '@headlessui/vue'

const props = defineProps({
  transition: Function
})
const { transition } = toRefs(props)
const isShowing = ref(true)

watch(transition, () => {
  isShowing.value = false

  setTimeout(() => {
    isShowing.value = true
  }, 500)
})
</script>

Answer №1

the upward movement of events paired with the downward shift of state is essential.

Ensure that your child component is actively monitoring a property, allowing the button in the parent to manipulate the state of said property.

update:

const { transition } = toRefs(props)

It's worth noting that reactivity could be compromised in this scenario.

for more information, visit:

update2:

Your current implementation should function properly, though directly referencing the prop is also acceptable: https://codesandbox.io/s/relaxed-sea-y95x6c?file=/src/App.vue

Answer №2

Revised in light of Sombriks' input, here is the solution:

Parent Component:

<!-- This snippet relies on Tailwind CSS version 2.0 or later -->
<template>
  <div class="min-h-full">
    <Disclosure as="nav" class="bg-gray-800">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="flex items-center justify-between h-16">
          <div class="flex items-center">
            <div class="hidden md:block">
              <div class="ml-10 flex items-baseline space-x-4">
                <button type="button" @click="transition" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Click to transition</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Disclosure>

    <main>
      <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
        <div class="px-4 py-6 sm:px-0">
          <HelloWorld :show="show" />
        </div>
      </div>
    </main>
  </div>
</template>

<script setup>
import { Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue'
import { BellIcon, MenuIcon, XIcon } from '@heroicons/vue/outline'
import { ref } from 'vue'
import HelloWorld from './components/HelloWorld.vue'

const show = ref(true)

const transition = () => {
  show.value = !show.value
}

</script>

Child Component:

<template>
  <div class="flex flex-col items-center py-16">
    <div class="w-96 h-96">
      <TransitionRoot
        appear
        :show="isShowing"
        as="template"
        enter="transform transition duration-[400ms]"
        enter-from="opacity-0 rotate-[-120deg] scale-50"
        enter-to="opacity-100 rotate-0 scale-100"
        leave="transform duration-200 transition ease-in-out"
        leave-from="opacity-100 rotate-0 scale-100 "
        leave-to="opacity-0 scale-95 "
      >
        <div class="w-full h-full bg-gray-400 rounded-md shadow-lg" />
      </TransitionRoot>
    </div>
  </div>
</template>

<script setup>
import { ref, toRefs, watch } from 'vue'
import { TransitionRoot } from '@headlessui/vue'

const props = defineProps({
  show: Boolean
})
const { show } = toRefs(props)
const isShowing = ref(true)

watch(show, () => {
  isShowing.value = false

  setTimeout(() => {
    isShowing.value = true
  }, 500)
})
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Nested routes are arranged in the depths and a variety of components appear depending on the path of the

I've encountered a situation where I have deeply nested routes in my routes.js file. The code snippet below shows that depending on the route, I need to render different components. For instance, if the route is for products, I should render the Produ ...

Ways to access an array's value using a variable in jade

Having trouble understanding why a variable cannot be used to call a value in an array using JS/Jade. This issue arises within a script on a .jade file. The array contains around 400 entries, and one of them is shown below: myFood[10]['Cake'] = ...

Aligning elements vertically with Vue.js, Bootstrap-Vue, and the <b-table> component

Dear all, I need some help with vertically aligning elements in my b-table within my Vue/Bootstrap project. This is my code: <template> <b-table small :fields="fields" :items="items" responsive="sm"> ...

Unexpected error encountered in Angular 2 beta: IE 10 displays 'Potentially unhandled rejection [3] SyntaxError: Expected'

Question regarding Angular 2 Beta: I am starting off with a general overview in the hopes that this issue is already recognized, and I simply overlooked something during my research. Initially, when Angular 2 Beta.0 was released, I managed to run a basic m ...

Utilizing Javascript's Mapping Functionality on Arrays

Here is an array that I need help with: var gdpData = {"CA": 1,"US": 2,"BF": 3,"DE": 4}; I am trying to retrieve the value associated with BF using a loop Can anyone provide guidance on how to accomplish this using either JQuery or Javascript? ...

Can you suggest a simple method for implementing the "componentDidUpdate()" lifecycle method using just JavaScript?

I've been curious about replicating the componentDidUpdate() lifecycle method in JavaScript on my own. It got me thinking, how did React and Vue.JS create their own lifecycle methods? I attempted to study the minified version of Vue.JS but found it qu ...

Tips for retrieving the return value from a function with an error handling callback

I am having an issue with my function that is supposed to return data or throw an error from a JSON web token custom function. The problem I am facing is that the data returned from the signer part of the function is not being assigned to the token const a ...

Having trouble sending a POST request from my React frontend to the Node.js backend

My node.js portfolio page features a simple contact form that sends emails using the Sendgrid API. The details for the API request are stored in sendgridObj, which is then sent to my server at server.js via a POST request when the contact form is submitted ...

After being awaited recursively, the resolved promise does not perform any actions

When working with the Twitter API, I need to make recursive method calls to retrieve tweets since each request only returns a maximum of 100 tweets. The process is straightforward: Call the function and await it Make an HTTP request and await that If the ...

Is there a method in Vuejs to choose a tab and update components simultaneously?

Currently facing an issue where selecting a tab does not refresh the input field in another component, causing data persistence. The data is stored in vuex, so I'm looking for a solution to refresh the component for usability. Appreciate any assistanc ...

What is the best way to retrieve data from the next page in a Protractor test?

I am currently in the process of automating the test for booking a flight. When I enter the credentials on the homepage, click the Submit button, and the browser navigates to the search results page. const EC = protractor.ExpectedConditions; describe( ...

WebStorm displaying 'Unresolved filter' error while using Vue

Regardless of the filter I apply in my Vue templates, they are highlighted in green with the error message "Unresolved filter." What is the solution to this issue? Should I report it to WebStorm or is there a way to fix it myself? My filters are specified ...

How to Remove a Dynamically Generated Popover in Angular

As a newcomer to angular, I successfully implemented a bootstrap popover around selected text using the following function: $scope.highlight = function () { var a = document.createElement("a"); a.setAttribute('tabindex', "0"); ...

The JSON on the Express page only appears after refreshing the page

When accessing my page at /id, the data pulled from an external API using Express does not display until the page is refreshed. Any suggestions on how to solve this issue? // Retrieves basic account data router.get('/:id', function(req, res, nex ...

Should we make it a routine to include shared sass variables in each vue component for better practice?

Within my Vue application, there are numerous components that rely on shared variables like colors. I'm considering having each component import a global "variables.scss" file. Would this approach have any adverse effects? ...

Add various inputs to a table using JavaScript

I came across a situation where I needed to append lines into a table in a specific way. However, I encountered an issue with JavaScript not accepting any input type='text' for an unknown reason. When I used a normal text variable, it worked fine ...

Troubleshooting code: JavaScript not functioning properly with CSS

I am attempting to create a vertical header using JavaScript, CSS, and HTML. However, I am facing an issue with the header height not dynamically adjusting. I believe there might be an error in how I am calling JSS. Code : <style> table, tr, td, t ...

Resizing the background while scrolling on a mobile web browser

My website background looks great on desktop, but on mobile (using Chrome) the background starts to resize when I scroll, mainly due to the browser search bar hiding and reappearing upon scroll. Is there a way to prevent my background from resizing? Check ...

Storing Firestore Timestamp as a Map in the database

Snippet Below const start = new Date(this.date + 'T' + this.time); console.log(start); // Thu Sep 12 2019 04:00:00 GMT+0200 const tournament:Tournament = { start: firebase.firestore.Timestamp.fromDate(start) } When passing the tournament ...

Is there a way to extract information from an HttpClient Rest Api through interpolation?

I am currently facing an issue with a component in my project. The component is responsible for fetching data from a REST API using the HttpClient, and the data retrieval seems to be working fine as I can see the data being logged in the Console. However, ...