Reputation: 6406
I'd like to have confirmation that my use of observables vs. service initialisation is correct or isn't bested by a standard pattern. I'm new to observables.
Say that I have multiple services (e.g. profileService) depending on the readiness of an authService: Some data should only be loaded once a users is known.
The example profileService
should only "obtain the connected user's profile" when the authentication service
emits (observer.next('userConnected')
) the signal that a user successfully authenticated to the app.
My profileService
looks as follows:
constructor(@Inject(AuthenticationService) private authSvc: AuthenticationService){
this.authSvc.getAuthChangeObservable().subscribe(data => this.onAuthenticationChanged(data) );
}
While the authenticationService
is written as follows:
private authChange: Observable<any>;
private _authObserver: Observer<any>;
constructor(@Inject(FirebaseService) firebaseService: FirebaseService){
// Cookies or whatever allow .auth() to identify the user after a page refresh
// This causes a slight delay, see my question below
firebase.auth().onAuthStateChanged(user => {
if(user) this.onAuthenticationSuccessfull(user);
else this.onLogoutSuccessfull();
});
// Create an observable for auth status
this.authChange = new Observable(observer => {
this._authObserver = observer;
}).share();
}
getAuthChangeObservable(){
return this.authChange;
}
...
onAuthenticationSuccessfull(user){
this.authenticatedUser = user;
// This is mainly the way I found to warn other services they are clear to load the
// user-related data
this._authObserver.next('auth');
}
...
What bothers me: What if there was no delay for authentication? Or in case of a more generic service, how to make sure that all the services depending on it are ready and subscribed to the observable?
I understand there is a race condition with observable.share(). Unless mistaken, whenever share() is called at least once, the first "pending" event is fired. And I need to call .share() as I need a "hot" observable (i.e. to not re-run the observable's observer .next()
routine).
Thanks in advance for sharing advices and tips.
Upvotes: 2
Views: 1320
Reputation: 11360
You can use Subject to simplify the code and it is a hot observable and by default it doesn't cache past event (the share behaviour you described is more like BehaviorSubject)
in your authenticationService
public onAuth=new Subject()
constructor(@Inject(FirebaseService) firebaseService: FirebaseService){
firebase.auth().onAuthStateChanged(user => {
if(user) this.onAuth.next(user);
else this.onLogoutSuccessfull();
})
in your profile service
constructor(@Inject(AuthenticationService) private authSvc:
AuthenticationService){
// onlogin
this.authSvc.onAuth.filter(user=>user&&user.id).map(data=>
// you can perform other operation here e.g chain, combine
).subscribe()
// onlogout
this.authSvc.onAuth.filter(user=>!user).map(data=>
// you can perform other operation here e.g chain, combine
).subscribe()
}
Upvotes: 2