Pour une application Web écrite avec Angular2 dans TypeScript, je dois travailler avec RxJs Observable
s.
Comme je n’avais jamais utilisé rxjs auparavant et que je suis novice en programmation réactive en général, j’ai parfois des difficultés à trouver le bon moyen de faire certaines choses spécifiques.
Je suis maintenant confronté à un problème. où je dois convertir un Array<Observable<T>>
en un Observable<Array<T>>
.
Je vais essayer de l'expliquer avec un exemple:
- J'ai une Observable
, ce qui me donne une liste de Users
(Observable<Array<User>>
)
- La User
- class a une fonction getPosts
renvoyant un Observable<Array<Post>>
.
- Je dois mapper le Observable<Array<User>>
à un Observable<Array<Post>>
pour évaluer tous les Post
s de la fonction onNext
.
Je peux facilement mapper de Observable<Array<User>>
à Observable<Array<Observable<Array<Post>>>>
en utilisantmap((result : Array<User>) => result.map((user : User) => user.getPosts()))
ans Je peux convertir un Array<Array<Post>>
en un Array<Post>
.
Cependant, je ne trouve pas la bonne façon de mapper le Observable<Array<Observable<Array<Post>>>>
dans un Observable<Array<Array<Post>>>
Jusqu'à présent, j’utilisais la fonction combineLatest
avec flatMap
.
Cela a semblé fonctionner et l'éditeur que j'ai utilisé (éditeur Atom) n'affichait aucune erreur. Cependant maintenant j'utilise Netbeans, ce qui me montre une erreur dans ce code. La compilation du code à l'aide de "tsc" entraîne également des erreurs.
Le look ressemble à ceci:
Argument of type '(result: Post[]) => void' is not assignable to parameter of type 'NextObserver<[Observable<Post>]> | ErrorObserver<[Observable<Post>]> | CompletionObserver<[...'.
Type '(result: Post[]) => void' is not assignable to type '(value: [Observable<Post>]) => void'.
Donc ma question est:
Comment puis-je "aplatir" une Array
de Observables
en une Array
?
L'opérateur flatMap
permet de le faire. Je ne comprends pas bien ce que vous essayez de faire mais je vais essayer de vous donner une réponse ...
Si vous voulez charger tous les
getPostsPerUser() {
return this.http.get('/users')
.map(res => res.json())
.flatMap((result : Array<User>) => {
return Observable.forkJoin(
result.map((user : User) => user.getPosts());
});
}
Observable.forkJoin
vous permet d'attendre que toutes les données observables aient reçu des données.
Le code ci-dessus suppose que user.getPosts()
renvoie un observable ...
Avec cela, vous recevrez un tableau de tableau de messages:
this.getPostsPerUser().subscribe(result => {
var postsUser1 = result[0];
var postsUser2 = result[1];
(...)
});
Vous pouvez utiliser la fonction apply sur la méthode rxjs que vous voulez, comme ceci:
const source1 = Rx.Observable.interval(100)
.map(function (i) { return 'First: ' + i; });
const source2 = Rx.Observable.interval(150)
.map(function (i) { return 'Second: ' + i; });
const observablesArray = [source1, source2];
const sources = Rx.Observable.combineLatest
.apply(this, observablesArray).take(4)
/* or you can write it without "apply" this way:
const sources = Rx.Observable
.combineLatest(...observablesArray)
.take(4)
*/
sources.subscribe(
(response) => {
console.log(response);
}
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>
Utilisez forkJoin sur ce tableau d'observables, alors ce sera un observable de tableau.
Voici un exemple de code utilisant [email protected]
import { of, forkJoin} from 'rxjs';
import { Observable } from 'rxjs'
const source:Array<Observable<String>> = [of('A'), of('B'), of('C') ];
forkJoin(source).subscribe( (x)=> console.log(x))