我试图围绕RxJS,我有一个问题。为了更好地理解一切是如何工作的,我开始使用Angular CLI生成一个新的空白Angular 4应用程序。在其中,我运行以下代码:
this.http.get('./src/app/data/products.json')
.map(res => res.json())
.filter((item: any) => {
let price = parseFloat(item.price);
return price < 5.0 && price >= 2.5;
})
.subscribe((list: Array<ProductModel>) => {
this.error = '';
this.products = list;
},
error => {
this.error = error;
});
问题是过滤器接收整个对象作为参数,我无法过滤单个项目。在非角度解决方案中使用RxJS,我使用了以下代码:
let products = Observable.create(observer => {
let xhr = new XMLHttpRequest();
let onLoad = () => {
let productsList = JSON.parse(xhr.responseText);
observer.next(productsList);
observer.complete();
}
xhr.addEventListener('load', onLoad);
xhr.open('GET', 'products.json');
xhr.send();
return () => {
console.log('cleanup');
xhr.removeEventListener('load', onLoad);
xhr.abort();
}
})
.flatMap(Observable.from)
.filter(item => {
let price = parseFloat(item.price);
return price < 5.0 && price >= 2.5;
});
let subscr = products.subscribe(
product => {
let li = document.createElement('li');
li.innerText = product.product_name + ' ' + product.price;
list$.appendChild(li);
},
error => {
console.log(`Error: ${error}`);
},
() => {
console.log('complete');
subscr.unsubscribe();
}
);
这里的区别在于我使用了flatMap,但是如果我在Angular版本中尝试相同的代码,我会得到: 类型'{(ish:ObservableInput,scheduler?:IScheduler)的参数:Observable; (ish:ArrayLike,...'不能分配给'(value:any,index:number)=&gt; ObservableInput'类型的参数。 参数'scheduler'和'index'的类型不兼容。 “号码”类型不能分配给“IScheduler”类型。
我只是想知道为什么同样的情况会产生不同的结果。 Angular是否使用不同风格的RxJS?在Angular版本中过滤结果的最有效方法是什么?
谢谢。
答案 0 :(得分:1)
下面我从SO回答中发现:Angular 2: How to use Observable filter
.map(content => response.json().data)
.concatMap(arr => Observable.from(arr))
.filter(item => item.Type === 5)
.subscribe(val => console.log(val))
如果您执行上述操作,则将数组转换回可观察流,并且可以对其应用过滤器。
但我仍然认为更好地使用数组的过滤函数而不是使用rxjs过滤函数
我喜欢这样,首先将响应映射到json,而不是订阅并为我的数组对象赋值,而不是应用过滤..
因为首先将响应转换为正确的对象类型,而不是过滤变得容易
this.http.get('./src/app/data/products.json')
.map(res => res.json())
.subscribe((list: Array<ProductModel>) => {
this.error = '';
this.products = list;
};
一旦你得到了对象,你也不需要使用rxJs过滤方法,你可以使用普通的数组过滤方法,如下所示
this.filterobj = this.object.filter(obj=> obj.property == val);
如果您的对象价格值已经浮动,那么
let filterProduct = this.products.
filter(o=> o.price < 5.0 && o.price >= 2.5);
或
FilterProduct(element, index, array) {
let price = parseFloat(element.price);
return price < 5.0 && price >= 2.5;
}
var filterProduct = this.ProductArray.filter(this.FilterProduct);
答案 1 :(得分:1)
getItems(): Observable<any>{
this.http.get('./src/app/data/products.json')
.map(res => {
const data = res.json(); // your GET returns array
return data.filter(item => parseFloat(item.price) >= 2.5 && parseFloat(item.price) < 5.0); // notice this is not Rxjs filter.
});
}
组件中的:
this.xxxService.getItems()
.subscribe(item => ...);
答案 2 :(得分:1)
第二次实施的原因是from
方法。为了更好地理解这一切是如何工作的,首先需要了解from
的工作原理。 from
接受一个iterable并发出每次迭代one at a time
。例如,如果你有
Observable.from([1, 2, 3]).subscribe(res => console.log('onNext: ', res));
您的输出将是
// onNext: 1
// onNext: 2
// onNext: 3
现在说我们添加了rxjs filter
运算符。过滤方法适用于每个发射值。
Observable.from([1, 2, 3])
.filter(res => {
console.log('filter: ', res);
return res === 3; // we only want items that === 3 to continue to next step in sequence
})
.subscribe(res => console.log('onNext: ', res);
您的输出将是
// filter: 1
// filter: 2
// filter: 3
// onNext: 3
在你的第一个实现中,你正在调用你的json,并让它说它返回[1, 2, 3]
。整个数组传递给rxjs filter
方法(不是每次迭代)。因此,您要检查整个阵列上的条件price < 5.0 && price >= 2.5
,这是您无法做到的。
正确的解决方案是在输出上执行js filter
方法
this.http.get('/./src/app/data/products.json')
.map(res => {
let data = res.json();
return data.filter((item: any) => {
let price = parseFloat(item.price);
return price < 5.0 && price >= 2.5;
});
})
.subscribe(list => {
this.products = list;
});
TLDR:rxjs filter
与原生js filter
的工作方式相同,您只需要知道您的可观察序列是如何发出的,这样您就知道应该选择哪一个。