【问题标题】:How to remove specific element from Observable<Array<any>>如何从 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)
  );    
}  

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

【问题讨论】:

    标签: javascript typescript angular rxjs


    【解决方案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$ 时尝试删除这个项目。
      猜你喜欢
      • 1970-01-01
      • 2012-02-07
      • 2011-07-09
      • 2017-06-15
      • 2021-05-27
      • 2017-01-15
      • 2016-11-15
      • 2013-12-10
      • 2011-01-27
      相关资源
      最近更新 更多