Reputation: 571
I have a login()
method an AuthService
. What I want is to emit value from login()
method in AuthService
to handle value in NavbarComponent
:
export class AuthService extends AbstractRestService<any> {
user: AppUser = {id: null};
login(userName: string, password: string) {
return this.http
.post('/auth/login')
.pipe(
map(res => {
// here I want to emit value of Observable `anUser$`
// to send value to NavbarComponent
this.getAppUser(); // I want to throw Observable value to handle its value
// in NavbarComponent.ts
return true;
})
, catchError(this.handleError)
);
}
public getAppUser(): Observable<AppUser> {
return of(this.user);
}
}
My NavbarComponent.html
looks like this:
<li *ngIf="appUser$ | async as anUser">
{{ anUser?.name }}
</li>
My NavbarComponent.ts
looks like this:
appUser$: Observable<AppUser>;
async ngOnInit() {
this.appUser$ = this.auth.getAppUser();
}
What I want is to emit value from login()
method in AuthService
to handle value in NavbarComponent
, however value of appUser$
is not shown in NavbarComponent.html
.
Could you tell me what I am doing wrong?
Upvotes: 0
Views: 425
Reputation: 20454
By returning of(this.user)
from the method getUser()
all you're doing is returning the an observable with a single emission that is the value of this.user
at the time of the call.
If you want a stream that will be updated every time the user is updated by login then the best way to do that would be to use a Subject. A Subject is an Observable that whose emissions can be set from the outside.
You probably want to use a special subject called BehaviorSubject that will emit the last value as soon as it is subscribed too. This way if login was already called after the observable is subscribed to then the current value will still be returned. It is equivalent to a regular observable with startWith and shareReplay operator.
export class AuthService extends AbstractRestService<any> {
private readonly userSubject = new BehaviorSubject<{ id: string }>();
login(userName: string, password: string) {
return this.http
.post('/auth/login')
.pipe(
tap(res => userSubject.next(res)),
catchError(this.handleError)
);
}
getAppUser() {
/** do other work **/
return this.userSubject.asObservable();
}
}
Personally, I would just assign the variable directly by exposing userSubject
as a readonly field using this.userSubject.asObservable()
. Since you indicated you have additional logic occurring in getAppUser()
, you can just do the same call in the method.
Upvotes: 3
Reputation: 29315
do like this:
export class AuthService extends AbstractRestService<any> {
user: AppUser = {id: null};
login(userName: string, password: string) {
return this.http
.post('/auth/login')
.pipe(
map(res => {
this.userSource.next(res); // just call next with the user here
return true;
})
, catchError(this.handleError)
);
}
private userSource = new BehaviorSubject<AppUser>({id: null})
public getAppUser = this.userSource.asObservbale();
}
Upvotes: 3