簡體   English   中英

在Angular5中的標簽數組上使用rxjs .filter()

[英]Using rxjs .filter() on array of tags in Angular5

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

據我所知,問題是tags是一個array ,而.filter function不知道該如何處理。

如何使用我的數組進行過濾?

filter也是一個javascript數組方法,也是可觀察的方法,因此您無需對filteredProducts結構做任何事情(請參見下文,此過程將按預期運行)。
只需使用.includes()測試所需的標簽。
Ref MDN Web文檔-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) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script> 

如果要讓您的方法實際返回按標記過濾的Observable<Product> ,則應首先對產品進行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<Products[]>那么您就可以這樣做(僅使用Array.filterincludes ):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM