0

We are using .pipe(takeUntil) in the logincomponent.ts. What I need is, it should get destroyed after successful log in and the user is on the landing page. However, the below snippet is being called even when the user is trying to do other activity and hitting submit on the landing page should load different page but the result of submit button is being overridden and taken back to the landing page.

enter code hereforkJoin({
  flag: this.auth
    .getEnvironmentSettings('featureEnableQubeScan')
    .pipe(take(1)),
  prefs: this.auth.preferences.pipe(take(1)),
}).subscribe(
  (result: any) => {
    this.qubeScanEnabled = result.flag.featureEnableQubeScan;
    this.userPrefs = result.prefs;
    // check to see if we're authed (but don't keep listening)
     this.auth.authed
      .pipe(takeUntilComponentDestroyed(this))
      .subscribe((payload: IJwtPayload) => {
        if (payload) {
           this.auth.accountO
            .pipe(takeUntilComponentDestroyed(this))
            .subscribe((account: IAccount) => {
                if (this.returnUrl) {
                  this.router.navigateByUrl(this.returnUrl);
                } else {
                      this.router.navigate(['dashboard']);
                    }
                  }
                }
              }
        }
);

 ngOnDestroy() {}

Custom Code:

    export function takeUntilComponentDestroyed(component: OnDestroy) {
  const componentDestroyed = (comp: OnDestroy) => {
    const oldNgOnDestroy = comp.ngOnDestroy;
    const destroyed$ = new ReplaySubject<void>(1);
    comp.ngOnDestroy = () => {
      oldNgOnDestroy.apply(comp);
      destroyed$.next(undefined);
      destroyed$.complete();
    };
    return destroyed$;
  };

  return pipe(
    takeUntil(componentDestroyed(component))
  );
}

Please let me know what I am doing wrong. Versions: rxjs: 6.5.5 Angular:10.0.8 Thanks

Avi
  • 65
  • 1
  • 8
  • Add take(1) operator, if you stop listening after first stream. – Developer Oct 10 '20 at 20:45
  • my understanding is ".pipe(takeUntilComponentDestroyed(this))" would take care of this. Correct me if i am wrong. Thanks – Avi Oct 10 '20 at 23:01
  • It would be helpful to create a StackBlitz that illustrates your problem. – Andrei Gătej Oct 11 '20 at 09:13
  • 1
    Kind suggestion, get rid of the nested subscriptions.If you do so you can remove the custom operator and simply use the common `takeUntil(unsubscribe$)` approach. – MoxxiManagarm Oct 12 '20 at 08:56
  • `takeUntil()` is waiting for destroyed$ to emit and I'm not sure `undefined` counts as an emission. Maybe try `destroyed$.next(1);` (Change the declaration as well) and see if you have better luck. – Mrk Sef Oct 12 '20 at 16:40

1 Answers1

0

I've done a first pass at creating a stream that doesn't nest subscriptions and continues to have the same semantics. The major difference is that I can move takeUntilComponentDestroyed to the end of the stream and lets the unsubscibes filter backup the chain. (It's a bit cleaner and you don't run the same code twice every time through)

It's a matter of taste, but flattening operators are a bit easier to follow for many.

enter code hereforkJoin({
  flag: this.auth
    .getEnvironmentSettings('featureEnableQubeScan')
    .pipe(take(1)),
  prefs: this.auth.preferences.pipe(take(1)),
}).pipe(
  tap((result: any) => {
    this.qubeScanEnabled = result.flag.featureEnableQubeScan;
    this.userPrefs = result.prefs;
  }),
  mergeMap((result: any) => this.auth.authed),
  filter((payload: IJwtPayload) => payload != null),
  mergeMap((payload: IJwtPayload) => this.auth.accountO),
  takeUntilComponentDestroyed(this)
).subscribe((account: IAccount) => {        
  if (this.returnUrl) {
    this.router.navigateByUrl(this.returnUrl);
  } else {
    this.router.navigate(['dashboard']);
  }
});

This function doesn't create another inner stream (destroyed$). This way is a bit more back to the basics so it should be easier to debug if you're not getting the result you want.

export function takeUntilComponentDestroyed<T>(comp: OnDestroy): MonoTypeOperatorFunction<T> {
  return input$ => new Observable(observer => {
    const sub = input$.subscribe({
      next: val => observer.next(val),
      complete: () => observer.complete(),
      error: err => observer.error(err)
    });
    const oldNgOnDestroy = comp.ngOnDestroy;
    comp.ngOnDestroy = () => {
      oldNgOnDestroy.apply(comp);
      sub.unsubscribe();
      observer.complete();
    };
    return { unsubscribe: () => sub.unsubscribe() };
  });
}
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21