I have an Angular component that lazy loads data to an Observable<Item[]> through a BehaviorSubject<Item[]> when the scroll position of a container reaches the bottom.
The needed properties and the init() function that initializes the list of items look like
private _itemList: BehaviorSubject<Item[]>;
private _done = new BehaviorSubject(false);
private _loading = new BehaviorSubject(false);
private _page: number;
itemList: Observable<Item[]>;
init() {
this._page = 0;
this._itemList = new BehaviorSubject([])
this.mapAndUpdate();
this.itemList = this._itemList.asObservable()
.scan((acc, val) => {
return acc.concat(val);
});
}
and the function that does the actual fetching of data
mapAndUpdate() {
if (this._done.value || this._loading.value) {
return;
}
this._loading.next(true);
const offset = this._page * 20;
const limit = 20;
return this.service.getItems(limit, offset)
.do(res => {
this._itemList.next(res.items);
this._loading.next(false);
if (!res.items.length) {
this._done.next(true);
}
}).subscribe();
}
In the same component, I'm subscribing to realtime push events that can emit new items which should be added to the beginning of the array instead of the end of the array.
subscribeToItemsChannel() {
this.pusherService.getItemsChannel().bind('new-item', (res: any) => {
const item = res.item as Item;
// Emitting the item with next() will only add it to the end of the array
this._itemList.next([item]);
});
}
I've tried to use a boolean value shouldPrepend that I set in the realtime function handler together with
.scan((acc, val) => {
if(this._shouldPrepend) {
return val.concat(acc);
} else {
return acc.concat(val);
}
});
which does add the new item to the beginning, but also messes up the order of the rest of the array and it doesn't feel like the correct rxjs way to do it either.
How can I at any given random moment prepend an object to an Observable<array>?
Here is a JSBin that better explains the problem.