Reputation: 105
I have 3 components, one that display a comment, one that display a list of comments and one that manage what should be displayed.
When a user click on a comment, the Comment component emit an "comment-selected" event and the CommentsList component listen to it to forward it (by doing an $emit too) to the CommentsView component.
So basically I have to pass an event from a component to is grand parent.
The communication between Comment and CommentsList is working and I can see in the Vue dev tools that the second $emit inside CommentsList is working too, but the listener on CommentsView is never triggered.
However, if I do the same $emit in CommentsList but somewhere else, like in mounted() instead of the "comment-selected" event listener, it works.
Here are the components :
<template>
<div>
<ul class="comments-list list-unstyled">
<li class="comments-list-item" v-for="comment in comments" :key="comment.id">
<app-comment :comment="comment" :post-id="postId" @comment-selected="comment => onSelect(comment)" />
</li>
</ul>
</div>
</template>
<script lang="ts">
import AppComment from './Comment.vue';
import { Component, Vue, Prop } from 'vue-property-decorator';
import { Comment } from '@/models/comment';
@Component({
name: 'comments-list',
components: {
AppComment,
},
})
export default class CommentsList extends Vue {
@Prop({ type: String, required: true }) private readonly type!: string;
@Prop({ type: Number, required: true }) private readonly postId!: number;
@Prop({ type: Array as () => Comment[], required: true }) private readonly comments!: Comment[];
private onSelect(comment: Comment) {
// This function is called and the event is emitted in the Vue dev tools
this.$emit('comment-selected', comment);
}
}
</script>
<template>
<div class="comments-view-shape">
<app-comments-list :type="type" :post-id="postId" :comments="comments" @comment-selected="comment => onSelect(comment)" />
</div>
</template>
<script lang="ts">
import AppCommentsList from './CommentsList.vue';
import { Component, Vue, Prop } from 'vue-property-decorator';
import { Comment } from '@/models/comment';
@Component({
name: 'comments-view',
components: {
AppCommentsList,
},
})
export default class CommentsView extends Vue {
@Prop({ type: String, required: true }) private readonly type!: string;
@Prop({ type: Number, required: true }) private readonly postId!: number;
@Prop({ type: Array as () => Comment[], required: true }) private readonly comments!: Comment[];
private onSelect(comment: Comment) {
// This function is never called but if I do an $emit in CommentsList, outside the v-on callback (like in mounted), it works
console.log(comment);
}
}
</script>
Why this isn't working ?
Upvotes: 2
Views: 1397
Reputation: 105
Ok I found the problem and it has nothing to do with the event system, it was an error in my code and it was in the Comment component.
CommentsList is recursive and a comment in the list can have a CommentsList component inside him to display all the answers of the comment. I was doing my tests on the sub-level CommentsList (the one that display answers), which just doesn't have the event listener.
To summerize, here is what I had :
<template>
<div :id="`comment-${comment.id}`" class="comment">
<div class="comment-shape">
<div class="comment-data">
<div class="comment-content" v-html="comment.content"></div>
<app-comments-list
type="post" :post-id="postId"
:comments="comment.childs"
v-if="hasChilds" />
</div>
</div>
</div>
</template>
And I just had to add a listener to this CommentsList too :
<template>
<div :id="`comment-${comment.id}`" class="comment">
<div class="comment-shape">
<div class="comment-data">
<div class="comment-content" v-html="comment.content"></div>
<app-comments-list
type="post" :post-id="postId"
:comments="comment.childs"
v-if="hasChilds"
@comment-selected="comment => onSelect(comment)" />
</div>
</div>
</div>
</template>
Which makes me wonder if there is no better way to do this, but that's another topic.
Upvotes: 1