最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

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

programmeradmin0浏览0评论

What I want: I have two ponents, the parent ponent (Wall.vue) and the child ponent (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 ponent to get all the posts again (this time without the deleted post).

The Problem: Inside the child ponent, 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 ponent that surrounds also the child-ponent, 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 '../ponents/PostItem.vue';

export default {
  ponents: {
    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,
    },
  },

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

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

What I want: I have two ponents, the parent ponent (Wall.vue) and the child ponent (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 ponent to get all the posts again (this time without the deleted post).

The Problem: Inside the child ponent, 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 ponent that surrounds also the child-ponent, 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 '../ponents/PostItem.vue';

export default {
  ponents: {
    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,
    },
  },

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

  methods: {
    deletePost(e) {
      const id = e.target.dataset.id;
      postsAPI.removeOne(id).then((res) => {
        this.$parent.getPosts();  <-------- PROBLEM HERE
      });
    },
  },
};
</script>
Share Improve this question edited Feb 25, 2021 at 10:50 Dan 63.2k18 gold badges111 silver badges119 bronze badges asked Feb 24, 2021 at 12:06 MichelMichel 1674 silver badges11 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

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

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.

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.

发布评论

评论列表(0)

  1. 暂无评论