角度4 + RxJS过滤

时间:2017-12-08 19:08:58

标签: angular rxjs

我试图围绕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版本中过滤结果的最有效方法是什么?

谢谢。

3 个答案:

答案 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的工作方式相同,您只需要知道您的可观察序列是如何发出的,这样您就知道应该选择哪一个。