1

I have a problem with observables. I've prepared stackblitz to simplify my problem.

I have 2 observables (obs1$, obs2$) and array of numbers. I want to wait for obs1$ to be completed and then loop through array and return observable of each element, run obs2$.

Here is the function code:

oneByOneObservables(): Observable<unknown> {
  const obs1$ = of(1, 2, 3);
  const arr = [4, 5, 6];
  const obs2$ = of(7, 8, 9);

  return obs1$.pipe(
    concat(() => arr.map((item) => of(item))),
    () => obs2$
  );
}

I've got an error :

No overload matches this call. The last overload gave the following error. Argument of type '() => Observable[]' is not assignable to parameter of type 'SchedulerLike | ObservableInput'. Property '[Symbol.iterator]' is missing in type '() => Observable[]' but required in type 'Iterable'.

Thanks for help

mackosz
  • 139
  • 1
  • 8
  • When extacly should obs2$ run? After each of the returned observables from obs1$ completed? – Lukasz Gawrys Dec 22 '21 at 14:48
  • @LukaszGawrys It doesn't matter. The most important for me is to run obs2$ and observables from array after obs1$ completed – mackosz Dec 22 '21 at 14:50
  • In ```obs1$``` you are emitting 1,2,3 - do you care about each of those values or do you only need to proceed with 3 as the last value emitted? Or you don't care about the values at all and only need to know if the Observable completed? – Lukasz Gawrys Dec 22 '21 at 15:18
  • Btw. your Stackblitz is not working out of the box due to some wrong imports. – Lukasz Gawrys Dec 22 '21 at 15:21
  • I don't care about these values. I only need to know if obs1$ completed. – mackosz Dec 22 '21 at 15:21

3 Answers3

1

So this will do the trick. I added some logs to track it down.

Here is also Stackblitz.

import { Component } from '@angular/core';
import { ChangeDetectionStrategy } from '@angular/core';
import { Observable, of, forkJoin } from 'rxjs';
import { concatMap, tap, last } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  styleUrls: ['./app.component.scss'],
  templateUrl: './app.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
  oneByOneObservables(): Observable<unknown> {
    const obs1$ = of(1, 2, 3).pipe(tap((v) => console.log('Obs1', v)));
    const arr = [4, 5, 6];
    const obs2$ = of(7, 8, 9);

    return obs1$.pipe(
      last(),
      tap((v) => console.log('Obs1 last value', v)),
      concatMap(() => forkJoin(arr.map((item) => of(item)))),
      tap((v) => console.log('Array of observables value', v)),
      concatMap(() => obs2$),
      tap((v) => console.log('Obs2 value', v))
    );
  }
}
Lukasz Gawrys
  • 1,234
  • 2
  • 8
1

Heres some code:

  • wait for obs1$ to be completed ✓
  • then loop through array and return observable of each element ✓ (This is currently a noop wasting a few cpu cycles. Creating an observable doesn't do anything, do you plan to subscribe to these? In order? All at once? Up to you, I guess)
  • run obs2$ ✓
function oneByOneObservables(): Observable<number> {
  const obs1$ = of(1, 2, 3);
  const arr = [4, 5, 6];
  const obs2$ = of(7, 8, 9);

  return obs1$.pipe(
    concatWith(defer(() => {
      arr.map((item) => of(item))
      return obs2$
    }))
  );
}

oneByOneObservables().subscribe(console.log);

output:

1
2
3
7
8
9

An example where you subscribe to the array of observables one after another.

function oneByOneObservables(): Observable<number> {
  const obs1$ = of(1, 2, 3);
  const arr = [4, 5, 6];
  const obs2$ = of(7, 8, 9);

  return obs1$.pipe(
    concatWith(defer(() => 
      concat(...arr.map((item) => of(item)))
    )),
    concatWith(obs2$)
  );
}

oneByOneObservables().subscribe(console.log)

output:

1
2
3
4
5
6
7
8
9
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21
0

You can use switchMap? Though I'm not sure what output from the observables you're looking for.

oneByOneObservables(): Observable<unknown> {
  const obs1$ = of(1, 2, 3);
  const arr = [4, 5, 6];
  const obs2$ = of(7, 8, 9);

  return obs1$.pipe(
    concat(() => arr.map((item) => of(item))),
    switchMap(() => obs2$)
  );
}
Mathew Berg
  • 28,625
  • 11
  • 69
  • 90