2016-08-23 7 views
3

私はrxjsが新しく、これを解決する方法についていくつかの助けが必要です。オブザーバーを観察可能な状態に戻すにはどうすればいいですか?

オブザーバーオブジェクトを受け取るObserveronAuthStateChanged()に渡します。オブザーバは何らかの作業を行い、ブール値を出力してブール値がObservableとして返されるようにします。観測可能から観測者までこの橋をどのように実装するのですか?

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> */ 
    } 
} 
+0

あなたはonAuthStateChanged' 'の機能の過負荷は、対象から放出された最後の値を記憶するために' replaySubject'を使用することができます関数内のそのサブジェクトを使用して、ブール値を出力します。その後、同じ主題を返します。被験者は観察者でも観察者でもあります。したがって、被験者は関数から値を受け取ります。観察可能なものであれば、他のリスナーも購読してその価値を取り戻すことができます。 'replaySubject'を使うので、あなたのリスナーが放出された後にサブジェクトにサブスクライブするとしても、値を取得することはできます。 – user3743222

答えて

2

他の人に恩恵を受けるには、私が書いたものがあります。これはうまくいくようです。これが動作しない場合があります奇妙な理由のために実際に

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

、そして我々は行うことができます。onAuthStateChanged以来

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

} 
1

は、入力としてオブザーバを取り、そしてティアダウン機能を返す、我々は単純でそれをラップすることができます:今、あなたはObservable.create機能に慣れていない場合

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

、私が説明しましょう:createは、onSubscribeという機能を使用してオブザーバーを操作し、ティアダウン機能を返します。それではとても馴染んでいないのですが、onAuthStateChangedがビルドされていますか?あなたはnextOrObserverを手渡し、それはティアダウンを返します!

(私のため observerを受け入れなかった nextOrObserver奇妙な理由のために今、私は上記のコードの代わりにそれを next機能を付与する。Hench切り替える。)

設定onAuthStateChanged$

、我々はストリームを変換することができます演算子を使用します。すべての演算子は1つの観測値を別の観測値に変換し、RxJには数十種類のものがあります。

canActivate(): Observable<boolean> { 
    onAuthStateChanged$ 
    .do(user => {if (!user) { this.router.navigate(['/login']); } }) 
    .map(user => !!user) 
    .do(user => console.log('Authenticated?', user)) 
} 
0

同様のアプローチ:

./auth-guard.ts

import { Injectable } from '@angular/core'; 
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; 
import { Observable } from 'rxjs/Observable'; 

import { AuthService } from '../shared/auth.service'; 

@Injectable() 
export class AuthGuard implements CanActivate { 

    constructor(
    private router: Router, 
    private authService: AuthService) { } 

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

    return this.authService.authState.map((auth) => { 
     if (auth == null) { 
     this.router.navigate(['auth']); 
     return false; 
     } else { 
     return true; 
     } 
    }).first(); 

    } 
} 

./shared/auth.service.ts

あなたのケースでは、それは次のようになります。
import { Observable } from 'rxjs/Observable'; 
import { Observer } from 'rxjs/Observer'; 
import { FirebaseApp } from '../shared/firebase'; 

@Injectable() 
export class AuthService { 

    public auth: firebase.auth.Auth; 
    public authState: Observable<firebase.User>; 

    constructor(public app: FirebaseApp) { 
    this.auth = app.auth(); 
    this.authState = this.authStateObservable(app); 
    } 

    /** 
    * @function 
    * @desc Create an Observable of Firebase authentication state 
    */ 
    public authStateObservable(app: FirebaseApp): Observable<firebase.User> { 
    const authState = Observable.create((observer: Observer<firebase.User>) => { 
     this.auth.onAuthStateChanged(
     (user?: firebase.User) => observer.next(user), 
     (error: firebase.auth.Error) => observer.error(error), 
     () => observer.complete() 
    ); 
    }); 
    return authState; 
    } 
} 

。/shared/firebase.ts

