14

I am trying to set up Firebase on my Ionic Angular project. I am using the linked tutorial https://www.positronx.io/ionic-firebase-authentication-tutorial-with-examples/ to do this.

I keep getting a TS2570 error:

Property 'sendEmailVerification' does not exist on type 'Promise'. Did you forget to use 'await'?

I have attached my code. The only major thing I changed was that AngularFire changed the way auth is used in 6.0.0

import { Injectable, NgZone } from '@angular/core';
import { auth } from 'firebase/app';
import { User } from "./user";
import { Router } from "@angular/router";
import { AngularFireAuth } from "@angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';

@Injectable({
  providedIn: 'root'
})

export class AuthenticationService {
  userData: any;

  constructor(
    public afStore: AngularFirestore,
    public ngFireAuth: AngularFireAuth,
    public router: Router,
    public ngZone: NgZone
  ) {
    this.ngFireAuth.authState.subscribe(user => {
      if (user) {
        this.userData = user;
        localStorage.setItem('user', JSON.stringify(this.userData));
        JSON.parse(localStorage.getItem('user'));
      } else {
        localStorage.setItem('user', null);
        JSON.parse(localStorage.getItem('user'));
      }
    })
  }

  // Login in with email/password
  SignIn(email, password) {
    return this.ngFireAuth.signInWithEmailAndPassword(email, password)
  }

  // Register user with email/password
  RegisterUser(email, password) {
    return this.ngFireAuth.createUserWithEmailAndPassword(email, password)
  }

  // Email verification when new user register
  SendVerificationMail() {
      return this.ngFireAuth.currentUser.sendEmailVerification()
      .then(() => {
        this.router.navigate(['verify-email']);
      })
    }

  // Recover password
  PasswordRecover(passwordResetEmail) {
    return this.ngFireAuth.sendPasswordResetEmail(passwordResetEmail)
    .then(() => {
      window.alert('Password reset email has been sent, please check your inbox.');
    }).catch((error) => {
      window.alert(error)
    })
  }

  // Returns true when user is looged in
  get isLoggedIn(): boolean {
    const user = JSON.parse(localStorage.getItem('user'));
    return (user !== null && user.emailVerified !== false) ? true : false;
  }

  // Returns true when user's email is verified
  get isEmailVerified(): boolean {
    const user = JSON.parse(localStorage.getItem('user'));
    return (user.emailVerified !== false) ? true : false;
  }

  // Sign in with Gmail
  GoogleAuth() {
    return this.AuthLogin(new auth.GoogleAuthProvider());
  }

  // Auth providers
  AuthLogin(provider) {
    return this.ngFireAuth.signInWithPopup(provider)
    .then((result) => {
       this.ngZone.run(() => {
          this.router.navigate(['dashboard']);
        })
      this.SetUserData(result.user);
    }).catch((error) => {
      window.alert(error)
    })
  }

  // Store user in localStorage
  SetUserData(user) {
    const userRef: AngularFirestoreDocument<any> = this.afStore.doc(`users/${user.uid}`);
    const userData: User = {
      uid: user.uid,
      email: user.email,
      displayName: user.displayName,
      photoURL: user.photoURL,
      emailVerified: user.emailVerified
    }
    return userRef.set(userData, {
      merge: true
    })
  }

  // Sign-out
  SignOut() {
    return this.ngFireAuth.signOut().then(() => {
      localStorage.removeItem('user');
      this.router.navigate(['login']);
    })
  }

}

The only time it's called is in the registration pages here

signUp(email, password){
        this.authService.RegisterUser(email.value, password.value)
        .then((res) => {
          // Do something here
          this.authService.SendVerificationMail()
          this.router.navigate(['verify-email']);
        }).catch((error) => {
          window.alert(error.message)
        })
    }

}

These are the dependancies used in the project:

    "@angular/common": "~8.2.14",
    "@angular/core": "~8.2.14",
    "@angular/fire": "^6.0.0",
    "@angular/forms": "~8.2.14",
    "@angular/platform-browser": "~8.2.14",
    "@angular/platform-browser-dynamic": "~8.2.14",
    "@angular/router": "~8.2.14",
    "@capacitor/cli": "^2.0.1",
    "@capacitor/core": "^2.0.1",
    "@capacitor/ios": "^2.0.1",
    "@ionic-native/core": "^5.0.7",
    "@ionic-native/splash-screen": "^5.0.0",
    "@ionic-native/status-bar": "^5.0.0",
    "@ionic/angular": "^5.0.0",
    "core-js": "^2.5.4",
    "firebase": "^7.14.0",
    "rxjs": "~6.5.1",
    "tslib": "^1.9.0",
    "zone.js": "~0.9.1"

