I am working on a Nuxt app. For one of my dynamic pages I want to show data with infinite scrolling. For that purpose I decided to use Vue-infinite-loading. I read this article and also skimmed the documentation of Vue-infinite-loading. In both of them they were using axios module to load data step by step to show in the page when the scroll reaches to specific point in that page. But in my page the data is already present in the page according to page-id with the help of $strapi module and Nuxt fetch hook. The whole code of my page is like below:
<template>
<v-container fluid>
<v-row>
<v-col cols="10" class="mx-auto">
<p v-if="$fetchState.pending">
در حال بارگذاری اطلاعات
</p>
<p v-else-if="$fetchState.error">
مشکلی در نمایش اطلاعات به وجود آمده است.
</p>
<div v-else>
<h1 v-html="this.fourType[this.nameRoute]['title']">
</h1>
<section>
<BaseCard
v-for="item in listShow"
:key="item.id"
:imgId = "item.id"
:sizeCard = "270"
>
<template v-slot:tozih>
{{ item.tozih }}
</template>
<template v-slot:aout>
{{ item.author }}
</template>
</BaseCard>
</section>
<infinite-loading
spinner="spiral"
@infinite="infiniteScroll"
>
</infinite-loading>
</div>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
data() {
return {
listBooks: [],
fourType:{
short: {
title: "در این قسمت می‌توانید کتابها را به ترتیب از کوچک (کمترین تعداد صفحه) به بزرگ (بیشترین تعداد صفحه) مشاهده نمایید:",
request: 1
},
programming: {
title: "در این قسمت می‌توانید کتب مرتبط با برنامه‌نویسی (دارای برچسب برنامه‌نویسی) را به ترتیب به روزرسانی (از جدیدترین به قدیمی‌ترین) مشاهده نمایید:",
request: 2
},
new: {
title: "در این قسمت می‌توانید کتب موجود در سایت را به ترتیب به روز رسانی (از جدید به قدیم) مشاهده نمایید:",
request: 3
},
random: {
title: "در این قسمت می‌توانید به صورت تصادفی به مشاهده تمامی کتب موجود در سایت بپردازید:",
request: 4
}
},
nameRoute: this.$route.params.type
}
}, // end of data
computed: {
listShow: function() {
return [ this.listBooks[0], this.listBooks[1] ]
}
}, // end of computed
methods: {
infiniteScroll($state) {
if (this.listBooks.length > 1) {
this.listBooks.forEach((item) => this.listShow.push(item))
$state.loaded()
}
else {
$state.complete()
}
}
}, // end of methods
async fetch() {
switch (this.nameRoute) {
case "short":
this.listBooks = await this.$strapi.$books.find("_sort=pageQuantity:ASC");
break;
case "programming":
this.listBooks = await this.$strapi.$books.find({ 'tags.name': ['برنامه نویسی'], _sort: 'updated_at:DESC' });
break;
case "new":
this.listBooks = await this.$strapi.$books.find("_sort=updated_at:DESC");
break;
default:
this.listBooks = this.$store.getters["books/randomBook"](this.$store.state.books.list2.length);
break;
}
}
}
</script>
<style scoped>
</style>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
In the code I get the data in fetch hook (that is different according to page id) and then put it in listBooks Vue data. What I want to do is that show for example 2 data in listBooks first and when the scroll reached to the end of the second data (second card here), I show the rest of data step by step with infinite scrolling method. So I used a Computed data called listShow and used it in v-for. Then I put the code I thought that maybe it might work inside infiniteScroll method. But obviously that does not work, because I just guess that. If anyone know that how change that code to work and show data in infinite scrolling please help me to solve this issue.
CodePudding user response:
Usually, an infinite loader is used to have a small subset of data that you then expand for performance reasons: not having to load 100 elements at once but 10, then 10 more etc...
If you already have the data locally at once and like the behavior of it, without any "pagination" needed from your Strapi backend, you can always watch for the @infinite
event and increase the size of your initial array of elements with the next one.
Saying that if you display 10 of them, want to scroll down and show 10 more: display the first 10, then when the infinite
event is triggered, append 10 more items to your initial array and so on.
My previous answer may help understand it a bit more.
PS: beware of some reactivity issues that you may face one day when dealing with arrays.
CodePudding user response:
I finally with the help of kissu answer and with the inspiration of the code of the article mentioned in my question found the solution. Here I will post the code of my whole Nuxt page to show the answer for using other developers:
<template>
<v-container fluid>
<v-row>
<v-col cols="10" class="mx-auto">
<p v-if="$fetchState.pending">
در حال بارگذاری اطلاعات
</p>
<p v-else-if="$fetchState.error">
مشکلی در نمایش اطلاعات به وجود آمده است.
</p>
<div v-else>
<h1 v-html="this.fourType[this.nameRoute]['title']">
</h1>
<section>
<BaseCard
v-for="item in list2"
:key="item.id"
:imgId = "item.id"
:sizeCard = "270"
>
<template v-slot:tozih>
{{ item.tozih }}
</template>
<template v-slot:aout>
{{ item.author }}
</template>
</BaseCard>
</section>
<infinite-loading
spinner="spiral"
@infinite="infiniteScroll"
>
</infinite-loading>
</div>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
data() {
return {
listBooks: [],
page: 0,
list2: [],
fourType:{
short: {
title: "در این قسمت می‌توانید کتابها را به ترتیب از کوچک (کمترین تعداد صفحه) به بزرگ (بیشترین تعداد صفحه) مشاهده نمایید:",
request: 1
},
programming: {
title: "در این قسمت می‌توانید کتب مرتبط با برنامه‌نویسی (دارای برچسب برنامه‌نویسی) را به ترتیب به روزرسانی (از جدیدترین به قدیمی‌ترین) مشاهده نمایید:",
request: 2
},
new: {
title: "در این قسمت می‌توانید کتب موجود در سایت را به ترتیب به روز رسانی (از جدید به قدیم) مشاهده نمایید:",
request: 3
},
random: {
title: "در این قسمت می‌توانید به صورت تصادفی به مشاهده تمامی کتب موجود در سایت بپردازید:",
request: 4
}
},
nameRoute: this.$route.params.type
}
}, // end of data
methods: {
infiniteScroll($state) {
setTimeout(() => {
let emptyArr = [];
for (let index = this.page*10; index < this.page*10 10; index ) {
if (this.listBooks[index]) {
emptyArr.push(this.listBooks[index])
}
}
if (emptyArr.length > 0) {
emptyArr.forEach(
(item) => this.list2.push(item)
)
$state.loaded();
} else {
$state.complete()
}
this.page
}, 500)
}
}, // end of methods
async fetch() {
switch (this.nameRoute) {
case "short":
this.listBooks = await this.$strapi.$books.find("_sort=pageQuantity:ASC");
break;
case "programming":
this.listBooks = await this.$strapi.$books.find({ 'tags.name': ['برنامه نویسی'], _sort: 'updated_at:DESC' });
break;
case "new":
this.listBooks = await this.$strapi.$books.find("_sort=updated_at:DESC");
break;
default:
this.listBooks = this.$store.getters["books/randomBook"](this.$store.state.books.list2.length);
break;
}
}
}
</script>
<style scoped>
</style>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
the two important changes were:
1- Using an empty array called list2 in my Vue data instead of Vue computed data.
2- Using a variable called emptyArr in my infiniteScroll method that holds only for example 10 items of the original data (Vue listBooks data) and is showing them with scrolling the page each time that 10 data passed from the user view.