3

I am trying to use Observables in angular 2 to watch for a simple change to a boolean called loggedIn which can be true or false. I am getting this error in TS.

Type 'boolean' is not assignable to type 'Subject'. Type 'boolean' is not assignable to type 'Observable'.

Can someone provide an alternative or tell me what I am doing wrong?

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import {Subject} from "../../node_modules/rxjs/src/Subject";
import {Observable} from "../../node_modules/rxjs/src/Observable";


@Injectable()
export class UserService {

  user: Subject<any>;
  user$: Observable<any>;
  //loggedIn: Subject<any>;
  //loggedIn$: Observable<any>;
  loggedIn: boolean;

  constructor(private http: Http) {
    this.user = new Subject();
    this.user$ = this.user.asObservable();
    this.loggedIn = false;
    //this.loggedIn = new Subject();
    //this.loggedIn$ = this.user.asObservable();


  }

  createAccount(user) {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');



    return this.http
      .post(
        '/api/accounts',
        JSON.stringify(user),
        { headers }
      )
      .map(res => res.json())
      .map((res) => {
        if (res['success']) {
          localStorage.setItem('auth_token', res['auth_token']);
          //this.loggedIn$ = true;
          //this.loggedIn.next(true);
        }

        return res['success'];
      });
  }

  login(user) {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');

    return this.http
      .post(
        '/api/authenticate',
        JSON.stringify(user),
        { headers }
      )
      .map(res => res.json())
      .map((res) => {
        console.log('Login Result:', res.user);
        if (res["success"]) {
          localStorage.setItem('jwt', res.token);
          //set user service info...
          //this.user.next(res.user[0]);
          //this.loggedIn.next(true);
        }
        return res;
      });
  }

  updateAccount(user) {
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
    headers.append('x-access-token', localStorage.getItem('jwt'));

    console.log('PAYLOAD FOR UPDATE USER: ' , user);

    return this.http
      .put(
        '/api/accounts/' + user._id,
        JSON.stringify(user),
        { headers }
      )
      .map(res => res.json())
      .map((res) => {
        if (res['success']) {
          localStorage.setItem('auth_token', res['auth_token']);
          //this.loggedIn$ = true;
          //this.loggedIn.next(true);
        }

        return res['success'];
      });
  }

  logout() {
    localStorage.removeItem('auth_token');
    //this.loggedIn$ = false;
    //this.loggedIn.next(false);
  }

}

Please see the lines that are commented out. I need to subscribe to the Observable which will return true or false at any time.

2
  • 4
    See stackoverflow.com/questions/37089977/… for an example. You need to use next() and not assignment. Commented Aug 16, 2016 at 2:26
  • I was able to fix this based on Mark's reference. loggedIn = new Subject<boolean>(); loggedIn$: Observable<any>; THEN: this.loggedIn.next(false); Commented Aug 16, 2016 at 3:13

1 Answer 1

1

Use a subject to emit values. Use private loggedIn: ReplaySubject<boolean> new ReplaySubject(1); if you want to emit the state on subscription but do not want an initial state. If you want an initial state, use private loggedIn: BehaviorSubject<boolean> = new BehaviorSubject(false);.

Do not present subjects as public properties - only expose observables, i.e. loggedIn$: Observable<boolean> = this.loggedIn.asObservable();. Consumers of the service should only be able to alter the state through public methods in a controlled way.

These are some of the parts of your service that are concerned with the logged in state.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class UserService {
  private readonly loggedIn: ReplaySubject<boolean> = new ReplaySubject(1);

  readonly loggedIn$: Observable<boolean> = this.loggedIn.asObservable();

  constructor(private readonly http: HttpClient) {}

  login(user): Promise<any> {
    return this.http
      .post(/* (...) */)
      .map((res) => {
        if (res["success"]) {
          this.loggedIn.next(true);
        }
      });
  }

  logout(): void {
    this.loggedIn.next(false);
  }
}

So we expose the state as an Observable<boolean> in the public loggedIn$ property which is only the Observable interface of the private loggedIn subject property. The state is changed by emitting a value to loggedIn which is observed by subscribers of loggedIn$.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.