Question:
Why Infinite scrolling in Vuejs is not working?

Problem

I am implementing infinite scrolling in my component of cards where 3 cards are present per row and on reaching to end of the page I want to make an API call for the next page to show and show the next cards. Here's my code implementation for infinite scrolling which is not working:


<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 also added the styles just in case any CSS can be a blocker, Please help to understand the issue here, I have been stuck for hours


Solutions

Make sure the scrollContainer div has a defined height. The overflow-y: auto; style will only create a scroll bar if the container has a maximum height or a fixed height.


<div class="container" ref="scrollContainer" style="max-height: 70vh;" @dragover.prevent="handleDragOverContainer" @drop.prevent="handleDrop">


Suggested blog

>Create a project using Vue.js: Beginners Guide

>Authentication with Vue 3 and Firebase

>Plugins and Presets for Vuejs project

>Create a Vue.js application with CLI Services

>Create a project using Vue.js: Beginners Guide

>Create Vue.js application API


Nisha Patel

Nisha Patel

Submit
0 Answers