Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make an observer to return as observable?

I'm new to rxjs and would like some help on how to solve this.

I want to pass an Observer to onAuthStateChanged(), which takes an observer object. The observer would do some work and emit a boolean value such that the boolean value can be returned as an Observable. How do I go about implement this bridge of from observable to observer?

export class AuthGuard implements CanActivate {

constructor(private firebase: FirebaseService, private router: Router) {
}

canActivate(): Observable<boolean> {
    this.firebase.auth.onAuthStateChanged(/* an observer */)
    return /* an Observable<boolean> */
    }
}
like image 442
Sam Avatar asked Aug 23 '16 23:08

Sam


People also ask

How do you make an Observable?

The process to create an Observable is fairly straightforward. First of all, we need to import Observable from rxjs. Then, we create an Observable by calling the new Observable constructor that takes one argument. In the following example, we create an Observable that emits a number every second to a subscriber.

What does an Observable return?

An Observable is basically a function that can return a stream of values to an observer over time, this can either be synchronously or asynchronously. The data values returned can go from zero to an infinite range of values.

Can we convert promise to Observable?

You can add a wrapper around promise functionality to return an Observable to observer. Creating a Lazy Observable using defer() operator which allows you to create the Observable only when the Observer subscribes.


2 Answers

Since onAuthStateChanged takes an observer as input, and returns the teardown function, we can simply wrap it with:

Rx.Observable.create(obs => firebase.auth().onAuthStateChanged(obs))

Actually for strange reasons this might not work, and we can do:

var onAuthStateChanged$ = Rx.Observable.create(obs => {
  return firebase.auth().onAuthStateChanged(
    user => obs.next(user),
    err => obs.error(err),
    () => obs.complete());
})

Now if you are unfamiliar with the Observable.create function, let me explain: create takes a onSubscribe function that hands in an observer and returns the teardown function. Doesnt that sounds very familiar with now onAuthStateChanged is build up? You hand in nextOrObserver and it returns the teardown!

(Now for strange reasons nextOrObserver did not accept an observer for me, so i switched to giving it a next function instead. Hench the code above.)

With the onAuthStateChanged$ set up, we can transform the stream using operators. All operators do is transform one observable into another, and RxJs has several dozen of these. In your case, it might look like this:

canActivate(): Observable<boolean> {
  onAuthStateChanged$
    .do(user => {if (!user) { this.router.navigate(['/login']); } })
    .map(user => !!user)
    .do(user => console.log('Authenticated?', user))
}
like image 170
Dorus Avatar answered Nov 15 '22 09:11

Dorus


To benefit others, here's what I ended up writing and it seems to work well.

import 'rxjs/add/operator/do';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';

import { Observable } from 'rxjs/Observable';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { FirebaseService } from '../shared/firebase.service';


@Injectable()
export class AuthGuard implements CanActivate {

    loggedInSubject: ReplaySubject<any>;

    constructor(private firebase: FirebaseService, private router: Router) {
        this.loggedInSubject = new ReplaySubject(1);
        this.firebase.auth.onAuthStateChanged(this.loggedInSubject);
    }

    canActivate(): Observable<boolean> {
        return this.loggedInSubject.map(user => {
            if (!user) {
                this.router.navigate(['/login']);
            }
            console.log('Authenticated?', !!user);
            return !!user;
        }).take(1);
    }

}
like image 38
Sam Avatar answered Nov 15 '22 09:11

Sam