For the component of cards in my project, I am trying to implement infinite scrolling with 3 cards per row. Upon reaching the end of the page, I intend to make an API call for the next page and display the subsequent set of cards. Below is my implementation code for infinite scrolling, which seems to be malfunctioning:
<template>
<div
class="container"
ref="scrollContainer"
@dragover.prevent="handleDragOverContainer"
@drop.prevent="handleDrop"
>
<div class="card-container">
<div class="card">
<AddCourseCard />
</div>
<div
class="card"
v-for="(element, index) in products"
:key="index"
:draggable="true"
@dragstart="handleDragStart(index)"
@dragover.prevent="handleDragOverCard(index)"
@dragend="handleDragEnd"
>
<CoursesCard
:title="element.title"
:text="element.text"
:imageSrc="element.imageSrc"
:productId="element.id"
/>
</div>
</div>
</div>
</template>
<script>
import AddCourseCard from './AddCourseCard.vue'
import CoursesCard from './CourseCard.vue'
import { OfferService } from '../../service/index'
import { GroupState } from '../../composition/groups'
import Draggable from 'vuedraggable'
export default {
name: 'Learning',
components: {
CoursesCard,
AddCourseCard,
draggable: Draggable,
},
data() {
return {
products: [],
pageNo: 1, // Initialize pageNo
limit: 10, // Set your desired limit per page
loading: false,
isGroupAdmin: GroupState.state.isGroupAdmin,
dragData: null,
draggedIndex: null,
dropTargetIndex: null,
reachedEnd: false,
// Flag to prevent multiple requests while loading
dragOptions: {
// Specify any options for Vue.Draggable here if needed
group: 'cards', // Add a group to allow cards to be dragged between different lists
animation: 200, // Animation duration when items are reordered
},
dummyData: [
{
title: 'Card 1',
text: 'Some quick example text for Card 1',
imageSrc: 'https://picsum.photos/1600/1176/?image=25',
},
{
title: 'Card 2',
text: 'Some quick example text for Card 2',
imageSrc: 'https://picsum.photos/1600/1176/?image=26',
},
{
title: 'Card 3',
text: 'Some quick example text for Card 3',
imageSrc: 'https://picsum.photos/1600/1176/?image=27',
},
{
title: 'Card 4',
text: 'Some quick example text for Card 1',
imageSrc: 'https://picsum.photos/1600/1176/?image=25',
},
{
title: 'Card 5',
text: 'Some quick example text for Card 2',
imageSrc: 'https://picsum.photos/1600/1176/?image=26',
},
{
title: 'Card 6',
text: 'Some quick example text for Card 3',
imageSrc: 'https://picsum.photos/1600/1176/?image=27',
},
// Add more dummy data items as needed
],
}
},
mounted() {
// Call the initial API request when the component is mounted
this.fetchAllProducts()
const container = this.$refs.scrollContainer
if (container) {
container.addEventListener('scroll', this.handleScroll)
}
},
methods: {
handleScroll() {
const container = this.$refs.scrollContainer
if (!container) return
// Calculate when to trigger fetching more data based on scroll position
const scrollPosition = container.scrollTop + container.clientHeight
const maxScroll = container.scrollHeight
if (
scrollPosition >= maxScroll - 100 &&
!this.loading &&
!this.reachedEnd
) {
// You can adjust the threshold (100 in this example) to your needs
this.fetchNextPage()
}
},
async fetchNextPage() {
// Your existing code to fetch the next page of data
// ...
if (this.pagesEnd) {
this.reachedEnd = true // Set the flag to indicate the end of data
}
},
async fetchAllProducts() {
if (!this.isGroupAdmin) {
this.fetchDataFromAPIForGroup()
} else {
this.fetchDataFromAPI()
}
},
async fetchDataFromAPI() {
if (this.loading) return // Prevent multiple requests while loading
this.loading = true
try {
const response = await OfferService.getOfferProductForUser({
pageNo: this.pageNo,
limit: this.limit,
})
// Append the new data to the existing products array
this.products = [...this.products, ...response]
// Increment the pageNo for the next request
this.pageNo++
} catch (error) {
console.error('Error fetching data from API:', error)
} finally {
this.loading = false
}
},
async fetchDataFromAPIForGroup() {
if (this.loading) return // Prevent multiple requests while loading
this.loading = true
try {
const response = await OfferService.getOfferProductForGroup({
pageNo: this.pageNo,
limit: this.limit,
})
// Append the new data to the existing products array
this.products = [...this.products, ...response]
// Increment the pageNo for the next request
this.pageNo++
} catch (error) {
console.error('Error fetching data from API:', error)
} finally {
this.loading = false
}
},
handleDragStart(index) {
this.draggedIndex = index
},
handleDragOverCard(index) {
this.dropTargetIndex = index
},
handleDragOverContainer(event) {
// Prevent the default behavior, which is to not allow dropping
event.preventDefault()
},
handleDrop() {
if (this.draggedIndex !== null && this.dropTargetIndex !== null) {
// Splice the dragged card out of the dummyData array
const draggedCard = this.products.splice(this.draggedIndex, 1)[0]
// Insert the dragged card at the drop target index
this.products.splice(this.dropTargetIndex, 0, draggedCard)
// Reset the dragged and drop target indices
this.draggedIndex = null
this.dropTargetIndex = null
}
},
// Handle drag over
handleDragOver(index) {
if (!this.dragData) return
// Prevent the default behavior, which is to not allow dropping
event.preventDefault()
// Swap the positions of the dragged item and the drop target
const temp = this.dummyData[index]
this.dummyData[index] = this.dragData
this.dragData = temp
console.log(this.dummyData)
},
// Handle drag end
handleDragEnd() {
this.dragData = null
},
},
}
</script>
<style scoped>
.container {
display: flex;
justify-content: center;
/* Added to enable scrolling */
overflow-y: auto;
}
.card-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
max-width: 1216px;
margin: 0 auto;
}
.card {
flex: 0 0 calc(33.33% - 10px);
max-width: calc(33.33% - 10px);
margin-bottom: 20px;
box-sizing: border-box;
}
@media (max-width: 768px) {
.card {
flex: 0 0 calc(50% - 10px);
max-width: calc(50% - 10px);
}
}
@media (max-width: 480px) {
.card {
flex: 0 0 100%;
max-width: 100%;
}
}
</style>
I have included the styles as well, just in case there might be a CSS-related issue causing a blockage. Please assist me in understanding the problem here as I have been stuck trying to resolve it for hours.