undefined
undefined

Reputation: 6854

RxJS switchMap with the take operator

I have a method that returns the following observable.

class Service {

  getData() {
     // the select observable will fire on every form change
     return this.store.select('filters').switchMap(filters => {
        return this.http.get('call the api with the filters')
     }).take(1);

  }
}

In my component, I call this method on submit.

class Component {

   submit() {
     this.service.getData().subscribe(...)
   }
}

The problem is that after I call submit once, I see two HTTP calls in the second submit. My question is if the take(1) operator, in this case, is killing both the inner and the outer observables?

Upvotes: 4

Views: 4627

Answers (2)

Muhamed Karajic
Muhamed Karajic

Reputation: 63

Look at the following code:

readonly propertyA$ = new BehaviorSubject<string | null>('A');
  readonly propertyB$ = new ReplaySubject<string[] | null>(1);

  constructor(ref: ChangeDetectorRef) {
    setTimeout(() => {
      this.propertyB$.next(['B']);
    }, 2000);

    setTimeout(() => {
      this.propertyB$.next(['B2']);
    }, 3000);

    setTimeout(() => {
      this.propertyA$.next('A2');
    }, 4000);

    setTimeout(() => {
      this.propertyB$.next(['B3']);
    }, 5000);

    setTimeout(() => {
      this.propertyB$.next(['B4']);
    }, 6000);

    setTimeout(() => {
      this.propertyA$.next('A3');
    }, 7000);

    setTimeout(() => {
      this.propertyB$.next(['B5']);
    }, 8000);


    this.propertyA$.pipe(switchMap(propertyA => {
      return this.propertyB$.pipe(
        take(1), //and without
        map(propertyB => ([propertyA, propertyB] as [string, string[]]))
      )
    })).subscribe(x => console.log('propertyA & propertyB (combineLatestFrom): ', x));
}

Without take(1):

A, B
A, B2
A2, B2
A2, B3
A2, B4
A3, B4
A3, B5

With take(1):

A, B
A2, B2
A3, B4

Upvotes: 0

martin
martin

Reputation: 96889

This is completely unrelated to the take() operator. You're simply making two subscriptions to the same source Observable with two chains.

The take(1) operator then just accepts only the first item emitted and send complete notification.

Right now you have the following:

           +-- switchMap --- take --> subscribe()
-- store --+
           +-- switchMap --- take --> subscribe()

So the same value is pushed to two different chains with two different switchMap's.

While you probably want something like this:

                         +--> subscribe()
-- store --- switchMap --+
                         +--> subscribe()

For example you have this (instead of do() you have switchMap()):

const subject = new Subject();
const obs = subject
    .do(console.log);

obs.subscribe(i => console.log('next:', i));
obs.subscribe(i => console.log('next:', i));

subject.next(1);

... which prints the following. Notice that the do() operator received two values:

1
next: 1
1
next: 1

Instead you could use:

const obs = subject
    .do(console.log)
    .publish()
    .refCount();

or this ...

const multicast = new Subject();
const obs = subject
    .do(console.log)
    .subscribe(multicast);

multicast.subscribe(...);

or this ...

const obs = subject
    .do(console.log)
    .publish();
obs.connect();

or whatever depending on what you need.

This goes through just one do():

1
next: 1
next: 1

Upvotes: 2

Related Questions