Reputation: 89
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
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