skip to Main Content

I have a function to add a comment to a post. Now when you add a new comment to a blog the page needs to reload so that you can see the new added blog.

I now use location.reload() but this refreshes the whole page which I don’t want to happen. How can I make it so that I only refresh the post?

I found this.$forceUpdate() but this won’t reload the component at all.

Here are the files I use and how I do it right now, I removed the unnecessary code for If youre wondering why somethings are missing.

my container view:

<template>
    <main>
        <div class="container">
            <MainContainerItem v-for="blog in blogs" :blog="blog"/>
        </div>
        
    </main>
</template>

<script setup>
import MainContainerItem from './MainContainerItem.vue';
import axios from 'axios'
</script>


<script>
export default {
    name: "MainContainer",
    data(){
        return {
            'blogs': null,
        }
    },
    methods: {
        getAllBlogs(){
            axios.get('/api/blog')
                .then((response) => {
                    this.blogs = response.data.blogs
                    console.log(this.blogs)
                })
                .catch((error) => {
                    console.warn(error)
                })
        },
    },
    mounted(){
        this.getAllBlogs()
    }
}
</script>

my other view:

<template>
        <div class="blog__comments">  
                <div class="blog__comments__existingComment">   
                    <div v-if="blog.comment !== null">
                        <div v-for="comments in blog.comments">
                            <span class="blog__comments blog__comments__existingComment--text">{{comments.comment}}</span>
                        </div>
                    </div>
                </div>

            <div class="blog__comments__add">
                <img class="blog__comments blog__comments--profilePicture" :src="defaultProfilePicture">
                <input class="blog__comments blog__comments--text" type="text" v-model="comment" placeholder="Write comment...">
                <button @click="addComment()">Add comment</button>
            </div>
        </div>
    </div>
</template>


<script>
    import axios from 'axios'
    export default {
        name: "MainContainerItem",
        methods: {
            /* add a comment to a blog */
            addComment() {
                axios.post('/api/blog/posts/' + this.posts_id + '/comment', {
                    'comment': this.comment,
                    'user_id': this.user_id,
                    'posts_id': this.posts_id
                })
                 /* reload the page */
                 .then((response) =>  {  
                    console.log(response)
                    /* my attempt with this.$forceUpdate() */
                    /* this.$forceUpdate(); */

                    /* with location.reload() how I have it now*/
                    location.reload();
                    this.blog.id = response.data.id 
                })
                .catch(function (error) {  
                    console.log(error);
                });
            },

        }
    }
</script>

my function to get the posts + comments:

public function getAllBlogs() : JsonResponse
    {
        return response()->json([
            'blogs' => 
            Posts::with(['comments' => function ($query) {
                $query->with('user');
            }])
            ->get()
        ]);
    }

3

Answers


  1. The trick is to not reload anything yourself, but update the data and have Vue figure it out through reactivity.

    I think in your case, you can just add the new comment to the blog:

    addComment() {
      axios.post('/api/blog/posts/' + this.posts_id + '/comment', {...})
        .then((response) => {
          this.blog.comments.push({comment: this.comment})
        })
        ...
    },      
    

    It is usually good practice to have your service return the comment data after saving, so you get the same data you would get when loading it (i.e. with IDs and other data added on server side). Then you can do something like:

    async addComment() {
      const url = '/api/blog/posts/' + this.posts_id + '/comment'
      const response = await axios.post(url, {...})
      this.blog.comments.push({comment: response.data})
    },      
    

    Alternatively, you could emit the created value to the parent component that manages the data or put it all into a store.

    Does that make sense? Does it work for you?

    Login or Signup to reply.
  2. Do you really need to reload this page? Maybe you should just push newly added comment to this comments array you are iterating through?

    You can’t modify props, so you should first move data from prop to data variable in mounted hook. Here is how MainContainerItem should look like:

    <template>
        <div class="blog__comments">  
            <div class="blog__comments__existingComment">   
              <div v-if="blog.comment !== null">
                <div v-for="comment in comments">
                  <span class="blog__comments blog__comments__existingComment--text">{{comment.comment}}</span>
                </div>
              </div>
            </div>
    
          <div class="blog__comments__add">
            <img class="blog__comments blog__comments--profilePicture" :src="defaultProfilePicture">
            <input class="blog__comments blog__comments--text" type="text" v-model="comment" placeholder="Write comment...">
            <button @click="addComment()">Add comment</button>
          </div>
        </div>
    </template>
    
    
    <script>
      import axios from 'axios'
      export default {
        name: "MainContainerItem",
        data () {
          return {
            comments: []
          }
        },
        methods: {
          /* add a comment to a blog */
          addComment() {
            const newCommentData = {
              'comment': this.comment,
              'user_id': this.user_id,
              'posts_id': this.posts_id
            };
            axios.post('/api/blog/posts/' + this.posts_id + '/comment', newCommentData)
             .then((response) =>  {  
              this.comments.push(newCommentData)
              this.blog.id = response.data.id 
            })
            .catch(function (error) {  
              console.log(error);
            });
          },
    
        },
        mounted () {
          this.comments = this.blog.comments
        }
      }
    </script>
    
    Login or Signup to reply.
  3. You just need to change location.reload() to this.$emit("refresh").

    Then, change this code to:

    <MainContainerItem v-for="blog in blogs" :blog="blog" @refresh="getAllBlogs"/>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search