Michel
Michel

Reputation: 167

Vue.js - no access to this.$parent when child component is inside <transition>

What I want: I have two components, the parent component (Wall.vue) and the child component (PostItem.vue). Every PostItem has a delete button. On click, a request to my API is sent and the item gets deleted from the database. Then I want to call the getPosts function of the parent component to get all the posts again (this time without the deleted post).

The Problem: Inside the child component, I have no access to the this.$parent Object (or more specific, it's just empty and doesn't contain the functions), so I can't call the getPosts-Function. When I remove the <transition-group> in the parent component that surrounds also the child-component, everything works fine.

What is the problem here?

Parent-Component (Wall.vue)

template-portion:

<template>
  <div class="Wall view">  
      <transition-group name="wallstate">
        <template v-else-if="messages">
          <PostItem
            v-for="(message, index) in messages"
            :key="index"
            :message="message"
            :index="index"
            class="PostItem"
          />
        </template>
        <h1 v-else>
          Could not load messages. Please try later.
        </h1>
      </transition-group>
  </div>
</template>

script-portion:

<script>
import { mapGetters } from 'vuex';
import { postsAPI } from '../services/posts.service.js';

import PostItem from '../components/PostItem.vue';

export default {
  components: {
    PostItem,
  },

  data() {
    return {
      messages: null,
    };
  },

  methods: {
    getPosts() {
      ///////Do stuff
    }
  }
};
</script>

Child-Component (PostItem.vue)

template-portion

<template>
  <div class="PostItem__message frosted">
    <p class="PostItem__messageContent">{{ message.content }}</p>
    <p>
      by: <strong>{{ message.user.username }}</strong>
    </p>
    <a
      @click="deletePost"
      :data-id="message._id"
      v-if="message.user._id === user.id"
    >
      Delete
    </a>
  </div>
</template>

script-portion:

<script>
import { postsAPI } from '../services/posts.service.js';
import { mapGetters } from 'vuex';

export default {
  name: 'PostItem',

  props: {
    message: {
      type: Object,
      required: true,
    },
    index: {
      type: Number,
      required: true,
    },
  },

  computed: {
    ...mapGetters({
      user: 'auth/user',
    }),
  },

  methods: {
    deletePost(e) {
      const id = e.target.dataset.id;
      postsAPI.removeOne(id).then((res) => {
        this.$parent.getPosts();  <-------- PROBLEM HERE
      });
    },
  },
};
</script>

Upvotes: 4

Views: 4396

Answers (2)

Lizzi
Lizzi

Reputation: 11

inside the methods part, instead of :

methods: {
  deletePost(e) {
    const id = e.target.dataset.id;
    postsAPI.removeOne(id).then((res) => {
      this.$parent.getPosts();  
    });
  },
},

you may try this:

  methods: {
    deletePost(e) {
      const id = e.target.dataset.id;
      let self=this;
      postsAPI.removeOne(id).then((res) => {
        self.$parent.getPosts(); 
    });
  }

Because of the scope chain, 'this' inside .then() does not point to the same variable environment as variable 'self' does. So perhaps it's the reason it fails to work.

Upvotes: 1

Dan
Dan

Reputation: 63119

It's generally considered a bad practice to use this.$parent (it couples the components and reduces encapsulation / code clarity.) The child component should emit an event when it wants to send information to an ancestor component.

Remove the direct access and $emit an event called 'deleted':

deletePost(e) {
  const id = e.target.dataset.id;
  postsAPI.removeOne(id).then((res) => {
    this.$emit('deleted');  // Emitting the event
  });
},

The parent should listen for that deleted event and run an event handler:

<PostItem
  v-for="(message, index) in messages"
  :key="index"
  :message="message"
  :index="index"
  class="PostItem"
  @deleted="getPosts"
/>

The parent will call the getPosts method when triggered by the @deleted event listener.

Upvotes: 4

Related Questions