Error: reCAPTCHA container is either not found or already contains inner elements

Viewed 17712

I am trying Phone number authentication using Ionic2/typescript and initialising the recaptcha verifier like this:

.ts file

    import firebase from 'firebase';

     @IonicPage()
     @Component({
       selector: 'page-login',
       templateUrl: 'login.html',
     })

     export class LoginPage {

    public recaptchaVerifier:firebase.auth.RecaptchaVerifier;
           constructor(afAuth: AngularFireAuth, public authData: AuthProvider, public alertController: AlertController, formBuilder: FormBuilder, public navCtrl: NavController, public navParams: NavParams) {
             this.loginForm = formBuilder.group({
               phone: ['', Validators.compose([Validators.required, 
                 Validator.isValidPhone])]
             });
             try {
               this.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
             }catch(e){
               console.log("There was a problem in initializing the recapctha verifier: " + e);
             }
             this.authData.recaptchaVerifier = this.recaptchaVerifier;
           }
}

.html file

<ion-content padding>
  <div id="recaptcha-container"></div>
  <form [formGroup]="loginForm" (submit)="loginUser()" novalidate>

    <ion-item>
      <ion-label stacked>Phone Number</ion-label>
      <ion-input #phone formControlName="phone" type="phone" placeholder="10 digit mobile number"
        [class.invalid]="!loginForm.controls.phone.valid &&
          loginForm.controls.phone.dirty"></ion-input>
    </ion-item>
    <ion-item class="error-message" *ngIf="!loginForm.controls.phone.valid  &&
      loginForm.controls.phone.dirty">
      <p>Please enter a valid 10 digit mobile number.</p>
    </ion-item>

    <button ion-button block type="submit">
      Next
    </button>

  </form>

</ion-content>

However when I run the code I get:

Error: reCAPTCHA container is either not found or already contains inner elements

Exploring the world of ionic and firebase for the first time, I find it difficult to understand the problem. Anyone encountered and solved this problem before? Any insight will be helpful.

8 Answers

You can also add a delay to load the captcha. It did the trick for me.

JS :

  var defaultApp = firebase.initializeApp(config);
  setTimeout(function() {
    window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
        'size': 'normal',
        'callback': function(response) {
            console.log("success", response);
        },
        'expired-callback': function() {
            console.log("expired-callback");
        }
    });

    recaptchaVerifier.render().then(function(widgetId) {
        window.recaptchaWidgetId = widgetId;
    });
  },2000);

HTML :

<div id="recaptcha-container"></div>

Well, the problem is, you have written the recaptcha verifying code before html rendition, either in constructor or oninit if using ionic4. Write it inside ionViewDidEnter. Html is rendered by then and that node can be found with given id in the html document by then.

In the constructor, the page has not been loaded yet therefore the DOM element does not exist.
Therefore You have to place it in either
ng on init (fastest)

ngOnInit(){

}

or ion view will enter (optimal)

ionViewWillEnter(){

}

or ion view did enter (safest)

ionViewDidEnter(){

}

or you could use a timer in your constructor problem is estimating the duration when all the pages take different durations

var duration = 3000; 
//in milliseconds. therefore 3 seconds. 
//which may either late or early
setTimeout(()=>{

}, duration)

Check out the ionic life cycle for a better understanding

using hooks

useEffect(() => {
    recaptchaVerifierRef.current = new Firebase.auth.RecaptchaVerifier(
      'recaptcha-container',
      {
        size: 'invisible',
        callback: function (response) {
          console.log('success', response);
        },
        'expired-callback': function () {
          console.log('expired-callback');
        },
      },
    ).verify();
  }, []);

This approach helped me:

  1. Create a component captcha.
  2. Take your container captcha to your new component.
  3. Take the initialization of the firebase and recaptchaVerifier config to your captcha component.
  4. Insert it wherever you need it.

Had the same issue in svelte but loading on ReCAPTCHA onMount saved the day

Related