首页 > 解决方案 > 使用 rxjs 进行 Mat-sort 无法正常工作

问题描述

当从观察者流创建源时,我在 mat-table 中实现 mat-sort 时遇到问题。

只需通过以下文档实现它:

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

无法正常工作 - 我的桌子上总是只排序 5 行。

我认为,我的问题在于正确使用它与 rxjs 连接。

不幸的是,在检查了另一个问题/文档后,我找不到任何想法。

我从两个观察者流生成数据源。我还使用了 BehaviourSubject(用于初始值)、combineLatest 和 switch map。表已正确创建并且工作正常。

此外,当我添加过滤器(根据角度材料设计文档)时,它工作正常。但是垫排序......不是(只有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 - 但我认为这也不是我的情况。任何想法/建议都将非常有价值。

我认为,我应该订阅可观察流的排序方法。我在分页时遇到了同样的问题。有时有效,有时无效。

标签: angularsortingrxjsangular-materialangular5

解决方案


您的问题代码类似于显示来自 HTTP 调用的数据的 mat-tables 示例: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


推荐阅读