Search code examples
javascriptvue.jsself-updating

Get Vue to update view/component


I'm stuck at a crossroads with a component I am working on.

I have the following component "RecentUpdates"

Within it I am passing props down to a few other components, as you can see from the top of the file.

My problem is when adding a new post, I can not figure out how to get the correct update object array back and i also can not figure out the correct 'Vue way' to update the data prop that is being passed down to the "PostList" component.

<template>
  <div>
    <PostFilter v-on:selectedCategory="getSelectedPosts" v-on:showAllPosts="showAllPosts" :user="user" :categories="categories"/>

    <PostList v-if="recent_posts[0]" :categories="categories" :posts="recent_posts[0]" :user="user"/>

    <Pagination v-on:getPreviousPage="getPreviousPage" v-on:getNextPage="getNextPage"/>
  </div>
</template>

<script>

import PostList from './PostList';
import PostFilter from './PostFilter';
import Pagination from './Pagination';
import EventBus from '../event-bus';


export default {

  name: 'RecentUpdates',

  data: () => ({
    errors: [],
    recent_posts: [],
  }),

  props: ['categories', 'user'],

  components: {
    PostList,
    PostFilter,
    Pagination
  },

  created() {

    if (this.user.meta.selected_categories[0] == 0) {
      this.showAllPosts();
    }

    // do not call here, not working as expected
    // is switching selected category to an incorrect one
    // this.updateList();

    this.getSelectedCategory();
  },

  watch: {
    recent_posts: function(newValue) {

      EventBus.$on('addPost', function(newPost) {
        console.log(newPost);

        this.$forceUpdate();


        //this.recent_posts.push(newPost);

        //this.$set(this.recent_posts, newPost, newPost);

        // this.$nextTick(function () {
        //   this.recent_posts.push(newPost);
        // });


      });

        console.log(this.recent_posts[0]);


      // this.$nextTick(function () {
      //   console.log(this.recent_posts[0]) // => 'updated'
      // });

      // if (this.user.meta.selected_categories[0] == 0) {
      //   EventBus.$on('addPost', this.showAllPosts);
      // } else {
      //   EventBus.$on('addPost', this.getSelectedCategory);
      // }
      //this.updateList();
    }
  },

  methods: {

    // updateList() {

    //   if (this.user.meta.selected_categories[0] == 0) {
    //     EventBus.$on('addPost', this.showAllPosts);
    //     //EventBus.$emit('newPost');

    //   } else {
    //     EventBus.$on('addPost', this.getSelectedCategory);
    //     //EventBus.$emit('newPost');
    //   }

    // },

    getSelectedCategory() {

      let categoryId = this.user.meta.selected_categories[0];

      this.getSelectedPosts(categoryId);
    },

    showAllPosts() {

      axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]', 
        {headers: {'X-WP-Nonce': portal.nonce}})
      .then(response => {
        this.recent_posts = [];
        //this.recent_posts = response.data;
        //console.log(response.data);
        this.recent_posts.push(response.data);
        console.log(this.recent_posts[0]);

      })
      .catch(e => {
        this.errors.push(e);
      });
    },

    getSelectedPosts(categoryId) {

      axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId,
        {headers: {'X-WP-Nonce': portal.nonce}})
      .then(response => {
        this.recent_posts = [];
        //console.log(response.data);

        this.recent_posts.push(response.data);

        console.log(this.recent_posts[0]);


      })
      .catch(e => {
        this.errors.push(e);
      });
    },

    /**
     * Pagination methods
     *
     */
    getPreviousPage(page) {
      axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page, 
        {headers: {'X-WP-Nonce': portal.nonce}})
      .then(response => {
        this.recent_posts = response.data;
      })
      .catch(e => {
        this.errors.push(e);
      });
    },

    getNextPage(page) {
      axios.get('/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&page=' + page, 
        {headers: {'X-WP-Nonce': portal.nonce}})
      .then(response => {
        this.recent_posts = response.data;
      })
      .catch(e => {
        this.errors.push(e);
      });
    }
  },
}

</script>

<style>

</style>

Solution

  • So there are a number of issues I see reading through your code.

    1. You have a recent_posts data property, which is an array. When you make your ajax call to get the posts you push the response which is also an array into the recent_posts array. Why? Why not just set recent_posts = response.data? Then you won't have to be passing recent_posts[0] around.
    2. You're setting up your EventBus handler inside a watcher. This is really unusual. Typically you would set up a handler inside created or mounted.
    3. this inside the EventBus handler likely refers to the EventBus and not your Vue. Ideally, you would set the handler to be a method on the component, which is already bound to the Vue. Something like EventBus.$on("addPost", this.addPost).
    4. Once you've done all that, adding a new post should be as simple as this.recent_posts.push(newPost).

    Here is what I might recommend.

    export default {
      name: 'RecentUpdates',
      data(){
        return {
          errors: [],
          recent_posts: []
        }
      },
      props: ['categories', 'user'],
      components: {
        PostList,
        PostFilter,
        Pagination
      },
      created() {
        if (this.user.meta.selected_categories[0] == 0) {
          this.showAllPosts();
        }
        this.getSelectedCategory();
    
        EventBus.$on("addPost", this.addPost)
      },
      beforeDestroy(){
        EventBus.$off("addPost", this.addPost)
      },
      methods: {
        getPosts(url){
          axios.get(url, {headers: {'X-WP-Nonce': portal.nonce}})
            .then(response => this.recent_posts = response.data)
            .catch(e => this.errors.push(e))
        },
        showAllPosts() {
          const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]';
          this.getPosts(url);
        },
        getSelectedPosts(categoryId) {
          const url = '/wp-json/wp/v2/posts?_embed=true&status=[publish,resolved,unresolved]&categories=' + categoryId;
          this.getPosts(url);     
        },     
        addPost(newPost){
          this.recent_posts.push(newPost)
        },
        ... //other methods
      },
    }