【问题标题】:Using rxjs .filter() on array of tags in Angular5在 Angular5 中的标签数组上使用 rxjs .filter()
【发布时间】:2018-06-15 12:08:14
【问题描述】:

在 Angular5 中,如何使用rxjs .filter() 根据标签(在标签数组中)过滤 ObservableArray?

这是产品:

export class Product {
    id: string;    
    title: string;
    tags: string[];
}

这是我的 ProductService:

@Injectable()
export class ProductService {

    // get all products from the db
    getProductsAll (): Observable<Product[]> {

        // initiate the collection
        this.productsCollection = this.afs.collection( 'products', ref => ref.orderBy( "published, "desc" ) ); 

        // get the products from the initiated collection
        this.products = this.productsCollection.snapshotChanges()
        .map( actions => {
            return actions.map( a =>  {
                const id = a.payload.doc.id; 
                const data = a.payload.doc.data() as Product;
                return { id, ...data };
            })
        })

        // return the products as observable
        return this.products;
    }

到目前为止,一切都很好。现在以下是我卡住的地方:

// get selected products filtered by their tag
getProductsByTag (): Observable<Product[]> {

    var filteredProducts = this.getProductsAll()
        // I know the next line is what causes the problem...
        .map( products => products.filter( product => product.tags == "shoes" ));

    // return the filtered products as observable
    return filteredProducts;    
}

据我所知,问题在于tagsarray,而.filter function 不知道如何处理这个事实。

如何使用我的数组过滤它?

【问题讨论】:

  • 那么您希望过滤标准是"shoes" 是否 product.tags?在那种情况下,你不能只查找 "javascript find string is in array" 或类似的吗?
  • 是的,我确实希望过滤标准是"shoes" 是否在product.tags 中。我在想这一定是一个常见的用例,并且必须有一个最佳实践解决方案来解决这个问题?我现在已经确定我可以为.filter() 函数提供一个函数,并使用 lodash .find() 函数使其工作,如下所示:return _.find( product.tags, function(o) { return (o == "shoes"); });。但了解在这种情况下通常如何解决此问题仍然会有所帮助!
  • product.tags.indexOf('shoes') &gt; -1?这与 Angular 或 RxJS 无关。请注意,您调用的是 Array.filter不是 Observable.filter,因此我建议您为此查找标准 JS 方法。
  • 那我怎么改成 Observable.filter 呢?我的代码现在是:var filteredProducts = this.getProductsAll() .map( products =&gt; products.filter( product =&gt; return product.tags.indexOf( "shoes" ) &gt; -1; }));
  • 好吧,你真的希望它成为一个可观察的过滤器吗?这将过滤 stream,而不是其中的单个数组。否则,这只是 stackoverflow.com/q/237104/3001761 的欺骗。

标签: angular filter rxjs


【解决方案1】:

filter 也是一个 javascript 数组方法,也是 observable 方法,所以你不需要对filteredProducts 结构做任何事情(见下文,它按预期运行)。
只需使用.includes() 来测试所需的标签。
参考MDN Web Docs - Array.prototype.filter()

const Observable = Rx.Observable;
const productsAll = Observable.of([ 
  {tags: ['shoes','coats']}, 
  {tags: ['hats','coats']} 
]);
productsAll.subscribe(console.log); // show productsAll emits once as an array

const filteredProducts = productsAll
  .map(products => products.filter( product => product.tags.includes('shoes') ));

filteredProducts.subscribe(console.log)
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"&gt;&lt;/script&gt;

【讨论】:

    【解决方案2】:

    如果您希望您的方法实际返回按标签过滤的Observable&lt;Product&gt;,您应该首先flatMap 您的产品然后过滤。您仍然需要在标签上使用 Array.includes(或类似名称),因为它们是数组:

    getProductsByTag (tag: string): rx.Observable<Product> {
        return this.getProductsAll()
            .flatMap((products: Product[]) => rx.Observable.from(products))
            .filter((product: Product) => product.tags.includes(tag));  
    }
    

    你也可以flatMap你的标签,然后在标签上使用可观察的filter,但这不太可读,更冗长:

    getProductsByTag (tag: string): rx.Observable<Product> {
        return this.getProductsAll()
            .flatMap((products: Product[]) => rx.Observable.from(products))
            .flatMap((prod: Product) => rx.Observable.from(prod.tags), (product: Product, tag: string) => ({ product, tag }))
            .filter((data: any) => data.tag === tag)
            .map((data: any) => data.product)
    }
    

    最后,如果您真的希望 api 保持为 Observable&lt;Products[]&gt;,那么您只需这样做(仅使用 Array.filterincludes):

    getProductsByTag (tag: string): rx.Observable<Product[]> {
        return this.getProductsAll()
            .map((products: Product[]) => products.filter((product: Product) => product.tags.includes(tag)));  
    }
    

    【讨论】:

      猜你喜欢
      • 2023-01-25
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      相关资源
      最近更新 更多