Search code examples
vue.jsvuejs2vue-componentslotemit

Vue.js - Emit from grandchild slot component didn't bubble $emit event to parent


I planned and made a modal and then created a button to close the modal window. I wanted to change the value of isHomeDialog using $emit as an event of the button.
However, $emit's event was not delivered to "Home.vue"

Home.vue

<template>
  <div>
    <ReviewDialog
      :is-open="isHomeDialog"
      @close="closeEvent()/>
  </div>
</template>

<script>
import ReviewDialog from '@/components/popup/dialog/ReviewDialog';
</script>

export default {
  name: 'Home',
  components: {
    ReviewDialog
  },
  data () {
    return {
      isHomeDialog: true
    };
  },
  methods: {
    closeEvent () {
      console.log('close');
      isHomeDialog = false;
    }
  }
};

BaseDialog.vue

<template>
  <div v-show="isOpen">
    <div class="mask">&nbsp;</div>
    <div class="content">
      <button
        class="close"
        @click="$emit('close')">&nbsp;</button>

      <slot/>

    </div>
  </div>
</template>
<script>
export default {
  props: {
    isOpen: {
      type: Boolean,
      required: true
    }
  }
};

Reviewdialog.vue

<template>
  <BaseDialog
    url="@/components/popup/dialog/BaseDialog"
    id="review-dialog"
    :is-open="isOpen"
    :header-text="'REVIEW'">

    <div class="warp">
      <p>
        test
      </p>
    </div>
  </BaseDialog>
</template>

<script>
import BaseDialog from '@/components/popup/dialog/BaseDialog';

export default {
  components: {
    BaseDialog
  },
  props: {
    isOpen: {
      type: Boolean,
      default: false
    }
  }
</script>

Home
└ BaseDialog
 └ ReviewDialog

In the above structure, I tried to send a request to BaseDialog and ReviewDialog with $emit, but it was not delivered to Home. Is there any way to send $ emit to its parent component other than requesting it with $root.$emit?


Solution

  • BaseDialog emits the close event to its parent, ReviewDialog, which is not listening for it. So you need to listen in ReviewDialog, and re-emit the event to Home:

    <BaseDialog
        url="@/components/popup/dialog/BaseDialog"
        id="review-dialog"
        :is-open="isOpen"
        :header-text="'REVIEW'"
        @close="$emit('close')"> <-- This line is new -->
    

    Another way to do this is to have ReviewDialog pass all its listeners down:

    <BaseDialog
        url="@/components/popup/dialog/BaseDialog"
        id="review-dialog"
        :is-open="isOpen"
        :header-text="'REVIEW'"
        v-on="$listeners"> <-- This line is new -->