I have a general confusion with takeWhile.
What I want to achieve:
- Wait for fireAuthUser$ Observable to have a value
- once that happens, do some stuff
- if fireAuthUser$ Observable does not receive a value, cancel once component is left
export class AuthService implements OnDestroy {
fireAuthUser: BehaviorSubject<firebase.User | undefined> = new BehaviorSubject<firebase.User | undefined>(undefined);
public readonly fireAuthUser$: Observable<firebase.User | undefined> = this.fireAuthUser.asObservable();
private subscription?: Subscription;
constructor(public fire: AngularFireAuth) {
this.subscription = this.fire.authState.subscribe((fireAuthUser) => {
if (fireAuthUser) {
this.fireAuthUser.next(fireAuthUser);
// ...
}
});
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
doSomeStuff(): void {
//do some stuff
}
}
export class Foo implements OnInit {
constructor(public auth: AuthService) { }
ngOnInit(): void {
this.auth.fireAuthUser$.pipe(takeWhile((fireAuthUser) => fireAuthUser === undefined)).subscribe({
complete: () => this.auth.doSomeStuff()
});
}
}
The code above works. However, according to Angular/RxJs When should I unsubscribe from `Subscription` by using takeWhile, the observable execution will not be cancelled on ngDestroy of the component. So from my understanding, I need to manually set a .next value in my ngOndestroy, as otherwise my takeWhile would never cancel? Use case would be, i.e., if the user cannot login (no fireAuthUser exists)
However, I guess I cannot simply put a ngOnDestroy(): void { this.auth.fireAuthUser.next(undefined); }
as this would always erase my fireAuth user, which is a problem if the user does have a fireAuthUser object? So what should I do in this case? Or did I misunderstand this remark and my code is safe to use?
CodePudding user response:
Use TakeUntil. I love to create a BaseComponent that extend the class that have observable.
@Component({
template: ''
})
export abstract class BaseComponent implements OnDestroy {
protected unsubscribe: Subject<void> = new Subject();
ngOnDestroy(): void {
this.destroy();
}
private destroy(): void {
this.unsubscribe.next();
this.unsubscribe.complete();
}
}
after this class you can extend all the class you want, and use takeUntil method for destory observable when component is destory
export class LeadEditComponent extends BaseComponent implements OnInit {
ngOnInit(): void {
this.subscription = this.fire.authState
.pipe(
takeUntil(this.unsubscribe)
)
.subscribe((fireAuthUser) => {
if (fireAuthUser) {
this.fireAuthUser.next(fireAuthUser);
// ...
}
});
}
}
CodePudding user response:
Use takeUntil Operator. It will listen to this.auth.fireAuthUser$
untill current component is destroyed
import { Subject, takeUntil } from 'rxjs';
export class Foo implements OnInit{
private destroy$ = new Subject();
constructor() {}
ngOnInit(): void {
this.auth.fireAuthUser$
.pipe(takeUntil(this.destroy$))
.subscribe({
next: (data) => console.log(data),
complete: () => this.uponComplete(),
});
}
uponComplete() {
console.log('Finally completed');
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
}
See demo here (click on Go to Auth
timer will start and click on Home
it will unsubscribe)