Home > Software engineering >  Why does AngularFire .set() waits forever for a response and doesn't proceed?
Why does AngularFire .set() waits forever for a response and doesn't proceed?

Time:07-25

I'm trying to create my first app in Angular using AngularFire to help with Firebase operations and after logging in with Twitter I'm trying to add the user as a document in my users collection. Here's the full function:

processLoggedUser(): Promise<number> {
    return this.afAuth.getRedirectResult().then(async result => {
        if (result.user) {
            const uid = result.user.uid;
            const credential = result.credential as firebase.default.auth.OAuthCredential;
            console.log('Twitter answer of AuthLogin: ', result)
            this.uid = uid
            let code = 0 // 0 = default code -> error
            if (result.additionalUserInfo.isNewUser) {
                console.log("New user")
                this.user = {
                    uid: this.uid,
                    email: result.user.email,
                    displayName: result.user.displayName,
                    photoURL: result.user.photoURL.replace('_normal', ''),
                    miniPhotoURL: result.user.photoURL,
                    accessToken: credential.accessToken,
                    secret: credential.secret,
                    twitterId: result.additionalUserInfo.profile["id"],
                    username: result.additionalUserInfo.username,
                    bio: result.additionalUserInfo.profile["description"],
                    verified: result.additionalUserInfo.profile["verified"],
                    wallet: 0,
                    staff: false,
                    banned: false,
                    hidden: false
                };
                console.log(this.user)
                await this.afs.collection('users').doc(this.uid).set(this.user || {nome: "oops"}).then(res => {
                    console.log("User created", res)
                    code = 2 // Number code for new user
                }).catch(err => {
                    console.log("Error creating user", err)
                    code = 0 // Number code for error
                })
                return 2
            } else {
                await this.getUser(uid).then(res => res.subscribe(res => {
                    if (res == undefined) {
                        this.signOut()
                        code = 4 // Number code for user not found
                    } else {
                        this.user = res
                        console.log("Existing user", this.user)
                        code = 1 // Number code for existing user
                    }
                }))
            }
            return code
        }else {
            return 3
        }
    }).catch((error) => {
        console.warn(error)
        return 0 // Number code for error
    })
}

What really bothers me is this part:

await this.afs.collection('users').doc(this.uid).set(this.user).then(res => {
    console.log("User created", res)
    code = 2 // Number code for new user
}).catch(err => {
    console.log("Error creating user", err)
    code = 0 // Number code for error
})

It never gets to .then() or .catch(), it just gets stuck waiting forever for a response. But, if i put this exact same code, let's say, in the constructor or anywhere else, it works perfectly and actually creates the document in the Firestore Database.

Can anyone suggest me a way to make this work?

CodePudding user response:

Found one, https://github.com/angular/angularfire/issues/2585

So basically they are telling you need to subscribe to ".authState or .user from AngularFireAuth", (note, authState triggers only on login/logout) i'd try something like below but i have no way to test, so sorry if anything:

Also, added some note about your subscribe function below, you can convert them to promise in the way i did also.

import { first, tap } from "rxjs/operators";

processLoggedUser(): Promise<number> {
  return this.afAuth
    .getRedirectResult()
    .then(async (result) => {
      if (result.user) {
        const authUser = await this.afAuth.user
          .pipe(
            // Logs
            tap((user) => {
              console.log("User changed: ", user);
            }),
            // to unsibscribe after first event emitted
            first()
          )
          .toPromise(); // toPromise is tricky, a chance it will not fire for you, i have no way to test.

        const uid = result.user.uid;
        const credential = result.credential as firebase.default.auth.OAuthCredential;
        console.log("Twitter answer of AuthLogin: ", result);
        this.uid = uid;
        let code = 0; // 0 = default code -> error
        if (result.additionalUserInfo.isNewUser) {
          console.log("New user");
          this.user = {
            uid: this.uid,
            email: result.user.email,
            displayName: result.user.displayName,
            photoURL: result.user.photoURL.replace("_normal", ""),
            miniPhotoURL: result.user.photoURL,
            accessToken: credential.accessToken,
            secret: credential.secret,
            twitterId: result.additionalUserInfo.profile["id"],
            username: result.additionalUserInfo.username,
            bio: result.additionalUserInfo.profile["description"],
            verified: result.additionalUserInfo.profile["verified"],
            wallet: 0,
            staff: false,
            banned: false,
            hidden: false
          };
          console.log(this.user);
          await this.afs
            .collection("users")
            .doc(this.uid)
            .set(this.user || { nome: "oops" })
            .then((res) => {
              console.log("User created", res);
              code = 2; // Number code for new user
            })
            .catch((err) => {
              console.log("Error creating user", err);
              code = 0; // Number code for error
            });
          return 2;
        } else {
          await this.getUser(uid).then((res) =>
            // Note: subscribe is not a promise, not awaitable, codes will not be set
            res.subscribe((res) => {
              if (res == undefined) {
                this.signOut();
                code = 4; // Number code for user not found
              } else {
                this.user = res;
                console.log("Existing user", this.user);
                code = 1; // Number code for existing user
              }
            })
          );
        }
        return code;
      } else {
        return 3;
      }
    })
    .catch((error) => {
      console.warn(error);
      return 0; // Number code for error
    });
}
  • Related