Reputation: 1885
I want to display list of documents that are fetched from Firestore. I'd like to display 5 documents by default and show a "Load more" button that will fetch another 5 documents when clicked.
With a static list, I'd do it like this, rather easy:
loadMoreInvoices() {
//Get number of last item
var lastItemInvoiceNumber = (this.invoices[this.invoices.length-1] as any).invoice_number;
this.afs.collection('clients').doc(uid).collection('invoices', ref => ref.orderBy('invoice_number').startAt(lastItemInvoiceNumber).limit(5+1)).get().then(snap => {
//Remove first elem from array as it is a duplicate
snap.shift()
//Add all loaded invoices to array
snap.forEach(item => {
this.invoices.push(item)
})
//Check if there are any more invoices to be loaded and set status accordingly
if (snap.length < this.moreInvoicesToBeLoaded) {
this.noMoreInvoices = true;
} else {
this.noMoreInvoices = false;
}
});
}
ngOnInit() {
this.afs.collection('clients').doc(uid).collection('invoices', ref => ref.orderBy('invoice_number').limit(invoicesToBeLoaded)).get().then(snap => {
if (invoices.length < this.invoicesToBeLoaded) {
//Display "Load more" only if false
this.noMoreInvoices = true;
}
this.invoices = invoices;
this.loaded = true;
})
}
How can I get the same behaviour using Observables instead of static data?
The way I did it above would result in a corruption of the list after this.invoices
changes due to the Observable.
Upvotes: 3
Views: 373
Reputation: 7692
Adding some information increnemntally is possible with help of scan
operator which allows you to use accumulator and return a new value which will be passed to the consumer and will serve as an accumulator for next observable emit.
You could make something like this
source$ = this.page$.pipe(
switchMap(page => this.getList(page)),
// here the magic goes. We initialize scan with "[]" seed (otherwise only second
// emit will be passed further as first one would be taken for the seed for accumulator)
// and use concat which returns new array of concatenated "acc" and "vall"
scan((acc, val) => acc.concat(val), [])
)
Then you simply use source$ | async
in template and you have your data fetched and updated incrementally (aka infinite scroll).
this.page$
is an observable for paging to make a new call to the remote resource.
Upvotes: 5