角度rxjs过滤器可观察

时间:2020-05-23 13:25:50

标签: angular filter rxjs observable rxjs-pipeable-operators

我正在尝试使用一系列过滤器来过滤可观察产品,但是我真的不知道如何。

让我解释一下,我想将过滤的结果设置为filteredProducts。 对于过滤,我必须针对每个过滤器检查产品的过滤器数组是否包含过滤器的名称以及产品值数组的过滤器ID是否包含。

目前,该过滤器有效,但仅适用于最后选择的过滤器,我想用我的selectedFilters数组中的所有过滤器过滤产品列表。我可以有一个或多个过滤器。

StackBlitz

export class ProductsFilterComponent extends BaseComponent implements OnInit {
    @Select(FiltersState.getAllFilters) filters$: Observable<any>;
    @Input() products$: Observable<Product[]>;
    filteredProducts$: Observable<Product[]>;
    public selectedFilters = [];

    constructor(
        private store: Store) { super(); }

    ngOnInit() {
        this.store.dispatch(new GetAllFilters());
    }

    private filterProducts() {
        this.filteredProducts$ = this.products$.pipe(
            map(
                productsArr => productsArr.filter(
                    p =>
                        p.filters.some(f => this.selectedFilters.some(([selectedF]) => selectedF === f.name.toLowerCase()) // Filter name
                            && f.values.some(value => this.selectedFilters.some(([, filterId]) => filterId === value)) // Filter id
                        )
                )
            )
        );
        this.filteredProducts$.subscribe(res => console.log('filtered:', res));
    }
}

这是产品对象的结构 Here's the structure of a product object

这是selectedFilters的结构 enter image description here

在此先感谢您:-)。

1 个答案:

答案 0 :(得分:0)

这是一个stackblitz,上面有一个有效的示例。

总结一下:

  1. 我们聆听产品和过滤器的变化,并使用combineLatest将它们组合成一个可观察的状态:
    const productsAndFilters: Observable<[Product[], ProductFilter[]]> = combineLatest([
      this.products$,
      this.filters$.pipe(startWith(initialFilters)),
    ]);
  1. 然后我们将组合的observable传递到实际执行过滤工作的函数中
    this.filteredProducts$ = productsAndFilters.pipe(
      map(([products, filters]) => {
        return AppComponent.filterProducts(products, filters);
      }),
    )
  1. 每次products$发出新值时,我们将更新filteredProducts$。每当filters$发出新值时,我们也会对其进行更新。

  2. 请注意,{Each combineLatest直到可观察到的至少发射一次后才会发射。因此,如果您的“ selectedFilters”一开始没有发出任何东西,则可以使用startWith运算符创建一个具有起始值的可观察对象。这样可以确保combineLatest会在products$发出值后立即发出值。


我还将过滤代码移到了静态函数中

  private static filterProducts(products: Product[], filters: ProductFilter[]) {
    // we can combine filters into a single function
    // so that the code a tiny bit more readable
    const matchesAllFilters = (product: Product) => filters.every(
        ([filterName, filterValue]) => product.filters
          .some(f => f.name === filterName &&
                     f.values.some(value => value === filterValue))
    );

    return products.filter(matchesAllFilters);
  }

在我的示例中,我假设您希望满足所有过滤条件。如果您希望满足“至少一个”过滤器,则可以将filters.every更改为filters.some