If anyone can give me any tips on how to fix this issue? I am not 100% sure on how to implement the async and await on the function without showing more errors.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

4 Answers4

33

The new version AngularFire 6.0.0 is released to support Angular 9. It is not backwards compatible with older versions. It no longer supports older versions of Angular (<9). It also dropped support for older versions of Typescript(<3.6.4), Firebase Javascript SDK (<7.13.1) and firebase-tools(<8.0.0).

'auth' property of AngularFireAuth is deprecated therefore the usage of 'currentUser' has also been changed.

'currentUser' is a promise that resolves the current user. Property 'sendEmailVerification' does not exist on it but can be easily accessed through the resolved user.

  // Email verification when new user register
  SendVerificationMail() {
    return this.ngFireAuth.currentUser.then(u => u.sendEmailVerification())
    .then(() => {
      this.router.navigate(['verify-email']);
    })
  }
cerkiner
  • 1,906
  • 10
  • 19
1

I think you should move the .then callback function to the component, as in the service, you are returning the promise

in the service

  // Email verification when new user register
  SendVerificationMail() {
      return this.ngFireAuth.currentUser.sendEmailVerification()
  }

and in the component

signUp(email, password){
    this.authService.RegisterUser(email.value, password.value)
    .then((res) => {
        // Do something here
        this.authService.SendVerificationMail()
        .then(() => {
            this.router.navigate(['verify-email']);
        })
    }).catch((error) => {
        window.alert(error.message)
    })
}

Update

you could leave everything as it is, and add async / await to the caller function in the component not in the service

component

async signUp(email, password){
  this.authService.RegisterUser(email.value, password.value)
  .then((res) => {
    // Do something here
    await this.authService.SendVerificationMail()
    this.router.navigate(['verify-email']);
  }).catch((error) => {
    window.alert(error.message)
  })
}

service

// Email verification when new user register
SendVerificationMail() {
  return this.ngFireAuth.currentUser.sendEmailVerification()
  .then(() => {
    this.router.navigate(['verify-email']);
  })
}
Mohammed Yousry
  • 2,134
  • 1
  • 5
  • 7
  • Thanks for responding. Cool I have changed around the code but it still seems to point back to the `SendVerificationMail() { return this.ngFireAuth.currentUser.sendEmailVerification() }` I have also added: `aync SendVerificationMail() { await this.ngFireAuth.currentUser.sendEmailVerification() }` But still shows the same error –  Apr 14 '20 at 18:49
  • I've updated my answer, you could add the async/await to the caller function in the component, and keep the service as it is – Mohammed Yousry Apr 14 '20 at 19:37
  • It's weird, still not working. Because the .then is in a seperate function it's not letting await work keeps showing the error from before plus the await error as it's seperate. `error TS1308: 'await' expression is only allowed within an async function. [ng] 23 await this.authService.SendVerificationMail() [ng] ~~~~~ [ng] src/app/shared/authentication-service.ts:45:40 - error TS2570: Property 'sendEmailVerification' does not exist on type 'Promise'. Did you forget to use 'await'? [ng] 45 return this.ngFireAuth.currentUser.sendEmailVerification()` –  Apr 15 '20 at 14:45
  • did you add `async` to the signup method in the component?, you have to add `async` keyword to the enclosing function to be able to use `await` – Mohammed Yousry Apr 15 '20 at 14:56
  • I did yeah it's weird I used what you posted above line for line still showing the error. I have two types of sign up pages. Using the same signUp() for now but it will be changing soon. But I wouldn't see why that is causing conflict? Edit: Thank you btw for helping me with this issue! –  Apr 15 '20 at 15:07
0

I have this issues.

import { auth } from 'firebase/app';

Since firebase/app is being removed. What does this replace? I had a problem with googleAuth(). Previously i also have a issue with able to login with popup on localhost but have error when deploy to android phone.

 // Sign in with Gmail
  GoogleAuth() {
    return this.AuthLogin(new auth.GoogleAuthProvider());
  }

// Auth providers
AuthLogin(provider) {
return this.ngFireAuth.signInWithPopup(provider)
.then((result) => {
   this.ngZone.run(() => {
      this.router.navigate(['tabs']);
    })
  this.SetUserData(result.user);
}).catch((error) => {
  window.alert(error)
})
}
0

try this

// Send email verfificaiton when new user sign up   
async SendVerificationMail() {
(await this.afAuth.currentUser).sendEmailVerification()
.then(() => {
  this.router.navigate(['verify-email']);
})   }

see this note https://github.com/angular/angularfire/issues/2409

tvas
  • 11
  • 1