I am new to rxjs and can't seem to find the correct operator for what I am trying to do.
In my example, I have an array I need to populate with results from an another observable, and once I have enough results in that array from making subscribe calls, I want to break and return the array.
// for reference, there is a class variable called keys
result = getResults(data, index).subscribe((result: any[]) => {
doSomethingWith(result);
});
getResults(data: any[], index: number) : Observable<any[]> {
obsFunctionThatGetsMeData(keys[index]).subscribe(result =>
data = data.concat(result);
if(data.length >= NEEDED_NUM_DATA) {
return Observable.of(data);
} else {
/* need to call obsFunctionThatGetsMeData(keys[index++]) and do the same logic as above. */
}
);
}
I know it is bad practice to put a subscribe in a subscribe, this is just the idea of what I'm looking for. I know takeWhile works on a condition, but I don't see how I can make extra calls if that condition fails. Does anyone know what operator is best for this kind of behavior?
Thanks!
Solved my own question Using recursion & switchmap
getResults(data: any[], index: number): Observable<any> {
return obsFunctionThatGetsMeData(keys[index]).pipe(
switchMap(result => {
if (result) {
data= data.concat(result);
if (data.length < NEEDED_NUM_DATA && index < keys.length) {
return getResults(data, ++index);
} else {
return Observable.of(data);
}
}
}));
}
I'm not an expert in RxJS, but I think something like this should be possible:
Rx.Observable.from(obsFunctionThatGetsMeData)
.take(NEEDED_NUM_DATA)
.subscribe(doSomethingWith);
public take(count: number): Observable Emits only the first count values emitted by the source Observable.
It's just an ideat to think about and doesn't pretend to be a working solution.
Looks like obsFunctionThatGetsMeData emits once (like an HTTP request), and you want to collect results from NEEDED_NUM_DATA number of these requests into array. And also it should append to whatever you already have in data parameter?
Try this:
getResults( data: any[], index: number ): Observable<any[]>
{
return Observable.range( index, NEEDED_NUM_DATA )
.concatMap( i => obsFunctionThatGetsMeData( keys[i] ) )
.reduce(( acc: any[], value ) => acc.concat( value ), data );
}
Promises are your friend here. (because you are working with single values).
Although you think you are working with a stream of results (the observables), you are actually just working with a single value at a time. Each value is independently operated on in a loop that pushes the result into an array. So NEEDED_NUM_DATA
independent variables consolidated into aa collection.
This code is much easier to rationalize about and to realize your goal:
var NEEDED_NUM_DATA = 4; var collection = []; async function getResults() { let url = 'https://jsonplaceholder.typicode.com/posts/'; let i = 1; while(collection.length <= NEEDED_NUM_DATA) { let result = await getsMeData(url + i++); collection.push(result); } } async function getsMeData(url) { const response = await fetch(url); const json = await response.json(); return json; } getResults() .then(()=>console.log(collection));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.