2016-08-15 12 views
0

アプリユーザーを認証してログインするために、いくつかの手順を実行するAngular 2サービスがあります。 Observerでnext()を呼び出そうとするたびに、私は定義されていないというエラーが出ます。 Observableがインスタンス化されたときに、私がnext()を呼び出すことができる唯一の場所はコンストラクタの内側です。RxJS Observable&Observerの問題

authenticateUser()を呼び出すと、this.isLoggedInが定義されていないというエラーが表示されます。

AuthService.ts

public isLoggedIn$: Observable<boolean>; 
private isLoggedIn: Observer<boolean>; 

constructor(...) { 

    this.isLoggedIn$ = new Observable<boolean>(
     (observer: Observer<boolean>) => { 
      this.isLoggedIn = observer; 

      // this works fine 
      this.doLogin(); 

     }).share() 

} 

private doLogin =():void => { 

    let context:AuthContextModel = this.authContextService.getAuthContext(); 

    if (context) { 

     let isAuthenticated = this.isAuthenticated(context); 

     if (isAuthenticated) { 

      this.doCreateCurrentUserContext(context) 
       .then((result) => {return this.doNotifyLoggedInStatus(result);}); 
     } 
    } 
}; 


private doNotifyLoggedInStatus = (result:boolean):Promise<boolean> => { 

    this.isLoggedIn.next(result); 

    return new Promise((resolve, reject) => { 
     return resolve(true); 
    }); 
}; 


public authenticateUser = (user: string, pass: string):Promise<boolean> => { 
    return this.doFetchToken(user, pass) 
     .then((fetchTokenData) => {return this.doStoreToken(fetchTokenData);}) 
     .then((authContext) => {return this.doCreateCurrentUserContext(authContext);}) 
     .then((result) => {return this.doNotifyLoggedInStatus(result);}); 

}; 
+2

私は 'isLoggedIn $は'加入していなかったためだと思います。 – estus

+0

@estusありがとうございました!私は数時間、頭を叩いています。ありがとう! – JBeckton

答えて

3

あなたが観測のインスタンス化の外にオブザーバーに.next()を呼び出したい場合は、あなたではなく別の観測とオブザーバーより件名を使用する必要があります。被験者はその両方として行動する。イベントをイベントに渡す場所とは別にイベントを購読することができます。

さまざまな種類の科目がありますが、状況に応じてBehaviorSubjectをおすすめします。あなたがそれを購読するときはいつでも、将来のイベントをキャッチするだけでなく、サブスクリプションが起こる前にの最後のイベントが返されます。これは、成功したログインのために別のコードを記述する必要はなく、すでに起こった後にユーザーが認証されたかどうか(または後でログアウトする)を実際に確認する必要がないため、認証コンポーネントにとって便利です。それは本当に簡単です。

import { BehaviorSubject } from 'rxjs/Rx'; 

//... 
    public isLoggedIn: BehaviorSubject<boolean> = BehaviorSubject.create(); 

    constructor(...) { } 

    private doLogin():void { 

    //... Do the log in 
    this.isLoggedIn.next(true); 

    }; 

あなたは状態のログをチェックしたいところはどこでもやらなければならないことは、BehaviorSubjectを取得し、それに加入しています。 doLogin()が呼び出される前または後にサブスクリプションが発生するかどうかは関係ありません。

リフレッシュ時にログイン状態を保持する場合は、コンストラクタで認証をチェックするだけで、いつものようにBehaviorSubjectの.next(true)を呼び出す必要があります。

も参照してください:

ReactiveX Subject docs

Intro to Rx BehaviorSubjects

+0

ありがとう、これはすばらしい助けとなりました。もう1つの質問.. DOMに影響を与えるために観測値を得るためのトリックは何ですか? * ngIf = "isLoggedIn" – JBeckton

+0

'* ngIf =" isLoggedIn | async "' *は*動作するはずです。非同期パイプは、(BehaviorSubjectの)Observableから値をアンラップするために必要です。さもなければ、あなたはそれに何をするかを指定せずにSubjectを与えているだけです。角はそれを好まないでしょう。ログインコンポーネントの外にあるDOMに影響を与えるには、isLoggedIn BehaviorSubjectを取得する必要があります。そのため、本当に何らかの認証サービスに配置する必要があります。それがうまくいかない場合は、コンポーネントで手動でサブスクリプションを購読し、ブール値のプロパティに値を割り当て、* ngIfをその値にバインドします。 – ABabin

+0

私はレイアウトのヘッダーに "Logged in As foo123"と表示されるCurrentUserコンポーネントを持っています。これは、ログイン後にアプリケーションを更新するときにのみ更新されます。私のCurrentUserコンポーネントはAuthServiceが注入され、isLoggedInビヘイビアのサブジェクトにコンストラクタでサブスクライブしました。また、AuthServiceがインジェクションされるLoginComponentもあり、ログインフォームはAuthService.authenticateUser()を呼び出して、すべてのビヘイビアがビヘイビアサブジェクトの次の(true)を呼び出します。しかし、このインプラントは、ログイン後にアプリをリロードするときにのみ機能します – JBeckton

関連する問題