Skip to content

Infinite repeated while using v-for in vuejs

I have an API to get list of books, in each book I have author ID. I also want to get author name from that ID through another API (get author), so I use v-for to get items in list of book. Each item I call getAuthor(authorId) function but it repeats infinitely. Does anyone know what the reason is? My source code:

export default {  
name: 'GetBooks',  
    data() {
        return {
            books: [],
            categories: [],
            author: [],
        };
    },
    created()  
    {  
        this.getBooks();  
    },  

methods: { 
    getBooks() {  
        BookServices.getBooks().then(response => {  
                this.books = response.data;  
                console.log(response.data);  
            })  
            .catch(e => {  
                console.log(e);  
            });  
    },  
    getAuthor(id) {  
        BookServices.getAuthor(id).then(response => {  
                this.author = response.data.name;
                console.log(response.data.name);  
            });
        return this.author;
    },  
}  

AND:

<tbody>  
    <tr v-for="item in books" :key="item.id">  
        <td>{{ item.id }}</td>  
        <td>{{ item.name }}</td>  
        <td>{{ getAuthor(item.authorId) }}</td>  
        <td>{{ item.price }}</td>  
        <td>{{ item.year }}</td>   
        <td><input class='myclass' type='button' value='Detail'/></td>
    </tr>  
</tbody>  

Answer

The model-fetching methods should decide when and how to fetch authors, not the markup. (this is @IgorMoraru’s good second idea, corrected to properly handle the async fetch of authors).

This also fixes OP code error that assigned the book author to the view instance.

getBooks() {  
    BookServices.getBooks().then(response => {  
            this.books = response.data;  
            console.log(response.data);
            this.getAuthors();  
        })  
        .catch(e => {  
            console.log(e);  
        });  
},
getAuthors() {
  let promises = this.books.map(book => this.getAuthor(book));
  return Promise.all(promises);
},
getAuthor(book) {  // note the change: pass the book here, not the id
    BookServices.getAuthor(book.id).then(response => {  
            book.author = response.data.name;
            console.log(response.data.name);  
        });
    return this.author;
},  

Defend the markup for books that are (temporarily) missing authors…

    <td>{{ item.id }}</td>  
    <td>{{ item.name }}</td>  
    <td v-if="item.author">{{ item.author }}</td>
    <td v-else>fetching...</td>
    <td>{{ item.price }}</td>  
    <td>{{ item.year }}</td>