cassini
cassini

Reputation: 89

Vue.js event emitted by child component does not reach parent

in my vue.js application i have a component which children inside, which are either of component type "Test" or "AnotherComponent". The user can add one of those components by a button click and it will then be added at the end of the list of child components.

Each of these components should have a delete-button to remove the component from the list shown.

I added such a button to "AnotherComponent" and added an event emitter on click because I wanted to notify the parent component of the event so it will take care of removing the right component from the list. Is this approach correct at all?

This is the child component

<template>
  <div>
    <div class="container">
        <b-card
            title="Card Title"
            class="mb-2"
        >
            <b-card-text>
                This card has some text and it different from the other component.
                Also there is a nice picture.
            </b-card-text>
            <button
                type="button"
                class="btn btn-secondary"
                v-on:click="deleteComponent()"
            >
              x
            </button>
        </b-card>
  </div>
  </div>
</template>

<script>

export default {
  name: 'AnotherComponent',
  data() {
    return {
    };
  },
  methods: {
    deleteComponent(event) {
      this.$emit('delete-component', this.$vnode.key);
    },
  },
};
</script>

This is the parent component:

<template>
  <div>
    <div class="container">
      <h1> This is my first layout page </h1>
      <alert :message=alertText></alert>
      <button
        type="button"
        class="btn btn-primary"
        v-on:click="addComponent('test')"
      >
        add component 1
      </button>
      <button
        type="button"
        class="btn btn-primary"
        v-on:click="addComponent('another')"
      >
        add component 2
      </button>
      <div class="row">
        <template
          v-for="block in content.body">
            <div class="col-3" v-bind:key="`col-${block._uid}`">
              <component
                :is="block.component"
                :block="block"
                :key="block._uid"
                v-on:delete-component="onDeleteChildComponent($event)">
              </component>
            </div>
        </template>
      </div>
  </div>
  </div>
</template>

<script>
/* eslint-disable vue/no-unused-components */
import axios from 'axios';

import TestComponent from './TestComponent.vue';
import AnotherComponent from './AnotherComponent.vue';
import Alert from './Alert.vue';

export default {
  name: 'FirstPage',
  data() {
    return {
      alertText: 'this is a test!',
      content: {
        body: [], /* holds the array of objects that are components */
      },
    };
  },
  components: {
    alert: Alert,
    test: TestComponent,
    another: AnotherComponent,
    // AnotherComponent,
  },
  methods: {
    getComponents() {
      const path = 'http://localhost:8080/components';
      axios.get(path)
        .then((res) => {
          console.log('res.data');
          this.content.body = res.data.components;
        })
        .catch((error) => {
          // eslint-disable-next-line
          console.error(error);
        });
    },
    addComponent(componentType) {
      const path = 'http://localhost:8080/components';
      const payload = {
        component: componentType,
        headline: 'Bar',
      };
      axios.post(path, payload)
        .then(() => {
          this.getComponents();
          this.message = 'Component added!';
        })
        .catch((error) => {
          // eslint-disable-next-line
          console.log(error);
          this.getComponents();
        });
    },
  },
  onDeleteChildComponent(id) {
    console.log('delete child');
    console.log(id);
  },
  created() {
    console.log('fetching components from backend');
    this.getComponents();
  },
};
</script>

Unfortunately in the parent component this event from th child does not get triggered at all. I am just starting with vue.js, so what am I doing wrong here? Thanks in advance!

Upvotes: 0

Views: 3569

Answers (1)

Excalibaard
Excalibaard

Reputation: 2073

You're emitting 'deleteComponent' and listening to 'delete-component'. This conversion doesn't work with event registrations, only for converting component names.

https://v2.vuejs.org/v2/guide/components-custom-events.html

Try this instead:

// child component

methods: {
    deleteComponent(event) {
      this.$emit('delete-component', this.$vnode.key);
    },
  },

EDIT: As Eldar correctly pointed out in the comments, your listener is also listening at the wrong element. Move the listener to your dynamic component like so:

// parent component

<!-- template tags not necessary unless you're trying to render more than 1 root node per v-for element -->

            <div class="col-3" v-for="block in content.body" :key="`col-${block._uid}`">
              <component
                @delete-component="onDeleteChildComponent($event)"
                :is="block.component"
                :block="block"
                :key="block._uid">
              </component>
            </div>

EDIT 2: The method you're trying to listen to is not listed in your methods, but it's one level too high. Keep track of your brackets! ;)

methods: {
    getComponents() {
      ...
    },
    addComponent(componentType) {
      ...
    },
  },
  onDeleteChildComponent(id) {
    console.log('delete child');
    console.log(id);
  },

should be:

methods: {
    getComponents() {
      ...
    },
    addComponent(componentType) {
      ...
    },
    onDeleteChildComponent(id) {
      console.log('delete child');
      console.log(id);
    },
  },

Upvotes: 1

Related Questions