简体   繁体   中英

How to avoid observable delay in angular or make sure my function gets called only when observable is ready

I have a login function which calls Firebase SDK method to authenticate with email. This Firebase method returns non-null Promise of UserCredential , so it says in Firebase docs. So I use .then() to wait until user is logged in, authenticated and then console.log his info and redirect to home. Unfortunately it doesn't work. I get undefined from console.log(value.email); in the console, not working from

if (this.userDetails) {
console.log("hello im user" + " " + email);
} else {
console.log("not working");
}

and errorTypeError: Cannot read property 'router' of undefined from:

.catch(function(error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      console.log("error" + error);
    });

then immediately after one or two seconds, it finally starts working, prints out hello im user lajmis@mail.com from

constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
    this.user = _firebaseAuth.authState;
    this.loggedIn = !!sessionStorage.getItem('user');

    this.user.subscribe(
        (user) => {
          if (user && user.uid) {
            this.userDetails = user;
            var email = this.userDetails.email;
            console.log("hello im user" + " " + email);
            this.setCurrentUser(email);
            this.loggedIn = true;
            console.log(this.userDetails);

          } else {
            this.userDetails = null;
          }
        }
      );
  }

and this.userDetails .

Why is this happening? Here is the full code:

export class AuthService {
  private user: Observable<firebase.User>;
  private userDetails: firebase.User = null;
  public loggedIn = false;

  constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
    this.user = _firebaseAuth.authState;
    this.loggedIn = !!sessionStorage.getItem('user');

    this.user.subscribe(
        (user) => {
          if (user && user.uid) {
            this.userDetails = user;
            var email = this.userDetails.email;
            console.log("hello im user" + " " + email);
            this.setCurrentUser(email);
            this.loggedIn = true;
            console.log(this.userDetails);

          } else {
            this.userDetails = null;
          }
        }
      );
  }

  // Set current user in your session after a successful login
    setCurrentUser(email: string): void {
        sessionStorage.setItem('user', email);
        this.loggedIn = true;
    }

    // Get currently logged in user from session
    getCurrentUser(): string | any {
        return sessionStorage.getItem('user') || undefined;
    }

    isLoggedIn() {
    return this.loggedIn;
    }

  logUserIn(email, pass) {
    firebase.auth().signInWithEmailAndPassword(email, pass).then(function(value) {

        console.log(value.email);
        this.router.navigate(['']);

    }).catch(function(error) {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      console.log("error" + error);
    });
if (this.userDetails) {
console.log("hello im user" + " " + email);
} else {
console.log("not working");
}
}

logUserIn is non blocking - so the workflow will be;

  • call constructor
  • call this.user.subscribe
  • call logUserIn
  • call firebase.auth().signInWithEmailAndPassword
  • call if (this.userDetails)
  • receive response from firebase.auth().signInWithEmailAndPassword
  • call .then(function(value) {
  • call this.router.navigate(['']);
  • receive response from this.user.subscribe

Therefore the console.log will output not working and a few seconds later the this.user.subscribe receives the user object.

router cannot be accessed because you're not using an arrow function . Use an arrow function to maintain access to this .

Perhaps try a workflow such as the following;

constructor(private _firebaseAuth: AngularFireAuth, private router: Router) {
  this.user = _firebaseAuth.authState;
  this.loggedIn = !!sessionStorage.getItem('user');

  this.user
    .subscribe(user => {
      console.log('constructor user: ' + user);
      this.updateUser(user);
    });
}

updateUser(user) {
  if (user && user.id) {
    this.userDetails = user;
    var email = this.userDetails.email;
    console.log("hello im user" + " " + email);
    this.setCurrentUser(email);
    this.loggedIn = true;
    console.log(this.userDetails);
  } else {
    this.userDetails = null;
  }
}

logUserIn(email, pass) {
  firebase.auth().signInWithEmailAndPassword(email, pass)
    .then(user => {
      console.log('logUserIn: ' + user);

      this.updateUser(user);

      this.router.navigate(['']);
    })
    .catch(error => {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      console.log("error" + error);
    });
}

This way both the logUserIn and constructor can update the userDetails when they receive the user object from Firebase.

It will also avoid you redirecting before this.userDetails have been set.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM