Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with RxJs BehaviorSubject's subscriber not being notified of value change

I am trying to use a RxJS BehaviorSubject that contains a boolean representing whether or not a user is connected/logged in the application.

Here is the component that subscribes to the new BehaviorSubject value i.e. true when the user has authenticated:

import {Component, OnInit} from '@angular/core';
import {CollapseDirective} from 'ng2-bootstrap';
import {PublicNavbarComponent} from './public.navbar.component';
import {PrivateNavbarComponent} from './private.navbar.component';
import {SessionService} from '../../session/session.service';

@Component({
    selector: 'navbar',
    templateUrl: 'app/shared/components/navbar.component.html',
    providers: [SessionService],
    directives: [PublicNavbarComponent, PrivateNavbarComponent, CollapseDirective]
})
export class NavbarComponent implements OnInit {

    constructor(private sessionService:SessionService) {
    }

    ngOnInit() {
        this.sessionService.authenticated$.subscribe({
            next: (value)=> this.isAuthenticated = value
        });
    }

    isAuthenticated:boolean = false;

    isCollapsed:boolean = true;
}

Here is the class/service containing the BehaviorSubject:

import {Injectable} from '@angular/core';
import {Http, Headers, RequestOptions} from '@angular/http';
import {Credentials} from '../shared/models/credentials.model';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import 'rxjs/Rx';

@Injectable()
export class SessionService {

    authenticated$:BehaviorSubject<boolean> = new BehaviorSubject(false);
    currentUserAccount;

    constructor(private http:Http) {
    }

    signin(credentials:Credentials) {
        let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
        let options = new RequestOptions({headers: headers});
        this.http.post('/api/signin', 'username=' + credentials.username + '&password=' + credentials.password, options)
            .subscribe(response=>
                this.setPersonalInfo(response.headers.get('x-auth-token'))
            );
    }

    setPersonalInfo(sessionToken) {
        localStorage.setItem('authenticated', 'true');
        localStorage.setItem('sessionToken', sessionToken);
        this.authenticated$.next(true);//next() from false to true
        this.http.get('/api/utils/current-useraccount')
            .subscribe(param => this.currentUserAccount = param);
    }
}

However this does not have the expected behavior: it seems that authenticated$ from session service is only true within setPersonalInfo function and isAuthenticated from NavbarComponent isn't notified at all when this.authenticated$.next(true) is invoked.

like image 415
balteo Avatar asked May 11 '16 00:05

balteo


People also ask

Can you subscribe to a BehaviorSubject?

You can either get the value by accessing the . value property on the BehaviorSubject or you can subscribe to it. If you subscribe to it, the BehaviorSubject will directly emit the current value to the subscriber. Even if the subscriber subscribes much later than the value was stored.

What happens if you don't subscribe to an observable?

If you don't subscribe nothing is going to happen. It's good to know that when you subscribe to an observer, each call of subscribe() will trigger it's own independent execution for that given observer. Subscribe calls are not shared among multiple subscribers to the same observable.

How do you find the current value of BehaviorSubject?

If you want to have a current value, use BehaviorSubject which is designed for exactly that purpose. BehaviorSubject keeps the last emitted value and emits it immediately to new subscribers. It also has a method getValue() to get the current value.

What is the difference between BehaviorSubject vs observable?

Observable is a Generic, and BehaviorSubject is technically a sub-type of Observable because BehaviorSubject is an observable with specific qualities. An observable can be created from both Subject and BehaviorSubject using subject.


1 Answers

It seems like you have multiple instances of SessionService. e.g. you provided it more than once and the instance that you call signin in is not the same instance as the one you injected in NavbarComponent.

It depends on your project design how you provide your services. Usually session services are singletons.
I recommend removing providers: [SessionService], from NavbarComponent.

like image 135
Abdulrahman Alsoghayer Avatar answered Sep 28 '22 15:09

Abdulrahman Alsoghayer