I have been working on a news app, using Vue 3 and the News API. I am currently working on a "load more (articles)" functionality.
The initial number of articles is 24 and, if the total number of articles is greater then the current number of articles, there is a button with the text "Load more articles" at the bottom of the page.
In srccomponentsArticleList.vue
I have:
<template>
<div v-if="articles && articles.length" class="row">
<div
v-for="article in articles"
:key="article._id"
class="col-xs-12 col-sm-6 col-lg-4 col-xl-3"
>
<ArticleCard :article="article" />
</div>
<div v-show="isMore" class="mb-3 text-center">
<LoadMoreButton @load-more="loadMore" text="Load more articles" />
</div>
</div>
<p v-if="totalResults == 0" class="text-center">No articles to display</p>
</template>
<script>
import ArticleCard from "./ArticleCard.vue";
import LoadMoreButton from "./LoadMoreButton.vue";
export default {
name: "NewsList",
components: { ArticleCard, LoadMoreButton },
props: {
whatToShow: {
type: String,
required: true,
},
searchString: {
type: String,
required: true,
default: "",
},
},
data: () => ({
language: "en",
page_size: 24,
current_page: 1,
totalResults: 1,
articles: [],
}),
mounted() {
this.getArticles();
},
watch: {
whatToShow() {
this.getArticles();
},
searchString() {
this.getArticles();
},
},
computed: {
isMore() {
// Check if the total number of pages is grater then the current page
let totalPages = Math.ceil(this.totalResults / this.page_size);
return totalPages > this.current_page;
},
},
methods: {
getArticles() {
const endpoint = `${process.env.VUE_APP_API_URL}/${this.whatToShow}?q=${this.searchString}&language=${this.language}&pageSize=${this.page_size}&page=${this.current_page}&apiKey=${process.env.VUE_APP_API_KEY}`;
this.$axios
.get(endpoint)
.then((response) => {
this.totalResults = response.data.totalResults;
this.articles = [...this.articles, ...response.data.articles];
})
.catch((err) => console.log(err));
},
loadMore() {
if (this.isMore) {
this.current_page++;
this.getArticles();
}
},
},
};
</script>
In srccomponentsLoadMoreButton.vue
I have:
<template>
<button class="btn btn-md btn-success" @click="$emit('load-more')">
{{ text }}
</button>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "LoadMoreButton",
props: {
text: {
type: String,
required: false,
default: "Load more",
},
},
});
</script>
I use the isMore
computed property (Boolean) to hide the button’s container if there are no more articles to load.
However, after the last click on the LoadMoreButton
, before it disappears, no additional articles are loaded.
And the "code" in the response is "maximumResultsReached".
There is a sandbox HERE with all the code.
What am I doing wrong?
What is the most reliable way to fix this issue?
2
Answers
Your loadMore is wanting a boolean from your computed property and only runs if it is true: you are only checking for greater than which will return false if it is equal to. So the last page and total number of pages should be the same integrate value and return true to load last part of your data.
I suggest you to track that
maximumResultsReached
property from the server, and once it’s true setisMore
tofalse
. It seems like a less complicated approach.