web-dev-qa-db-fra.com

Tableau de RxJs d'Observable à Tableau

Pour une application Web écrite avec Angular2 dans TypeScript, je dois travailler avec RxJs Observables.
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 Posts de la fonction onNext.

Je peux facilement mapper de Observable<Array<User>> à Observable<Array<Observable<Array<Post>>>> en utilisant
map((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?

18
Springrbua

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];
  (...)
});
27

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>

7
Julian FARHI

Utilisez forkJoin sur ce tableau d'observables, alors ce sera un observable de tableau.

1
r ne

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))

https://arrayofobservablesexamp.stackblitz.io

0