【问题标题】:Rxjs filter observable with array of filters带有过滤器数组的 Rxjs 过滤器可观察
【发布时间】:2020-09-05 17:44:17
【问题描述】:

我在这里是因为我在使用 Rxjs 进行过滤时遇到问题。 我正在尝试使用一系列过滤器过滤可观察到的产品...

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

目前,过滤器有效,但仅适用于最后选择的过滤器,我想用我的 selectedFilters 数组中的所有过滤器过滤产品列表

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

这是产品对象的结构

这里是 selectedFilters 的结构

提前非常感谢您:-)。

【问题讨论】:

    标签: javascript angular filter rxjs observable


    【解决方案1】:

    这是我得到的错误。以及存在错误的行。

    【讨论】:

      【解决方案2】:

      您的代码看起来不错,但可以稍作修改。 首先,我会清理谓词,您可以使用 lodash intersectionWith 函数来交叉两个具有不同值的数组。
      此外,您可以使用mergeAll 运算符逐个过滤器迭代过滤器,这使得它看起来不那么嵌套。

      总体上应该是这样的:

      products$
        .pipe(
          mergeAll(),
          filter(
            product =>
              _.intersectionWith(
                product.filters,
                selectedFilters,
                (filter, [name, id]) =>
                  filter.name.toLowerCase() === name && filter.values.includes(id)
              ).length > 0
          )
        )
        .subscribe(console.log);
      

      您可以运行完整的示例代码here

      【讨论】:

      • 感谢您的帮助和解释,Tal :)。使用您的方法,我记录了与一个过滤器相对应的每个产品,但是当我添加另一个过滤器时,我收到错误“未定义不是函数”
      • 如果你能在 stackblitz 上重现你的错误,我会调查一下
      • 我无法在 Stackblitz 上重现它,但我发布了错误的答案
      【解决方案3】:

      我认为您必须将 selectedFilters 更改为 BehaviorSubject 并将其与 products$ observable 一起使用。有combineLatest 函数可以监听多个可观察对象的最新值并返回一个数组

      示例

      window.products$ = rxjs.of([
          {
              id: 1,
              name: "product 1",
              category: {
                  id: 1,
                  name: 'test'
              },
              filters: [
                  {
                      name: "test1",
                      values: [1]
                  }
              ],
              url: '/assets/test1.png'
          },
          {
              id: 2,
              name: "product 2",
              category: {
                  id: 1,
                  name: 'test'
              },
              filters: [
                  {
                      name: "test2",
                      values: [2]
                  }
              ],
              url: '/assets/test2.png'
          }
      ])
      window.filteredProducts$ = null;
      window.selectedFilters = new rxjs.BehaviorSubject([])
      
      function filterProducts() {
          filteredProducts$ = rxjs.combineLatest(products$, selectedFilters)
              .pipe(
                  rxjs.operators.map(
                  ([products, filters]) => products.filter(
                      product =>
                          product.filters.some(filter => filters.some(([filterName]) => filterName === filter.name.toLowerCase())
                              && filter.values.some(value => filters.some(([, filterId]) => filterId === value))
                          )
                  )
              )
          );
          filteredProducts$.subscribe(res => console.log('filtered:', res));
      }
      
      filterProducts()
      window.selectedFilters.next([...window.selectedFilters.value, ['test1', 1]]);
      window.selectedFilters.next([...window.selectedFilters.value, ['test2', 2]]);
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"&gt;&lt;/script&gt;

      【讨论】:

      • 感谢您的帮助 Józef !我正在尝试以角度实现您的解决方案,但我收到不同的错误,因为 selectedFilters 是一个数组,我在其上使用了不同的方法。我会继续实施它并让你知道:)
      • 您必须将 selectedFilters 更改为 BehaviorSubject,因为您的数据依赖于其最新状态。否则应用程序将不知道发生了什么
      • 没关系,但它呈现的结果与开始时相同。当我只选择一个过滤器时没关系,但现在当我添加另一个过滤器时我会得到更多结果。我认为它需要最后一个过滤器来进行过滤。当我记录我的 selectedFilters 时,我会看到所有选定的过滤器。
      • 您可以在开始时检查过滤器数组是否为空,如果是则返回所有产品
      • 我在添加或删除过滤器时启动该功能。数组为空时没关系。问题是当我在 behaviorSubject 的值中有多个过滤器时。该函数只使用一个过滤器而不是全部
      猜你喜欢
      • 1970-01-01
      • 2020-09-10
      • 1970-01-01
      • 2018-07-01
      • 1970-01-01
      • 2018-11-23
      • 2019-06-05
      • 1970-01-01
      • 2016-11-19
      相关资源
      最近更新 更多