[英]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.filter
並includes
):
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.