将对象添加到可观察数组

时间:2018-03-07 15:57:15

标签: angular rxjs

我有一个Angular组件,当容器的滚动位置到达底部时,延迟将数据加载到Observable<Item[]>BehaviorSubject<Item[]>

初始化项目列表所需的属性和init()函数看起来像

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);
    });
}

以及实际获取数据的函数

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();
}

在同一个组件中,我订阅了可以发出新项目的实时推送事件,这些新项目应该添加到数组的开头而不是数组的末尾。

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]);
    });
}

我尝试使用我在实时函数处理程序中设置的布尔值shouldPrepend

.scan((acc, val) => {
    if(this._shouldPrepend) {
        return val.concat(acc);
    } else {
        return acc.concat(val);         
    }
});

确实将新项目添加到开头,但也会混淆数组其余部分的顺序,并且它也不会像正确的rxjs方式那样。

我如何在任何给定的随机时刻将对象添加到Observable<array>

Here is a JSBin可以更好地解释问题。

2 个答案:

答案 0 :(得分:2)

我理解使用一个特殊的this._shouldPrepend变量看起来很奇怪,因为它打破了&#34;纯函数&#34;范例

因此,我个人会发出包含信息的对象,无论我要添加或附加什么信息。

enum Action { Append, Prepend };

...

numberList = bSubject
  .scan((acc, val) => val.action === Action.Prepend
    ? [val.value, ...acc]
    : [...acc, val.value]
  );

...

setInterval(() => { 
  console.log('Fetching data... Numberlist is now: ');
  bSubject.next({ action: Action.Append, value: i});
  i++;
}, 3000);

您的最新演示:http://jsbin.com/wasihog/edit?js,console

最终,如果您不想改变发布值的方式,您可以拥有两个合并的主题。一个预先设定价值的,另一个追加价值。

const append$ = new Subject();
const prepend$ = new Subject();

Observable.merge(
  append$.map(value => ({ action: Action.Append, value })),
  prepend$.map(value => ({ action: Action.Prepend, value })),
)

你可以看到你发出像append$.next(1)这样的值,并且该值将被一个告诉scan如何处理它的对象包裹。

答案 1 :(得分:0)

我对这件事有些迟了,但是您似乎想要 startWith

//emit (1,2,3)
const source = of(1, 2, 3);

//start with 0
const example = source.pipe(startWith(0));

//output: 0,1,2,3
const subscribe = example.subscribe(val => console.log(val));

此代码示例来自https://www.learnrxjs.io/operators/combination/startwith.html