web-dev-qa-db-ja.com

Angular2-ネストされた呼び出しで未定義のプロパティ 'subscribe'を読み取ることができません

thisthis 、および this を含む多くのリソースを見てきましたが、望ましい結果を達成することができませんでした。

私がやろうとしているのは、(firebaseを使用して)ユーザーを認証し、認証されたら、次のページのダッシュボードをロードする前に、プロファイルをロードして変数userProfileに保存することです。

マイサインインサービス:

_public signinUser(user: User) {
    this.af.auth.login({
        email: user.email,
        password: user.password
    },
        {
            provider: AuthProviders.Password,
            method: AuthMethods.Password
        }

    )
        .then(                
        success => {
            console.log('Authenticated');
            this.getProfile().subscribe( // PROBLEM is here
                profile => {
                    console.log(profile);
                    console.log('Profile Loaded');
                    this.router.navigate(['/dashboard']);
                }
            )               
        }
        )
        .catch(function (error) {
            ...
            console.log('ERROR SIGNING USER IN');
        }
_

私のgetProfile()メソッド:

_public getProfile(): Observable<any> {            
        return this.af.database.object('/profiles/' + this.user.uid)
        .flatMap(
            profile => {
                console.log('inside success');
                console.log(profile);
                this.userProfile = <User>profile;                    
                console.log('getProfile has completed');       
                return profile;
            },
            error => {
                console.log(error)
            });
_

これはログの一部がどのように見えるかです:

_Authenticated
auth.service.ts:104 ERROR SIGNING USER IN
auth.service.ts:105 TypeError: Cannot read property 'subscribe' of undefined
at auth.service.ts:91
at ZoneDelegate.invoke (zone.js:232)
at Object.onInvoke (ng_zone.js:238)
at ZoneDelegate.invoke (zone.js:231)
at Zone.run (zone.js:114)
at zone.js:502
at ZoneDelegate.invokeTask (zone.js:265)
at Object.onInvokeTask (ng_zone.js:229)
at ZoneDelegate.invokeTask (zone.js:264)
at Zone.runTask (zone.js:154)
auth.service.ts:106 Cannot read property 'subscribe' of undefined
auth.service.ts:184 inside success
auth.service.ts:185 Object {confirmPassword: "123123", email: "[email protected]", github: "aaa" name: "a", password: "123123"…}
auth.service.ts:188 
getProfile has completed()
auth.service.ts:185
_

メソッドが個別に意図したとおりに機能していることがわかります。ユーザーが認証され、プロファイルがロードされます(ログに表示されます)。問題は、私が知らない理由でサブスクライブイベントにあります。

10
benscabbia

これは奇妙ですが、webpackを再起動すると問題は解決したようです。

これは、コードがどのように見え、promiseを介して正しく認証され、成功するとプロファイルをロードし、次に次のページをロードする方法です。

私のsigninUserメソッド:

public signinUser(user: User) {
    this.af.auth.login({
        email: user.email,
        password: user.password
    },
        {
            provider: AuthProviders.Password,
            method: AuthMethods.Password
        }

    )
        .then(                
        success => {
            console.log('Authenticated');
            this.getProfile().subscribe(
                profile => {
                    this.router.navigate(['/dashboard']);
                }, 
                error => console.log(error)
            )

そして、私のgetProfileメソッド:

public getProfile(): Observable<User> {        
        return this.af.database.object('/profiles/' + this.user.uid)
        .map(                
            profile => {
                console.log('inside success');
                console.log(profile);
                this.userProfile = <User>profile;                    
                console.log(this.userProfile);        
                return profile;
            },
            error => {
                console.log(error)
            });
}

コールスタック:

  1. ユーザーは認証されています
  2. GetProfileをサブスクライブし、メソッドが完了するのを待ちます...
    1. GetProfile()メソッドが実行されます
    2. プロファイルが設定されています
  3. ページがリダイレクトされます
4
benscabbia

問題は、getProfileが実際にObservableを返さないことだと思います。

flatMapを使用して、監視可能シーケンスをチェーン化し、プロファイルを監視可能として返すことができます。ただし、これが機能するためには、flatMap内のコールバックがpromiseまたはobservableを返す必要があります( this answer から学んだように)。そうしないと、オブザーバブルのチェーンが壊れます。

したがって、おそらくあなたがする必要があるのは次のようなものです:

public getProfile(): Observable<any> {            
        return this.af.database.object('/profiles/' + this.user.uid)
        .flatMap(
            profile => {
                console.log('inside success');
                console.log(profile);
                this.userProfile = <User>profile;                    
                console.log('getProfile has completed');       
                return Promise.resolve(profile);//<-- this is what needs to be changed
            },
            error => {
                console.log(error)
            });
4
Yaron Schwimmer