Тема и Наблюдаемый, как удалить элемент, список фильтра () и следующий ()

У меня есть список песен с настройками Subject и Observable (показано с | async на вид), и теперь я хочу удалить песню из списка, сделать некоторые filter() и позвонить next() на предмет.

Как и где я могу фильтровать? Сейчас занимаюсь getValue() на тему и передачи этого next() на, ну, тема. Это только кажется неправильным и округлым.

Я также пытался подписаться на тему и получать данные таким образом, фильтруя их и вызывая next() внутри subscribe(), но я получил RangeError.

Я мог бы отфильтровать Observable, сохранив все удаленные идентификаторы. После этого список субъекта становится несинхронным, так как там есть удаленные песни, и каждый наблюдатель должен иметь список удаленных идентификаторов, который кажется нелепым. Я быстро старею и становлюсь ментальным. Пожалуйста, помогите мне интернет:(

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

}

3 ответа

Решение

Я рекомендую вам создать новый атрибут на вашем компоненте, где вы будете в последний раз хранить состояние. (здесь понимает множество песен).

Всегда лучше концептуализировать ваш код с помощью внутреннего свойства, которое представляет ваше состояние (или хранилище), и другого атрибута, который играет роль для синхронизации остальной части вашего приложения (с помощью наблюдаемого / события).

Еще один совет - набирайте код по модели. Будет легче отлаживать и поддерживать.

Тогда вам просто нужно обновить его в соответствии с вашей логикой, а затем по вашей теме

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

Если вы хотите сохранить все в потоках, вы можете взять страницу из книги воспроизведения 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);
  }
}

Таким образом, вы можете просто фильтровать, как будто это простой массив объектов.

Другие вопросы по тегам