How to implement BehaviorSubject with getter and setter in Angular 2
Asked Answered
E

1

11

I'm trying to implement in my LoginService a isLoggedIn boolean value of type BehaviorSubject together with getter and setter functions to get the value as an Observable / set the variable correctly via its BehaviorSubject. This is working, however it throws two errors in TSLint about "Type not assignable" and "Dublicate identifier". What would be the right way to define it without TSLint complaining about.

This is a stripped down version of the above mentioned code:

@Injectable()
export class LoginService {
  public isLoggedInSource = new BehaviorSubject<boolean>(false);
  public isLoggedIn: Observable<boolean> = this.isLoggedInSource.asObservable(); // Duplicate identifier 'isLoggedIn'.

  constructor(private http: Http) {}

  set isLoggedIn(logged): void { // Duplicate identifier 'isLoggedIn'.
    this.isLoggedInSource.next(logged);
  }

  get isLoggedIn(): Observable<boolean> { // Duplicate identifier 'isLoggedIn'.
    return this.isLoggedInSource.asObservable();
  }

  logout() {
    this.isLoggedIn = false; // Type 'boolean' is not assignable to type 'Observable<boolean>'.
  }

  login(body) {
    return this.http.post('/login', body)
        .map(res => {
                if (res.token) {
                  this.isLoggedIn = true; // Type 'boolean' is not assignable to type 'Observable<boolean>'.
                }
                return res;
              })
        .catch(err => Observable.throw(err););
  }
}
Emilia answered 7/10, 2016 at 10:18 Comment(2)
use different names for the property and getter/setters.Catchpole
also... there isn't really a point to having a getter/setter for a public property. The users of your class would be able to go around them anyway.Catchpole
T
8

When you use TypeScript getter/setter, you have to rename your property, so the property name should be different from getters/setters name.

Moreover, you can modify your code by setting your behaviorSubject as a private member of your service, and just expose your Observable.

@Injectable()
export class LoginService {

  private isLoggedInSource = new BehaviorSubject<boolean>(false);

  public _isLoggedIn: Observable<boolean> = this.isLoggedInSource.asObservable();

  constructor() {}

  set isLoggedIn(logged: boolean) {
    this.isLoggedInSource.next(logged);
  }

  get isLoggedIn() {
    return this._isLoggedIn;
  }

  logout() {
    this.isLoggedIn = false;
  }

  login() {
    this.isLoggedIn = true;
  }

} 

And you will be able to listen change in your component :

export class App {
  constructor(private loginService: LoginService) {

    loginService.isLoggedIn.subscribe(bool => console.log(bool));

    //Wait and simulate a login
    setTimeout(() => {
      loginService.login();
    }, 1200);

  }
}
Telles answered 7/10, 2016 at 13:21 Comment(5)
How would you solve error handling using this pattern?Lindbom
You can handle your errors on the service layer. But you cannot send something like new Error() to the subject stream, because it will kill it. You should split your architecture into two parts : a data generation flow and a data store. You can refer to this postTelles
I'm getting an error TS2380: 'get' and 'set' accessor must have the same type.Goodin
Thats correct, getter and setter should have the same type. So thats not an option.Valise
The above code won't work. You can't return an observable in the getter and have a boolean value as input in the setter for the same property.Fortran

© 2022 - 2024 — McMap. All rights reserved.