【问题标题】:Angular Observable filteringAngular Observable 过滤
【发布时间】:2020-09-03 08:12:11
【问题描述】:

我遇到了一个用数组过滤 observable 的问题。 让我解释一下……

我有:

  • products$:可观察的;
  • filteredProducts$:可观察的;
  • selectedFilters = [['过滤器名称', idOfFilter], ['过滤器名称', idOfFilter]]; (开头为空)

这是一个产品对象的结构:

这是我的过滤器数组的结构

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

到目前为止,我一直在写这篇文章,但我不知道如何真正过滤我的 Observable...

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

    public tempProducts$: Observable<Product[]>;
    public selectedFilters = [];

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

    ngOnInit() {
        this.store.dispatch(new GetAllFilters());
        this.uns = this.products$.subscribe(res => console.log('products from filter component', res));
    }

    private filterProducts() {
      this.filteredProducts$ = this.products$.pipe(
          map(productsArray =>
              productsArray.filter(product => {
                  product.filters.filter(filters => filters.values.includes(5));
              }))
      );
  }

}

【问题讨论】:

    标签: angular filter rxjs observable


    【解决方案1】:

    我认为这可能是一个解决方案:

    this.filteredProducts$ = products$.pipe(
      map(
        productsArr => productsArr.filter(
          p => 
            p.filters.some(f => selectedFilters.some(([selectedF]) => selectedF === f.name) // Filter name
            && f.values.some(value => selectedFilters.some(([, filterId]) => filterId === value)) // Filter id
        )
      ),
    )
    

    【讨论】:

    • 谢谢,但是过滤器第二行中的“f”呢? f.values.some.... f 未知
    • 这是来自product.filtersfilter 对象。 unknown 是什么意思?
    • 找不到名字'f'
    • 我认为 f 不在独家新闻中 private filterProducts() { this.filteredProducts$ = this.products$.pipe( map( productsArr => productsArr.filter( p => p.filters .some(f => this.selectedFilters.some(([selectedF]) => selectedF === f.name)) // 过滤器名称 && f.values.some(value => this.selectedFilters.some(([ , filterId]) => filterId === value)) // 过滤器 id ) ) ); this.filteredProducts$.subscribe(res => console.log('filtered:', res)); }
    • 对不起,第一行有一个额外的)。现在应该没事了。
    【解决方案2】:

    您可以使用combineLatest 创建一个可观察流,只要任何源可观察对象发出新值,该流就会更新。

      filteredProducts$ = combineLatest(this.products$, this.filters$).pipe(
        map(([products, selectedFilters]) => {
          return products.filter(p => {
            // actual filter logic goes here
            return p.filters.some(pf => selectedFilters.some(f => pf == f));
          });
        })
      );
    

    看看这个工作StackBlitz

    【讨论】:

    • 感谢@BizzyBob,这可能是一个不错的解决方案,我一直记在心里^^。但是,我必须使用 selectedFilters 数组过滤我的过滤器
    【解决方案3】:

    您可以在ngOnInit() 中声明您的filteredProducts$

    ngOnInit() {
       this.filteredProducts$ = this.products$.pipe(
          switchMap(products => {
             return this.filters$.pipe(
                startWith([]),
                map(filters => {
                    return products.filter(/* apply your filter*/)
                })
             );
          })
       )
    }
    

    因此,每次您的filters$ 更改时,都会应用过滤器。 使用startWith(),您可以说 Observable filters 在开始发出源 Observable 发出的项目之前发出一个空数组。

    编辑:啊,您已经将filters$ 用作@Select。我更新了我的答案。

    【讨论】:

    • 非常感谢您的快速回复。我明白你为什么这么告诉我,但是我不知道如何制作过滤器,因为我必须将选定的过滤器映射到你说我要过滤的地方
    • 所以如果我理解正确的话,你想用一组过滤器过滤一组产品。一个产品还有一组过滤器,它们有一组值?运行时将是可怕的。我猜你必须过度考虑你的工作流程。
    • 此解决方案在filters$ 更改时不会更新,它只会在products$ 更改时更新。我认为combineLatest 非常适合这种情况。这样,每当products$filters$ 发生变化时,filteredProducts$ 都会相应地更新。请参阅下面的答案。
    • @BizzyBob 我的例子确实有效。每当行为主题发生变化时,它都会更新。看一个小例子:stackblitz.com/edit/angular-ivy-5ziu8s
    • 你的 stackblitz 与上面的有点不同。我在您的stack blitz 上制作了 cmets。我并不是说这不起作用,它会在products$ observable 获得新值时起作用,但我认为在这种情况下,他希望它在filters$ observable 发出新值时更新。
    猜你喜欢
    • 2018-07-15
    • 2021-07-23
    • 1970-01-01
    • 2015-08-27
    • 2018-03-21
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多