web-dev-qa-db-fra.com

Angular2 - Impossible de lire la propriété 'subscribe' d'undefined dans un appel imbriqué

J'ai examiné un certain nombre de ressources, y compris this , this et this , mais je n'ai pas été en mesure d'atteindre le résultat souhaité.

Tout ce que j'essaie de faire est d'authentifier un utilisateur (en utilisant Firebase) puis une fois authentifié, chargez son profil et stockez-le dans une variable userProfile avant de charger la page suivante Tableau de bord:

Mon service de connexion:

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

Ma méthode 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)
            });

Voici à quoi ressemble une partie du journal:

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

Je peux voir que les méthodes, individuellement, fonctionnent comme prévu. L'utilisateur s'authentifie et le profil est chargé (affiché dans le journal). Le problème réside dans l'événement subscribe pour des raisons que je ne connais pas.

10
benscabbia

Ok c'est étrange mais j'ai redémarré webpack et il semble avoir résolu le problème.

Voici à quoi ressemble le code et il s'authentifie correctement via la promesse, puis en cas de succès, il charge le profil qui charge ensuite la page suivante:

Ma méthode 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)
            )

Et ma méthode 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)
            });
}

La pile d'appels:

  1. L'utilisateur est authentifié
  2. Abonnez-vous à getProfile et attendez la fin de la méthode ...
    1. La méthode GetProfile () s'exécute
    2. Le profil est défini
  3. La page est redirigée
4
benscabbia

Je pense que le problème est que getProfile ne retourne pas vraiment un Observable.

Vous utilisez flatMap pour pouvoir enchaîner la séquence observable et renvoyer le profil en tant qu'observable. Mais pour que cela fonctionne, votre rappel à l'intérieur du flatMap devrait retourner une promesse ou un observable (comme j'ai appris de cette réponse ). Sinon, la chaîne des observables est rompue.

Donc, ce que vous devez probablement faire est quelque chose comme:

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