Using observables for query
options just does not work like that. There is no facility in the underlying SDK to dynamically modify a query's limitToFirst
and there's no way of doing it in AngularFire2.
Each time an observable query
option emits a new value, a new Firebase ref is created. You can see it in the source here.
However, it would be possible to create an observable that represents an infinite list by doing something like this:
import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import rxjs/add/observable/defer";
import rxjs/add/observable/zip";
import rxjs/add/operator/concatMap";
import rxjs/add/operator/filter";
import rxjs/add/operator/first";
import rxjs/add/operator/map";
import rxjs/add/operator/scan";
import rxjs/add/operator/share";
import rxjs/add/operator/startWith";
const pageSize = 100;
let notifier = new Subject<any>();
let last: Observable<any>;
let infiniteList = Observable
// Use zip to combine the notifier's emissions with the last
// child value:
.zip(notifier, Observable.defer(() => last))
// Use concatMap to emit a page of children into the
// composed observable (note that first is used to complete
// the inner list):
.concatMap(([unused, last]) => this.af.database.list("quests", {
query: {
// If there is a last value, start at that value but ask
// for one more:
limitToFirst: last ? (pageSize + 1) : pageSize,
orderByChild: "date_published",
startAt: last
}
})
.first()
)
// Use scan to accumulate the page into the infinite list:
.scan((acc, list) => {
// If this isn't the initial page, the page was started
// at the last value, so remove it from the beginning of
// the list:
if (acc.length > 0) {
list.shift();
}
return acc.concat(list);
}, [])
// Use share so that the last observable (see below) doesn't
// result in a second subscription:
.share();
// Each time a page is emitted, map to its last child value so
// that it can be fed back into the composed infinite list:
last = infiniteList
.filter((list) => list.length > 0)
.map((list) => list[list.length - 1].date_published)
.startWith(null);
infiniteList.subscribe((list) => console.log(list));
// Each time the notifier emits, another page will be retrieved
// and added to the infinite list:
notifier.next();
notifier.next();
notifier.next();
That will work, but if the child upon which you are ordering has duplicate values, AngularFire2 won't be able to page through the results reliably until this issue is re-opened and resolved.
The resultant list is static. That is, children already paged in to the list won't be updated if the database changes. Implementing a dynamic list is more challenging, as duplicated and missing children can easily be effected by the limit-based paging mechanism.
Since writing this answer, I've made available tested implementations of forward and reverse, non-realtime and realtime infinite list observables in a library of Firebase observables that I have open sourced. See this GitHub repo.