mnlgr
mnlgr

Reputation: 21

Is there a way to do pagination with firebase realtime database (vuejs)?

I'm trying to paginate my data from firebase realtime database.

Do I have to change to firestore ? Where all is explain in Google's doc (https://firebase.google.com/docs/firestore/query-data/query-cursors) or it's also possible with rtdb ?

Here is my code (i'm using vue js) :

loadConcerts ({commit}) {
      commit('setLoading', true)
      firebase.database().ref('concerts')
      .orderByChild('expires')
      .startAt(Date.now() / 1e3)
      .limitToFirst(10)
      .once('value')
      .then(data => {
        const concerts = []
        data.forEach(element => {
        concerts.push({
              id: element.key,
              title: element.val().title,
              day: element.val().day,
              ticketlink: element.val().ticketlink,
              description: element.val().descriptio
            })
        })
          commit('setLoadedConcerts', concerts)
          commit('setLoading', false)
        })
        .catch(
          (error) => {
            console.log(error)
            commit('setLoading', false)
          }
        )
    },

I would like to add pagination after 10 results, or infinite scrolling.

Upvotes: 2

Views: 1391

Answers (1)

xaander1
xaander1

Reputation: 1160

I have also had similar problem with pagination. The documentation seems to be insufficient i.e they show you how to go to next page but not how to move back to the previous page. Its just frustrating really.

I am using firestore

Below is how i implemented a simple pagination. I have already configured VueFire , Firebase and BootstrapVue i'll head straight to the code.

What to do different that no one shows you.

  • Use VueFire programmatic binding instead of declarative binding see here
  • To get firstVisible item in firebase run documentSnapshots.docs[0]
<template>
    <div>
        <p>{{countries}}</p>
         <b-button-group size="lg" class="mx-2">
      <b-button :disabled="prev_btn" @click="previous" >&laquo;</b-button>
      <b-button :disabled="next_btn" @click="next">&raquo;</b-button>
    </b-button-group>
    </div>
</template>
<script>
 import firebase from 'firebase/app'
import 'firebase/auth'
import { db } from '../main'

export default {
 name: 'Countries',
 data () {
  return {
   countries: [],
   limit: 2,
   lastVisible: '',
   firstVisible: '',
   next_btn: false,
   prev_btn: true
  }
 },
 methods: {
  next () {
   if (!this.next_btn) {
   // bind data with countries
    this.$bind('countries', db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit))
    // set last and first visible items
    db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get().then(documentSnapshots => {
     this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
     this.firstVisible = documentSnapshots.docs[0]
    }).then(() => {
     // Peep  on the next  next query to see if it gives zero
     db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get()
      .then(snap => {
       if (snap.size === 0) {
        //disable button if the next peeped result gets zero
        this.next_btn = true
        // enable previous button
        this.prev_btn = false
       } else {
        // enable next button if peeped result is not zero
        this.next_btn = false
        // enable previous button
        this.prev_btn = false
       }
      })
    })
   }
  },
  previous () {
   // Ensure previous is not zero
   db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get().then(snap => { return snap.size })
   .then(size => {
    //confirm is not zero here
    if (size !== 0) {
     //bind the previous to countries
     this.$bind('countries', db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit))
     // Set last and first visible
     db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get().then(documentSnapshots => {
      this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
      this.firstVisible = documentSnapshots.docs[0]
     }).then(() => {
      // peep the next previous query
      db.collection('Countries').orderBy('createdAt').endBefore(this.firstVisible).limitToLast(this.limit).get()
       .then(snap => {
        if (snap.size === 0) {
         //if next peeped previous button gets 0 disable
         this.prev_btn = true
         this.next_btn = false
        } else {
         //if next peeped result is does not get 0 enable buttons
         this.prev_btn = false
         this.next_btn = false
        }
       })
     })
    }
   })
  }
 },
 mounted () {
  // run first query and bind data
  this.$bind('countries', db.collection('Countries').orderBy('createdAt').limit(this.limit))
  // set last and first Visible
  db.collection('Countries').orderBy('createdAt').limit(this.limit).get().then(documentSnapshots => {
   this.lastVisible = documentSnapshots.docs[documentSnapshots.docs.length - 1]
   this.firstVisible = documentSnapshots.docs[0]
  }).then(() => {
            // peep to check if next should be on or off
            db.collection('Countries').orderBy('createdAt').startAfter(this.lastVisible).limit(this.limit).get()
                .then(snap => {
                    if (snap.size === 0) {
                        this.next_btn = true
                    }
                })
        })
 }
}
</script>

Upvotes: 1

Related Questions