如何从 Observable<Array<any>> 中删除特定元素

Posted

技术标签:

【中文标题】如何从 Observable<Array<any>> 中删除特定元素【英文标题】:How to remove specific element from Observable<Array<any>> 【发布时间】:2016-11-06 00:32:53 【问题描述】:

有一个地点数组的 Observable:

places: Observable<Array<any>>;

在模板中它与异步管道一起使用:

<tr *ngFor="let place of places | async">
  ...
</tr>

在一些用户操作之后,我需要从这个数组中删除具有特定 id 的地方。我的代码中有这样的东西,但它不起作用:

deletePlace(placeId: number): void 
  this.apiService.deletePlace(placeId)
  .subscribe(
    (res: any) => 
      this.places
        .flatMap((places) => places)
        .filter((place) => place.id != placeId);
    , 
    (err: any) => console.log(err)
  );    
  

你能帮我解决这个问题吗?

【问题讨论】:

【参考方案1】:

你不能这样做,因为你不能“更新”一个 observable(即它不保持状态),但你可以通过它对事件做出反应。

对于您的用例,我将利用 scan 运算符并将两个流合并为一个:

一个用于初始加载 另一个用于删除事件。

这是一个示例:

let obs = this.http.get('/data').map(res => res.json());

this.deleteSubject = new Subject();

this.mergedObs = obs.merge(this.deleteSubject)
.startWith([])
.scan((acc, val) => 
  if (val.op && val.op==='delete') 
    var index = acc.findIndex((elt) => elt.id === val.id);
    acc.splice(index, 1);
    return acc;
   else 
    return acc.concat(val);
  
);

要触发元素删除,只需在主题上发送一个事件:

this.deleteSubject.next(op:'delete', id: '1');

看到这个 plunkr:https://plnkr.co/edit/8bYoyDiwM8pM74BYe8SI?p=preview。

【讨论】:

很想看到这个问题的更新答案,已经尝试了一天多。【参考方案2】:

您可以利用 filter 运算符:

this.places$
        .pipe(
            map(places => 
                // Here goes some condition, apply it to your use case, the condition only will return when condition matches
                return places.filter(place => place.placeId !== 0);
            ),
            map(response => (this.users$ = of(response)))
        )
        .subscribe(result => console.warn('Result: ', result));

【讨论】:

@kushalBaldev,不管模板更新,这都会返回一个 Observable;如果您的模板中有绑定,这将自动更新,因为您的可观察对象和模板之间存在同步。【参考方案3】:

过滤函数是不可变的,不会改变原始数组。

我会将 deletePlace 函数更改为如下所示:-

deletePlace(placeId: number):  void 
  this.apiService.deletePlace(placeId)
  .subscribe(
    (res: any) => 
      this.places = this.places.filter((place) => place.id != placeId);
    , 
    (err: any) => console.log(err)
  );    
  

【讨论】:

【参考方案4】:

RxJS 版本 6

将接受的答案与 RxJS 6typescript 一起使用会引发错误,因为 observables 持有不同的类型。你最好使用combineLatest,你也可以使用zip,但它不起作用!你刚才问为什么?答案是here :)

combineLatest([
  this.items$,
  this.deleteItem$
]).pipe(
  takeUntil(this.onDestroy),
  tap(([items, deleteItem]) => 
    if (deleteItem && deleteItem.op === 'deleteItem') 
      var index = items.findIndex((item) => item.id === deleteItem.id);
      if (index >= 0) 
        items.splice(index, 1);
      
      return items;
    
    else 
      return items.concat(deleteItem);
    
  )
).subscribe();

然后你可以发送事件..

this.deleteItem$.next( op: 'deleteItem', id: '5e88fce485905976daa27b8b' );

我希望它会帮助某人..

【讨论】:

这个解决方案的问题是,combineLatest 也总是发出最新的 deleteItem$ 值。意思是,在 deleteItem$ 第一次发出后,脚本会在每次发出 items$ 时尝试删除这个项目。

以上是关于如何从 Observable<Array<any>> 中删除特定元素的主要内容,如果未能解决你的问题,请参考以下文章

将Observable的输出从Object转换为Array

如何检查 Observable 数组的长度

将Observable中的值推送到Observable

Array 和 Observable Array 有啥区别?

Observable 的转换

RxJS 将 observable 附加到 typescript 中的 observable 数组列表