Mat-sort с rxjs не работает должным образом

У меня проблема с реализацией mat-sort в mat-table, когда источник был создан из потока наблюдателей.

Просто выполните его с помощью документации:

ngAfterViewInit() {
        this.dataSource.sort = this.sort;
    }

не работает должным образом - всегда будет сортироваться только 5 строк на моем столе.

Я думаю, моя проблема заключается в правильном использовании его с соединением rxjs.

К сожалению, после проверки других вопросов/документации я не могу найти никакой идеи.

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

Также, когда я добавил фильтр (в соответствии с документацией по угловому материалу), он работает правильно. Но mat-sort... not (только 5 первых строк).

ngOnInit() {
        this.filters = itemFilters;
        this.idSubject = new BehaviorSubject(this.filters[0]);
        Observable.combineLatest(this.name, this.selectedFilter)
            .do(_ => this.items = null)
            .switchMap(([name, filterIndex]: [Name | null, number]) => {
                const item = this.filters[filterIndex];
                this.namesSubject.next(item.display);
                return this.itemService.getItems(name);
            })
            .subscribe(this.setItems.bind(this), this.setError.bind(this));
    }

Также я пробовал с Observable.zip - но я думаю, что это тоже не мое дело. Любая идея/совет будет очень ценным.

Я думаю, я должен подписаться на метод сортировки на наблюдаемые потоки. Та же проблема у меня с разбивкой на страницы. Иногда работает, иногда нет.

Ответ 1

Ваш код вопроса выглядит как пример из матовых таблиц, отображающих данные из HTTP-вызовов: https://stackblitz.com/angular/rmoxkmpkkyj?file=app%2Ftable-http-example.ts

Я думаю, что реализация может быть упрощена путем обработки событий разбивки на страницы и сортировки отдельно.

Пожалуйста, взгляните на этот пример, который я создаю, который обновляет данные по каждому событию: https://stackblitz.com/edit/angular-material-mat-table-sort-merge-streams?file=src%2Fapp%2Fmy-books % 2Fmy-books.component.ts

Обработчики событий

ngOnInit() {

    // default data 
    this.refresh(this.getDefaultOptions());

    this.sort.sortChange.subscribe((sort: Sort) => {
      console.log('sortChange', this.sort.active);
      this.paginator.pageIndex = 0;
      this.refresh(this.getCurrentOptions());
    });

    this.paginator.page.subscribe((page: PageEvent) => {
      console.log('paginator ', page);
      this.refresh(this.getCurrentOptions());
    });

}

Метод получения текущих параметров просмотра

getCurrentOptions() {
    const options: ViewOptions = {
      sortField: this.sort.active,
      sortDirection: this.sort.direction,
      page: this.paginator.pageIndex,
      pageSize: this.paginator.pageSize
    };

    return options;
  }

Пример того, как объединить несколько потоков

  findBooks(options: ViewOptions): Observable<BooksResponse> {

    console.log('findBooks', options);

    // retrieve multiple streams
    const multipleStreams = this.mockMultipleStreams();

    // sort and slice result
    const sortedAndSliced = multipleStreams.pipe(
      tap(items => {
        items = items.sort((a, b) => {
          const sortOrder = options.sortDirection === 'asc' ? -1 : 1;
          const valueA = a[options.sortField];
          const valueB = b[options.sortField];

          var result = (valueA < valueB) ? -1 : (valueA > valueB) ? 1 : 0;
          return result * sortOrder;
        });
      }),
      tap((items: Book[]) => {
        const start = options.page * options.pageSize;
        const end = start + options.pageSize;
        items = items.slice(start, end);
      })
    );

    // wrap in the response object
    const bookResponse = sortedAndSliced.pipe(
      map((items: Book[]) => {
        const response: BooksResponse = {
          items: items,
          total: this.fakeDataLength
        };
        return response;
      })
    );

    return bookResponse;

  }

  mockMultipleStreams(): Observable<Book[]> {
    const third = this.fakeDataLength / 3;

    // merge all the streams together
    const allTheBooks: Observable<[Book[], Book[], Book[]]> = zip(
      of(this.mockBooks('Magazine', third)),
      of(this.mockBooks('Books', third)),
      of(this.mockBooks('Newspaper', third))
    );

    // flatten the data 
    const result = allTheBooks
      .pipe(map((items) => {
        let result: Book[] = [];
        items.forEach(books => {
          books.forEach(book => { result.push(book) })
        });
        return result;
      }));

      return result;
  }

См. Полный код здесь: https://stackblitz.com/edit/angular-material-mat-table-sort-merge-streams?file=src%2Fapp%2Fbooks.service.ts