Subject 和 Observable,如何删除 item,filter() list 和 next()

Subject and Observable, how to delete item, filter() list and next()

我有一个设置了主题和可观察对象的歌曲列表(在视图中显示为 | async),现在我想从列表中删除一首歌曲,执行一些 filter() 并调用 next() 关于主题。

如何以及在何处过滤? 现在我正在对主题进行 getValue() 并将其传递给 next() 主题。这似乎是错误和循环的。

我也尝试订阅主题并以这种方式获取数据,过滤它并在 subscribe() 中调用 next(),但我得到了一个 RangeError。

我可以通过存储所有已删除的 ID 来过滤 Observable。 Subject 的列表然后通过删除那里的歌曲变得不同步,而且每个观察者都必须有 deleted-id 的列表,这看起来很可笑。我正在迅速变老和精神。请帮我上网:(

export class ArtistComponent implements OnInit {
  private repertoire$;
  private repertoireSubject;
  constructor(
    private route: ActivatedRoute,
    private service: ArtistService
  ) {
    this.getRepertoire().subscribe(
      songs => this.repertoireSubject.next(songs)
    );
  }

  getRepertoire() {
    return this.route.paramMap
      .switchMap((params: ParamMap) =>
      this.service.fetchRepertoire(params.get('id')));
  }

  //THIS IS WHERE I'M HAVING TROUBLE
  delete(id): void {
    this.repertoireSubject.next(
      this.repertoireSubject.getValue().filter(song => (song.id !== id))
    );
    // TODO remove song from repertoire API
  }

  ngOnInit() {
    this.repertoireSubject = new BehaviorSubject<any>(null);
    this.repertoire$ = this.repertoireSubject.asObservable();
  }

}

如果你想将所有内容都保存在流中,那么你可以从 Redux 剧本中获取一页并执行如下操作:

const actions = new Rx.Subject();

const ActionType = {
  SET: '[Song] SET',
  DELETE: '[Song] DELETE'
};

const songs = [
  { id: 1, name: 'First' },
  { id: 2, name: 'Second' },
  { id: 3, name: 'Third' },
  { id: 4, name: 'Fourth' },
  { id: 5, name: 'Fifth' }
];

actions
.do(x => { console.log(x.type, x.payload); })
.scan((state, action) => {
  switch(action.type) {
    case ActionType.SET:
     return action.payload;
    case ActionType.DELETE:
      return state.filter(x => x.id !== action.payload);
  }
  return state;
}, [])
.subscribe(x => { console.log('State:', x); });


window.setTimeout(() => {
  actions.next({ type: ActionType.SET, payload: songs });
}, 1000);

window.setTimeout(() => {
  actions.next({ type: ActionType.DELETE, payload: 2 });
}, 2000);

window.setTimeout(() => {
  actions.next({ type: ActionType.DELETE, payload: 5 });
}, 3000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.min.js"></script>

或者像这样:

const deletes = new Rx.Subject();

const songs = Rx.Observable.of([
  { id: 1, name: 'First' },
  { id: 2, name: 'Second' },
  { id: 3, name: 'Third' },
  { id: 4, name: 'Fourth' },
  { id: 5, name: 'Fifth' }
]);

window.setTimeout(() => {
  deletes.next(2);
}, 1000);

window.setTimeout(() => {
  deletes.next(5);
}, 2000);

songs.switchMap(state => {
  return deletes.scan((state, id) => {
    console.log('Delete: ', id);
   return state.filter(x => x.id !== id);
  }, state)
  .startWith(state);
}).subscribe(x => { console.log('State:', x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.min.js"></script>

如果您停止依赖异步管道并使用变量来处理您的歌曲,它会变得更容易:

import { filter } from 'rxjs/operators';
export class ArtistComponent implements OnInit {
  private songs: any;

  constructor(
    private route: ActivatedRoute,
    private service: ArtistService
  ) {
    this.getRepertoire().subscribe(songs => this.songs = songs);
  }

  getRepertoire() {
    return this.route.paramMap
      .switchMap((params: ParamMap) =>
        this.service.fetchRepertoire(params.get('id')));
  }

  delete(id): void {
    this.songs = this.songs.filter(song => song.id !== id);
  }
}

这样,您就可以像简单的对象数组一样简单地进行过滤。

我建议您在组件上创建新属性,您将在其中最后存储状态。 (这里理解歌曲数组)。

总是更好地概念化您的代码,内部 属性 代表您的状态(或存储)和另一个具有同步应用程序其余部分的角色的属性(通过可观察/事件)。

另一个技巧是按模型强类型代码。将更容易调试和维护。

然后你只需要根据你的逻辑更新它,然后在你的主题上

export interface SongModel {
        id: number;
        title: string;
        artiste: string;
    }

    export class ArtistComponent implements OnInit {
        private repertoire$ : Observable<SongModel[]>;
        private repertoireSubject: BehaviorSubject<SongModel[]>;
        //Array of song, should be same type than repertoireSubject.
        private songs: SongModel[];

        constructor(
            private route: ActivatedRoute,
            private service: ArtistService
        ) {

            //We push all actual references.
            this.getRepertoire().subscribe(
                songs => {
                    this.songs = songs;
                    this.repertoireSubject.next(this.songs);
                }
            );
        }

        ngOnInit() {
            //Because is suject of array, you should init by empty array.
            this.repertoireSubject = new BehaviorSubject<SongModel[]>([]);
            this.repertoire$ = this.repertoireSubject.asObservable();
        }


        getRepertoire() {
            return this.route.paramMap
                .switchMap((params: ParamMap) =>
                this.service.fetchRepertoire(params.get('id')));
        }

        //THIS IS WHERE I'M HAVING TROUBLE
        delete(id: number): void {
            // Update your array referencial.
            this.songs = this.songs.filter(songs => songs.id !== id);
            // Notify rest of your application.
            this.repertoireSubject.next(this.songs);
        }
    }