Marcello di Simone Marcello di Simone - 2 months ago 128
TypeScript Question

How to implement BehaviorSubject with getter and setter in Angular 2

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););
}
}

Answer

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);

  }
}