Reputation: 3082
I am learning RXjs and I want to understand how things work. So that's why I envisioned a scenario where I make Observable.of
and pass in an array. I know, Observable.from
would be more appropriate, but I'm learning how things work.
So, here's my code:
let sourceZero = Rx.Observable
.of([{name: 'James', age: 25}, {name: 'Angelina', age: 30}]);
sourceZero.subscribe(
x => console.log(x)
);
This works as expected: the subscribed value is array.
OK, so now I want to filter that array. While I know there are many other choices I can do that, e.g. in the subscribe part of the code, I want to filter it when creating observable. So, I used flatMap
, like this.
let source = Rx.Observable
.of([{name: 'James', age: 25}, {name: 'Angelina', age: 30}])
.flatMap(x => x)
.filter(x => x.age > 15)
While this does what I want, the result is not array anymore, but a stream of objects.
Now, my question is, how do I make an array out of this filtered data again? I don't want to pass single objects to the subscribe part, but an array, as was the case in the first example.
So, the result currently is:
[object Object] {
age: 25,
name: "James"
}
[object Object] {
age: 30,
name: "Angelina"
}
But I want it to be:
[[object Object] {
age: 25,
name: "James"
}, [object Object] {
age: 30,
name: "Angelina"
}]
Basically, I'm looking for a way to reverse flatMap
. I used .concatMap(x => Rx.Observable.of(x))
to no avail.
The code is available here: http://jsbin.com/lujeqowofi/1/edit
Upvotes: 3
Views: 3321
Reputation: 1816
To add on to @Serginho's answer, it might be cleaner to use an empty array as the seed
(first value)
const toArray = reduce((acc, x) => {
acc.push(x);
return acc;
}, Array<any>());
Upvotes: 0
Reputation: 7490
Reduce
operator is what you are looking for:
let source = Rx.Observable
.of([{name: 'James', age: 25}, {name: 'Angelina', age: 30}])
.flatMap(x => x)
.reduce((acc, x) => (acc instanceof Array) ? acc.push(x): [acc, x]);
Upvotes: 3
Reputation: 14574
I think you're misunderstanding what RxJS is about. Maybe if I walk you through what your code is doing, you'll see how you went wrong.
let source = Rx.Observable
.of([{name: 'James', age: 25}, {name: 'Angelina', age: 30}]) // 1.
.flatMap(x => x) // 2.
.filter(x => x.age > 15) // 3.
The key abstraction of Observable is that it's a "stream of values over time". By that we mean that observables emit single values, one value at a time. Those values being emitted may be complex objects or even arrays, but they are still single values.
In your code, when you said Observable.of() (step 1), you made an observable that can only emit a single value: your array.
Then, when you flatMapped (step 2), you did something i don't think you meant to do. The flatMap operator is meant to work with an Observable that emits Observables as its values. However, in your step 2, your original observable isn't emitting observables, it's emitting an array. But, flatMap is able to convert an array into an observable, so that's what it did.
But at this point, you now have an observable that will emit 2 values: first -> {name: 'James', age:25 }
and then --> {name: 'Angelina', age: 30}
. At this point, your observable is no longer dealing with arrays. It's dealing with individual objects.
If your aim is just to filter your original array to only include items that have an age > 15, then use a map on your array.
Upvotes: 2