import * as firebase from 'firebase'; 

export class FirebaseApp implements firebase.app.App { 

    name: string; 
    options: {}; 
    auth:() => firebase.auth.Auth; 
    database:() => firebase.database.Database; 
    messaging:() => firebase.messaging.Messaging; 
    storage:() => firebase.storage.Storage; 
    delete:() => firebase.Promise<any>; 

    constructor() { 
    return firebase.initializeApp({ 
     apiKey: 'AIzaSyC6pDjAGuqXtVsU15erxVT99IdB0t4nln4', 
     authDomain: 'inobrax-ebs-16552.firebaseapp.com', 
     databaseURL: 'https://inobrax-ebs-16552.firebaseio.com', 
     storageBucket: 'inobrax-ebs-16552.appspot.com', 
     messagingSenderId: '383622803653' 
    }); 
    } 

} 
0

これが必ずしも上記の回答よりも「良い」かどうかはわかりませんが、それは確かにきれいです。 AuthServiceに2つのプロパティを作成することにしました.1つは、ユーザーが認証されているかどうかを反映するブール値と、基本的にブール値プロパティの値を出力するuserLoggedInサブジェクトです。両方のプロパティはonAuthStateChanged()でバインドされています。したがって、状態が変更されると、authenticatedプロパティはtrueになり、認証されている場合はfalseになり、userLoggedInnext()next(this.authenticated))を使用してこの値を返します。 AuthGuardの場合、CanActivate()にはbooleanまたはObservable<boolean>が返されます。まず、AuthServiceauthenticatedプロパティがチェックされていればtrueを返し、それ以外の場合はuserLoggedInのサブジェクトをマップしてユーザが認証されているかどうかを調べます。これは、ページが更新された後、authenticatedがまだ定義されていないので、ガードは放出されたサブジェクトの値を返しますので、代わりにuserLoggedInが戻るのを待ちます。最初にauthenticatedのプロパティをチェックする理由は、navリンクを使用してページを変更しようとすると、ガードがサブジェクトの発行された値を返すだけなので何も起こりません。ログイン、ログアウト、またはページリフレッシュ(アプリケーションを再起動する)。以下のコード:

のAuthService

import * as firebase from 'firebase'; 
import { Router } from '@angular/router'; 
import { Injectable, OnInit } from '@angular/core'; 
import { Subject } from 'rxjs/Subject'; 

@Injectable() 

export class AuthService implements OnInit { 
    authenticated: boolean; 
    userLoggedIn = new Subject<boolean>(); 

    constructor(private router: Router) {} 

    ngOnInit() { 
    } 

    checkAuthStatus() { 
     firebase.auth().onAuthStateChanged((user) => { 
      this.authenticated = !!user; 
      this.userLoggedIn.next(this.authenticated); 
     }); 
    } 

    login(email: string, password: string) { 
     firebase.auth().signInWithEmailAndPassword(email, password).then(() => { 
      this.authenticated = true; 
      this.router.navigate(['/']); 
     }).catch((error) => { 
      console.log(error); 
     }); 
    } 

    logout() { 
     firebase.auth().signOut().then(function() { 
      this.router.navigate(['login']); 
     }.bind(this)).catch((error) => { 
      console.log(error); 
     }); 
    } 
} 

AuthGuard

import { CanActivate, Router } from '@angular/router'; 
import { Injectable } from '@angular/core'; 
import { AuthService } from './auth.service'; 
import { Observable } from 'rxjs/Observable'; 

import 'rxjs/add/operator/map'; 

@Injectable() 

export class AuthGuard implements CanActivate { 
    constructor(private authService: AuthService, private router: Router) { 
    } 

    canActivate(): Observable<boolean> | boolean { 
     if(this.authService.authenticated) { 
      return true; 
     } 

     return this.authService.userLoggedIn.map((authenticated) => { 
      if(!authenticated) { 
       this.router.navigate(['login']); 
      } 

      return authenticated; 
     }); 
    } 
} 
関連する問題