0

I have a merged stream of observables,

const nextClickHandler$ = merge(doA$, doB$, doC$),

do A$/B$/C$ are observables which makes HTTPRequests or performs some sideeffects, they operate on some mutually exclusive conditions, where either doA$/doB$/doC$ are active and perform the network calls / side-effects.

The use-case is, on the click of the next button, do either A/B/C, I am facing an issue on how to subscribe to this merged observable, if I subscribe to it before-click of next, i.e.

ngOnInit(){
    this.nextClickHandler$.subscribe()
}

This will be eagerly evaluating those mutually exclusive conditions and executing, without even clicking next,

I tried subscribing on click of goForward:

 goForward(): void {
        if (this.getCurrentStep() == 1) {
            if (this.validateForm()) {\
                //performs side-effects for either A$/B$/C$
                this.nextClickHandler$.subscribe();  
            }
            return;
        }

But now, when I am on the Step I again, it doesnt wait for the click of the next, since it is a long-living subscription, it just eagerly executes the behaviour, which is not what I want, I want them to be lazy-executed only when clicking next, I tried take(1) but that does not fix the issue, How can I achieve this?

3
  • Question: does it work when you place subscribe in goForward()? So your issue is you want to cancel subscription when they go back?
    – BizzyBob
    Commented Apr 1, 2021 at 15:24
  • I can definitely do so, when going back I can unsubscribe, it does work when I subscribe in goForward(), but is there a better way than managing the subscriptions manually, I don't like the idea of creating a subscription every time on the click of the next.
    – AndyW
    Commented Apr 1, 2021 at 15:29
  • There is probably a better way. It's hard to say without know more about your flow. You could possibly have a currentStep$ observable that internally uses switchMap() to subscibe to whatever observable is relevant to each step. I can elaborate if you share more details / code. If you could put it in a StackBlitz, that would make it easier to help you. :-)
    – BizzyBob
    Commented Apr 1, 2021 at 15:34

2 Answers 2

1

You can try to create an Observable from click event of the button, using fromEvent:

 <button #sbtn>
      Subscribe
    </button>

 @ViewChild('sbtn', { static: true }) sbtn: ElementRef;
 this.clickBtnEvent$ = fromEvent(this.sbtn.nativeElement, 'click');

and than on init (or after view init) you subscribe to that Observable:

this.clickBtnEvent$.pipe(
  mergeMap(() => nextClickHandler$)
).subscribe( /* some logic*/);

This Observable will emit only when you click the button, actualy every time you click on it.

0

If creating multiple subscription variables is not something to your liking then,

switchMap() is a good example to use, but if you want to keep using merge() or mergeMap, try using takeUntil() operator. You need not create a subscription variable every time.

You create only once and destroy once, but you can use it many times in the same page code.

// Step-1: Create a destroy variable
destroy$: Subject<any> = new Subject();

// Step-2: Use it how many times you want

obs1$.pipe(takeUntil(this.destroy$)).subscribe();
obs2$.pipe(takeUntil(this.destroy$)).subscribe();
obs3$.pipe(takeUntil(this.destroy$)).subscribe();
.
.
.
so on... 

// Step-3 : Destroy the subject

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

If you want to merge observables, you can also use combineLatest() operator, where you can subscribe to multiple observables at once. Something like this:

combineLatest(obs1$, obs2$, obs3$)
   .takeUntil(this.destroy$)
   .subscribe(([obs1Data, obs2Data, obs3Data]) => {})

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.