Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Howto paginate back to previous pages in a Angular(6) and firebase Firestore setup

There seem to be a lot of examples, tutorials and videos on howto paginate to the next page when using Angular with Cloud Firestore (Firebase).

But after extensive search i cannot find a way to paginate to a previous page. The furthest i got is just returning to the first page.

Here is how my Service looks right now:

import { Injectable } from '@angular/core';
import { AngularFirestore } from 'angularfire2/firestore';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Task } from './task.model';

@Injectable()
export class TaskService {
  private _data: BehaviorSubject<Task[]>;
  public data: Observable<Task[]>;
  firstEntry: any;
  latestEntry: any;

  constructor(private afs: AngularFirestore) { }

  public first() {
    this._data = new BehaviorSubject([]);
    this.data = this._data.asObservable();

    const tasksRef = this.getCollection('tasks', ref => ref.orderBy('createdAt').limit(5))
      .subscribe(data => {
        this.firstEntry = data[0].doc;
        this.latestEntry = data[data.length - 1].doc;
        this._data.next(data);
      });
  }

  public next() {
    const tasksRef = this.getCollection('tasks', ref => ref.orderBy('createdAt').startAfter(this.latestEntry).limit(5))
      .subscribe(data => {
        if (data.length) {
          this.firstEntry = data[0].doc;
          this.latestEntry = data[data.length - 1].doc;
          this._data.next(data);
        }
      });
  }

  public previous() {
    const tasksRef = this.getCollection('tasks', ref => ref.orderBy('createdAt').endBefore(this.firstEntry).limit(5))
      .subscribe(data => {
        if (data.length) {
          this.firstEntry = data[0].doc;
          this.latestEntry = data[data.length - 1].doc;
          this._data.next(data);
        }
      });
  }

  private getCollection(ref, queryFn?): Observable<any[]> {
    return this.afs.collection(ref, queryFn).snapshotChanges().pipe(
      map(actions => {
        return actions.map(a => {
          const data = a.payload.doc.data();
          const id = a.payload.doc.id;
          const doc = a.payload.doc;
          return { id, ...data, doc };
        });
      })
    );
  }
}

The initial loading (first page) works, and also all next pages are working as expected. But it seems like endBefore(this.firstEntry) doesn't hold the correct cursor, and results in the first page again.

What is the proper way to navigate back to the previous page?

And if someone knows of a complete tutorial or example of a working paginator, please share...

like image 311
Jordy Bulten Avatar asked Aug 13 '18 22:08

Jordy Bulten


People also ask

How do I get most recent documents on firestore?

Is there any way to get the last created document in Firebase Firestore collection? Yes, there is! The simplest way to achieve this is to add a date property to each object in your collection, then simply query it according to this new property descending and call limit(1) function. That's it!

What is orderByChild in firebase?

Firebase orderByChild once child_added is only giving one child. 0. Returning a single child's value on Firebase query using orderByChild and equalTo. 3. unspecified index when searching data with firebase cloud function on nested object running nested Query.


1 Answers

import * as firebase from 'firebase/app';
import { last } from 'lodash';
import { dropRight } from 'lodash';

Install this npm packages ( Lodash, Firebase )

After import firebase, last and dropRight from lodash. Last method returns the last element of array. DropRight method slices the last element of the array.

allEntry: Array<any[]> =  [];
firstEntry = [];
lastEntry;

Create three variables and assign the the firstEntry to an array in order to store the first data in the query. AllEntry stores all the data retrieved from the query. LastEntry to store the last element in the allEntry which would be used to as a cursor to get the data after that.

getMainEntry() {
return this.afs.collection('tasks', ref => ref.orderBy('createdAt').limit(5)).valueChanges().subscribe(data => {
  this.allentry = data;
  firebase.firestore().collection('tasks').doc(data[data.length - 1]['key']).onSnapshot(c => {
    this.lastentry = c;
    firebase.firestore().collection('tasks').doc(data[0]['key']).onSnapshot(da => {
      this.firstEntry.push(da);
    });
  });
});
}

This getMainEntry function gets the data in the collection, orders it by createdAt and limits it to 5. Then gets and assigns the documentsnapshot of the last element in the allEntry array to the lastEntry. After gets and pushes the documentsnapshot of the first element in the allEntry array into the firstEntry array.

Now let's create the next function

getNextData(){
  const entarr = [];
  firebase.firestore().collection('tasks').orderBy('createdAt').startAfter(this.lastEntry).limit(5).get().then((data) => {
    data.docs.map(a => {
      entarr.push(a.data());
      this.allEntry = entarr;
    });
  }).then(() => {
    firebase.firestore().collection('tasks').doc(entarr[entarr.length - 1]['key']).onSnapshot(data => {
      this.lastEntry = data;
    });
  }).then(() => {
    firebase.firestore().collection('tasks').doc(entarr[0]['key']).onSnapshot(da => {
      this.firstEntry.push(da);
    });
  });
}

The getNextData function gets the next data in the collection, orders it by createdAt and limits it to the next 5 data after the lastEntry. Then gets and assigns the documentsnapshot of the last element in the entarr array to the lastEntry. After gets and pushes the documentsnapshot of the first element in the allEntry array into the firstEntry array.

Previous Function

getPrevData() {
const entarr = [];
  this.firstEntry = dropRight(this.firstEntry);
const firstEntry = last(this.firstEntry);
firebase.firestore().collection('tasks').orderBy('createdAt').startAt(firstEntry).limit(5).get().then((d) => {
  d.docs.map(a => {
    entarr.push(a.data());
    this.allEntry = entarr;
    });
  }).then(() => {
    firebase.firestore().collection('tasks').doc(entarr[entarr.length - 1]['key']).onSnapshot(da => {
      this.lastEntry = da;
    });
  });
}

Hope this would be useful.

like image 102
Code Mickey Avatar answered Nov 14 '22 23:11

Code Mickey