Home > Blockchain >  Is there any way to combine following two Observable into a array of object in angular?
Is there any way to combine following two Observable into a array of object in angular?

Time:09-29

Suppose we have two observables

 student$ = from([
    {id: 1, name: "Alex"},
    {id: 2, name: "Marry"},
  ])

  address$ = from([
    {id: 1, location: "Chicago", sid: 1},
    {id: 2, location: "Florida", sid: 2},
  ])

I want to combine them into a array of object, the expected result would be following

  studentAddress = [
    {
      id: 1,
      name: "Alex",
      address: [
        {id: 1, location: "Chicago", sid: 1},
      ]
    },
    {
      id: 2,
      name: "Marry",
      address: [
        {id: 2, location: "Florida", sid: 2},
      ]
    },
  ]

CodePudding user response:

You would want to use flatMap for that (RxJs method). Your first value would be needed by the second one. I am pasting an example code snippet below for flatMap() and also the article link there are other methods as well (the below example is from the same article link)

let first = Observable.of(10);
first.flatMap((operand1) => {
  return Observable.of(operand1   10);
 })
.subscribe(res => this.flatMappedStreams = {msg: '10   10 = '   res});

Check out this article here for concat, combine, forkJoin etc

But the important thing is the way to achieve is RxJs Operators. You can also refer to their official docs for further understanding

CodePudding user response:

Considering your students$ and address$ observable emits an array of objects.

  address$ = of([
    { id: 1, location: 'Chicago', sid: 1 },
    { id: 2, location: 'Florida', sid: 2 },
  ]);

  students$ = of([
    { id: 1, name: 'Alex' },
    { id: 2, name: 'Marry' },
  ]);

Use RxJs function combineLatest: It Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables.

combineLatest will not emit an initial value until each observable emits at least one value

combineLatest(
  [this.students$, this.address$],
  (students, address) =>
    students.map((s) => ({
      ...s,
      address: address.filter((a) => a.sid === s.id),
    })) // combineLatest also takes an optional projection function
).subscribe(console.log);

imports used :

import { combineLatest, of } from 'rxjs';

Angular Demo by using combineLatest and forkJoin

Note: In your case instead of combibeLatest you can use forkJoin. forkJoin only emits value When all observables are complete, emit the last emitted value from each.

CodePudding user response:

Taken from your comment that the arrays are obtained from nested HTTP calls, I'd say you need

var { of } = rxjs;
var { switchMap, map } = rxjs.operators;

const students$ = of([
  {id: 1, name: "Alex"},
  {id: 2, name: "Marry"},
]);

const addresses$ = of([
  {id: 1, location: "Chicago", sid: 1},
  {id: 2, location: "Florida", sid: 2},
]);

const result$ = students$.pipe(
  switchMap(students =>
    addresses$.pipe(
      map(addresses => 
        students.map(student => ({
          ...student,
          address: addresses.filter(address => address.id === student.id)
        }))
      )
    )
  )
);

result$.subscribe(console.log);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://unpkg.com/[email protected]/bundles/rxjs.umd.min.js"></script>

  • Related