Tal Humy
Tal Humy

Reputation: 1227

RxJS - Return subject with value

I've created a authentication service which components can subscribe to permission changes (login/logout/role change ,etc). In isAuthenticated function, I'm returning a subject. The problem is that I want to return the subject with a value (like Observable.of. For now, I'm using setTimeout.

@Injectable()
export class AuthenticationService {
  constructor(private credentials: CredantialsStorageService,
    private oauthService:OAuth2Service,
    private secureHttp: SecureHttpService) {}
  
  private isAuthenticatedSubject: Subject<boolean> = new Subject<boolean>();

  login(email:string, password: string, remember?:boolean ): Observable<boolean> {
      return this.oauthService.login(email, password)
        .flatMap(() => this.getAndStoreUserCredantials())
        .map((userCredantials: any) =>  {
          this.isAuthenticatedSubject.next(true);
          return true;
        })
 
  }

  logout(): Observable<void> {
    return this.secureHttp.post('/logout', null)
      .finally(() => {
        this.credentials.clear();
        this.oauthService.clear();
        this.isAuthenticatedSubject.next(false);
      })
      .map(() =>  null);
  }

  isAuthenticated(): Observable<boolean> {
    setTimeout(() => { //Hack - find a way to change this
      this.isAuthenticatedSubject.next(this.oauthService.isAuthenticated());
    })
    return this.isAuthenticatedSubject;
  }

  private getAndStoreUserCredantials() {
    return this.secureHttp.get('/user/info')
      .map((res:Response) => {
        let userCredantials = res.json();
        this.credentials.set(userCredantials);
        return userCredantials;
      })
  }
}

Upvotes: 3

Views: 7388

Answers (3)

martin
martin

Reputation: 96891

I think the easiest way to do this is using the startWith() operator:

isAuthenticated(): Observable<boolean> {
    return this.isAuthenticatedSubject.startWith(this.oauthService.isAuthenticated());
}

You could also use BehaviorSubject or ReplaySubject but these only repeat a value that went through them already. Maybe also have a look at this answer for more detailed description what's the difference: Does startWith() operator turns Observable into ReplaySubject(1)?.

Upvotes: 2

CozyAzure
CozyAzure

Reputation: 8468

You can return it as an Observable using .asObservable().

isAuthenticated(): Observable<boolean> {
    setTimeout(() => { //Hack - find a way to change this
        this.isAuthenticatedSubject.next(this.oauthService.isAuthenticated());
    })
    return this.isAuthenticatedSubject.asObservable();
}

Edit:

If you want to however, add some delay for into your method, you could use Obersvable.delay(), and then use .do() operator:

isAuthenticated(): Observable<boolean> {
    Observable
        .delay(1000) //delay for 1000ms
        .do(() => {
            this.isAuthenticatedSubject.next(this.oauthService.isAuthenticated());
        });
    return this.isAuthenticatedSubject.asObservable();
}

Upvotes: 2

Konstantin Vitkovsky
Konstantin Vitkovsky

Reputation: 1228

If you'd like to set an initial value for the Subject, you could use a BehaviorSubject. The only difference is that you pass your initial value to BehaviorSubject constructor.

import { BehaviorSubject } from 'rxjs/BehaviorSubject';

const subject = new BehaviorSubject(42);
subject.subscribe((value) => console.log(value));
// 42

subject.next(84);
// 84

Upvotes: 1

Related Questions