Search code examples
javascriptvue.jsvuejs2v-for

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>  

Solution

  • 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>