Harald Wiesinger
Harald Wiesinger

Reputation: 681

Pass boolean from observable to observable

I want to check in my adminauthguard if the user has set a adminflag(in Firebase using angularfire2)

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> | boolean {
    return this.loginservice.af.auth.map((auth) =>  {
      if(auth == null) {
        return false;
      } else {
        this.membersservice.get(auth.uid).subscribe(users => {
          if(users.admin == true) {
            return true;
          } else {
            return false;
          }
        })
      }
    });

how can I resolve the observable in the observable inside?

Upvotes: 9

Views: 23060

Answers (2)

Manuel Villena
Manuel Villena

Reputation: 41

I need wait User Suscription info before to run any secure component. I use a similar solution to lastWhisper's, implementing canActivateChild and setting in routes:

    path: 'app', component: FullLayoutComponent, data: {title: 'Home'}, canActivateChild: [CanActivateChildTeam],

CanActivateChildTeam Service:

    import {Injectable, OnDestroy} from "@angular/core";
    import {CanActivateChild} from "@angular/router";
    import {Meteor} from 'meteor/meteor';
    import {Router} from '@angular/router';
    import {Observable} from "rxjs/Rx";
    import {MeteorObservable} from 'meteor-rxjs';
    import {Subscription} from 'rxjs/Subscription';


    @Injectable()
    export class CanActivateChildTeam implements CanActivateChild, OnDestroy {

    allow:Observable<boolean>;
    private _userSub:Subscription;

    constructor(private router:Router) {
    }

    canActivateChild(route:any, state:any):Observable<boolean> | Promise<boolean> | boolean {
        return this.getUser();
    }

    getUser() {
        if (this.allow) {
            this.allow = new Observable(observer => {
                observer.next(true);
                observer.complete();
            });
            return this.allow;
        }
        if (Meteor.userId()) {
            this.allow = new Observable(observer => {
                if (this._userSub)
                    this._userSub.unsubscribe();
                this._userSub = MeteorObservable.subscribe('user', Meteor.userId()).subscribe(
                    () => {
                        observer.next(true);
                        observer.complete();
                    }
                );
            });
            return this.allow;
        }
        else {
            this.router.navigate(['/']);
        }
    }

    ngOnDestroy():void {
        if (this._userSub)
            this._userSub.unsubscribe();
    }
}

Upvotes: 4

lastWhisper
lastWhisper

Reputation: 477

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> | boolean {

return new Observable<boolean>( observer => {

   this.loginservice.af.auth.map((auth) =>  {
      if(auth == null) {
        observer.next(false);
      } else {
        this.membersservice.get(auth.uid).subscribe(users => {
          if(users.admin == true) {
            observer.next(true);
          } else {
            observer.next(false);
          }
        })
      }
    });

Not 1000% sure if this will work with your service Observables, since I don't know Firebase for Angular2 exactly (only iOS), but this way you create an observable that just emits values based on the events that are happening inside the closure.

The only thing you may need to make sure (with tests) is that you do not run into undefined states, e.g. something like async hazards where you both emit true and false.

Upvotes: 16

Related Questions