0

I'm having quite a hard time with VueJS. In one of my components, I retrieved data from the backend in the form of an array of objects. Once I retrieve this data, I loop through it using forEach and add a field in each object.

<template>
    ...
    <div v-if="!waitingForComments && comments.length > 0">
      <div class="comment" v-for="comment in comments" :key="comment.id">
        <p>{{ comment.content }}</p>
        <span>Par <router-link :to="{ name: 'user', params: { id: comment.author_id } }">-- {{ comment.author }}</router-link></span>
      </div>
    </div>
    ...
</template>

<script>
  import { getPost } from "../services/post";
  import { getComments } from "../services/comment";
  import { getUser } from "../services/user";

  export default {
    name: 'Post',
    data() {
      return {
        post: null,
        comments: [],
        postId: null,
        waitingForComments: true
      }
    },
    async created() {
      this.postId = this.$route.params.id;
      this.post = await getPost(this.$route.params.id);

      let allComments = await getComments(this.postId);
      allComments.forEach(async comment => {
        let author = await getUser(comment.author_id);
        comment.author = author.firstname + " " + author.lastname;
      });
      this.comments = allComments;
      this.waitingForComments = false;
    }
  }
</script>

In the <router-link>, "--" shows with no problem, but comment.author doesn't print anything ! Yet Vue's Chrome debugger shows that the author fields do hold values !

I really don't understand where this comes from. I tried using await in front of forEach(), I also tried using a watcher on comments and retrieve the authors inside that watcher. But nothing works.

Any help would be much appreciated !

tomfl
  • 707
  • 1
  • 11
  • 29

3 Answers3

1

A foreach function does not work like a .map function. Map return an array but foreach doesn't.

Copy/paste this for your created function:

async created() {
  this.postId = this.$route.params.id;
  this.post = await getPost(this.$route.params.id);

  let allComments = await getComments(this.postId);

  this.comments = allComments.map(async comment => {
    let author = await getUser(comment.author_id);
    comment.author = author.firstname + " " + author.lastname;

    return comment;
  });

  this.waitingForComments = false;
}

But, this iteration havea problem, to see the result you must let the queries end. So you need to add the following code in the created() function.

this.waitingForComments = true;
const results = await Promise.all(this.comments);
this.waitingForComments = false;

Maybe it doesn't work because I didn't checked it. But please, try this and I hope it will work for you.

  • Yeah it works ! Thanks. But I really don't understand what goes on, especially where you do `this.comments = await ...`. After mapping through the result, isn't the `this.comments` array supposed to be just ONE object ? – tomfl Nov 25 '19 at 10:58
0

I would not not use forEach with async/await: see here I guess that's you pb here : forEach doesn't wait ;)

A good ol' for... of would do the trick.

async created() {
      this.postId = this.$route.params.id;
      this.post = await getPost(this.$route.params.id);

      let allComments = await getComments(this.postId);
      for(let comment of allComments){
        let author = await getUser(comment.author_id);
        comment.author = `${author.firstname} ${author.lastname}`;
      }
      this.comments = allComments;
      this.waitingForComments = false;
    }

Pierre_T
  • 1,094
  • 12
  • 29
-1

use

this.$set(this, "comments", allComments);

instead

this.comments = allComments;